diff --git a/src/Mod/Sketcher/App/Constraint.cpp b/src/Mod/Sketcher/App/Constraint.cpp
index bf13188cb7..b808adf6cb 100644
--- a/src/Mod/Sketcher/App/Constraint.cpp
+++ b/src/Mod/Sketcher/App/Constraint.cpp
@@ -27,7 +27,7 @@
#include
#include
-
+#include
#include "Constraint.h"
#include "ConstraintPy.h"
@@ -42,10 +42,10 @@ TYPESYSTEM_SOURCE(Sketcher::Constraint, Base::Persistence)
const int Constraint::GeoUndef = -2000;
Constraint::Constraint()
-: Type(None),
+: Value(0.0),
+ Type(None),
AlignmentType(Undef),
Name(""),
- Value(0.0),
First(GeoUndef),
FirstPos(none),
Second(GeoUndef),
@@ -56,13 +56,24 @@ Constraint::Constraint()
LabelPosition(0.f),
isDriving(true)
{
+ // Initialize a random number generator, to avoid Valgrind false positives.
+ static boost::mt19937 ran;
+ static bool seeded = false;
+
+ if (!seeded) {
+ ran.seed(QDateTime::currentMSecsSinceEpoch() & 0xffffffff);
+ seeded = true;
+ }
+ static boost::uuids::basic_random_generator gen(&ran);
+
+ tag = gen();
}
Constraint::Constraint(const Constraint& from)
-: Type(from.Type),
+: Value(from.Value),
+ Type(from.Type),
AlignmentType(from.AlignmentType),
Name(from.Name),
- Value(from.Value),
First(from.First),
FirstPos(from.FirstPos),
Second(from.Second),
@@ -71,7 +82,8 @@ Constraint::Constraint(const Constraint& from)
ThirdPos(from.ThirdPos),
LabelDistance(from.LabelDistance),
LabelPosition(from.LabelPosition),
- isDriving(from.isDriving)
+ isDriving(from.isDriving),
+ tag(from.tag)
{
}
@@ -89,6 +101,31 @@ PyObject *Constraint::getPyObject(void)
return new ConstraintPy(new Constraint(*this));
}
+void Constraint::setValue(double newValue)
+{
+ Value = newValue;
+}
+
+double Constraint::getValue() const
+{
+ switch (Type) {
+ case Distance:
+ case Radius:
+ return std::abs(Value);
+ case DistanceX:
+ case DistanceY:
+ if (FirstPos == Sketcher::none || Second != Sketcher::Constraint::GeoUndef)
+ return std::abs(Value);
+ else
+ return Value;
+ case Angle:
+ case SnellsLaw:
+ return Value;
+ default:
+ return Value;
+ }
+}
+
unsigned int Constraint::getMemSize (void) const
{
return 0;
diff --git a/src/Mod/Sketcher/App/Constraint.h b/src/Mod/Sketcher/App/Constraint.h
index 82737de95d..53dc5fc6e4 100644
--- a/src/Mod/Sketcher/App/Constraint.h
+++ b/src/Mod/Sketcher/App/Constraint.h
@@ -26,6 +26,8 @@
#include
+#include
+#include
namespace Sketcher
{
@@ -80,13 +82,18 @@ public:
virtual PyObject *getPyObject(void);
- friend class Sketch;
+ void setValue(double newValue);
+ double getValue() const;
+ friend class Sketch;
+ friend class PropertyConstraintList;
+
+private:
+ double Value;
public:
ConstraintType Type;
InternalAlignmentType AlignmentType;
std::string Name;
- double Value;
int First;
PointPos FirstPos;
int Second;
@@ -96,6 +103,8 @@ public:
float LabelDistance;
float LabelPosition;
bool isDriving;
+protected:
+ boost::uuids::uuid tag;
};
} //namespace Sketcher
diff --git a/src/Mod/Sketcher/App/ConstraintPyImp.cpp b/src/Mod/Sketcher/App/ConstraintPyImp.cpp
index 669b6d447d..126453c0a0 100644
--- a/src/Mod/Sketcher/App/ConstraintPyImp.cpp
+++ b/src/Mod/Sketcher/App/ConstraintPyImp.cpp
@@ -150,7 +150,7 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
}
if (valid) {
this->getConstraintPtr()->First = FirstIndex;
- this->getConstraintPtr()->Value = Value;
+ this->getConstraintPtr()->setValue(Value);
return 0;
}
}
@@ -218,7 +218,7 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
this->getConstraintPtr()->Type = Angle;
this->getConstraintPtr()->First = FirstIndex;
this->getConstraintPtr()->Second = SecondIndex;
- this->getConstraintPtr()->Value = Value;
+ this->getConstraintPtr()->setValue(Value);
return 0;
}
else if (strcmp("DistanceX",ConstraintType) == 0) {
@@ -227,7 +227,7 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
this->getConstraintPtr()->Type = DistanceX;
this->getConstraintPtr()->First = FirstIndex;
this->getConstraintPtr()->FirstPos = (Sketcher::PointPos) FirstPos;
- this->getConstraintPtr()->Value = Value;
+ this->getConstraintPtr()->setValue(Value);
return 0;
}
else if (strcmp("DistanceY",ConstraintType) == 0) {
@@ -236,7 +236,7 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
this->getConstraintPtr()->Type = DistanceY;
this->getConstraintPtr()->First = FirstIndex;
this->getConstraintPtr()->FirstPos = (Sketcher::PointPos) FirstPos;
- this->getConstraintPtr()->Value = Value;
+ this->getConstraintPtr()->setValue(Value);
return 0;
}
}
@@ -306,7 +306,7 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
this->getConstraintPtr()->First = intArg1;
this->getConstraintPtr()->FirstPos = (Sketcher::PointPos) intArg2;
this->getConstraintPtr()->Second = intArg3;
- this->getConstraintPtr()->Value = Value;
+ this->getConstraintPtr()->setValue(Value);
return 0;
}
}
@@ -366,7 +366,7 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
this->getConstraintPtr()->SecondPos = Sketcher::none;
this->getConstraintPtr()->Third = intArg3;
this->getConstraintPtr()->ThirdPos = (Sketcher::PointPos) intArg4;
- this->getConstraintPtr()->Value = Value;
+ this->getConstraintPtr()->setValue(Value);
return 0;
}
if (valid) {
@@ -374,7 +374,7 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
this->getConstraintPtr()->FirstPos = (Sketcher::PointPos) intArg2;
this->getConstraintPtr()->Second = intArg3;
this->getConstraintPtr()->SecondPos = (Sketcher::PointPos) intArg4;
- this->getConstraintPtr()->Value = Value;
+ this->getConstraintPtr()->setValue(Value);
return 0;
}
}
@@ -406,7 +406,7 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/)
this->getConstraintPtr()->SecondPos = (Sketcher::PointPos) SecondPos;
this->getConstraintPtr()->Third = ThirdIndex;
this->getConstraintPtr()->ThirdPos = none;
- this->getConstraintPtr()->Value = Value;
+ this->getConstraintPtr()->setValue(Value);
return 0;
}
}
diff --git a/src/Mod/Sketcher/App/PropertyConstraintList.cpp b/src/Mod/Sketcher/App/PropertyConstraintList.cpp
index 6e9bb35c2c..604b8c052b 100644
--- a/src/Mod/Sketcher/App/PropertyConstraintList.cpp
+++ b/src/Mod/Sketcher/App/PropertyConstraintList.cpp
@@ -32,6 +32,8 @@
#include
#include
#include
+#include
+#include
#include "PropertyConstraintList.h"
#include "ConstraintPy.h"
@@ -63,10 +65,41 @@ PropertyConstraintList::~PropertyConstraintList()
if (*it) delete *it;
}
+App::ObjectIdentifier PropertyConstraintList::makeArrayPath(int idx)
+{
+ return App::ObjectIdentifier(getContainer()) << App::ObjectIdentifier::Component::ArrayComponent(ObjectIdentifier::String(getName()), idx);
+}
+
+App::ObjectIdentifier PropertyConstraintList::makeSimplePath(const Constraint * c)
+{
+ return App::ObjectIdentifier(getContainer()) << App::ObjectIdentifier::Component::SimpleComponent(getName())
+ << App::ObjectIdentifier::Component::SimpleComponent(App::ObjectIdentifier::String(c->Name, !ExpressionParser::isTokenAnIndentifier(c->Name)));
+}
+
+App::ObjectIdentifier PropertyConstraintList::makePath(int idx, const Constraint * c)
+{
+ return c->Name.size() == 0 ? makeArrayPath(idx) : makeSimplePath(c);
+}
+
void PropertyConstraintList::setSize(int newSize)
{
+ std::set removed;
+
+ /* Collect information about erased elements */
+ for (unsigned int i = newSize; i < _lValueList.size(); i++) {
+ valueMap.erase(_lValueList[i]->tag);
+ removed.insert(makePath(i, _lValueList[i]));
+ }
+
+ /* Signal removed elements */
+ if (removed.size() > 0)
+ signalConstraintsRemoved(removed);
+
+ /* Actually delete them */
for (unsigned int i = newSize; i < _lValueList.size(); i++)
delete _lValueList[i];
+
+ /* Resize array to new size */
_lValueList.resize(newSize);
}
@@ -81,7 +114,18 @@ void PropertyConstraintList::set1Value(const int idx, const Constraint* lValue)
aboutToSetValue();
Constraint* oldVal = _lValueList[idx];
Constraint* newVal = lValue->clone();
+
+ if (oldVal->Name != newVal->Name) {
+ std::map renamed;
+
+ renamed[makePath(idx, _lValueList[idx])] = makePath(idx, lValue);
+ if (renamed.size() > 0)
+ signalConstraintsRenamed(renamed);
+ }
+
_lValueList[idx] = newVal;
+ valueMap.erase(oldVal->tag);
+ valueMap[newVal->tag] = idx;
delete oldVal;
hasSetValue();
}
@@ -92,10 +136,38 @@ void PropertyConstraintList::setValue(const Constraint* lValue)
if (lValue) {
aboutToSetValue();
Constraint* newVal = lValue->clone();
+ std::set removed;
+ std::map renamed;
+ int start = 0;
+
+ /* Determine if it is a rename or not * */
+ if (_lValueList.size() > 0 && lValue->tag == _lValueList[0]->tag) {
+ renamed[makePath(0, _lValueList[0])] = makePath(0, lValue);
+ start = 1;
+ }
+
+ /* Signal rename changes */
+ if (renamed.size() > 0)
+ signalConstraintsRenamed(renamed);
+
+ /* Collect infor about removals */
+ for (unsigned int i = start; i < _lValueList.size(); i++) {
+ valueMap.erase(_lValueList[i]->tag);
+ removed.insert(makePath(i, _lValueList[i]));
+ }
+
+ /* Signal removes */
+ if (removed.size() > 0)
+ signalConstraintsRemoved(removed);
+
+ // Cleanup
for (unsigned int i = 0; i < _lValueList.size(); i++)
delete _lValueList[i];
+
+ /* Set new data */
_lValueList.resize(1);
_lValueList[0] = newVal;
+ valueMap[_lValueList[0]->tag] = 0;
hasSetValue();
}
}
@@ -110,10 +182,46 @@ void PropertyConstraintList::setValues(const std::vector& lValue)
void PropertyConstraintList::applyValues(const std::vector& lValue)
{
std::vector oldVals(_lValueList);
+ std::map renamed;
+ std::set removed;
+
+ /* Check for renames */
+ for (unsigned int i = 0; i < lValue.size(); i++) {
+ boost::unordered_map::const_iterator j = valueMap.find(lValue[i]->tag);
+
+ if (j != valueMap.end() && (i != j->second || _lValueList[j->second]->Name != lValue[i]->Name) )
+ renamed[makePath(j->second, _lValueList[j->second] )] = makePath(i, lValue[i]);
+ }
+
+ /* Update value map with new tags from new array */
+ valueMap.clear();
+ for (std::size_t i = 0; i < lValue.size(); i++)
+ valueMap[lValue[i]->tag] = i;
+
+ /* Signal renames */
+ if (renamed.size() > 0)
+ signalConstraintsRenamed(renamed);
+
+ /* Collect info about removed elements */
+ for (std::size_t i = 0; i < oldVals.size(); i++) {
+ boost::unordered_map::const_iterator j = valueMap.find(oldVals[i]->tag);
+
+ if (j == valueMap.end())
+ removed.insert(makePath(i, oldVals[i]));
+ }
+
+ /* Signal removes */
+ if (removed.size() > 0)
+ signalConstraintsRemoved(removed);
+
+ /* Resize array to new size */
_lValueList.resize(lValue.size());
- // copy all objects
+
+ /* copy all objects */
for (unsigned int i = 0; i < lValue.size(); i++)
_lValueList[i] = lValue[i]->clone();
+
+ /* Clean-up; remove old values */
for (unsigned int i = 0; i < oldVals.size(); i++)
delete oldVals[i];
}
@@ -268,5 +376,125 @@ bool PropertyConstraintList::scanGeometry(const std::vector &G
return true;
}
+string PropertyConstraintList::getConstraintName(const std::string & name, int i)
+{
+ if (name != "")
+ return name;
+ else
+ return getConstraintName(i);
+}
+
+string PropertyConstraintList::getConstraintName(int i)
+{
+ std::stringstream str;
+
+ str << "Constraint" << (i + 1);
+ return str.str();
+}
+
+bool PropertyConstraintList::validConstraintName(const std::string & name)
+{
+ return name.size() > 0;
+}
+
+ObjectIdentifier PropertyConstraintList::createPath(int ConstrNbr) const
+{
+ return App::ObjectIdentifier(getContainer())
+ << App::ObjectIdentifier::Component::ArrayComponent(App::ObjectIdentifier::String(getName()), ConstrNbr);
+}
+
+int PropertyConstraintList::getIndexFromConstraintName(const string &name)
+{
+ return std::atoi(name.substr(10,4000).c_str()) - 1;
+}
+
+void PropertyConstraintList::setValue(const ObjectIdentifier &path, const boost::any &value)
+{
+ const ObjectIdentifier::Component & c0 = path.getPropertyComponent(0);
+ double dvalue;
+
+ if (value.type() == typeid(double))
+ dvalue = boost::any_cast(value);
+ else if (value.type() == typeid(Quantity))
+ dvalue = (boost::any_cast(value)).getValue();
+ else
+ throw std::bad_cast();
+
+ if (c0.isArray() && path.numSubComponents() == 1) {
+ if (c0.getIndex() < 0 || c0.getIndex() >= _lValueList.size())
+ throw Base::Exception("Array out of bounds");
+ aboutToSetValue();
+ _lValueList[c0.getIndex()]->setValue(dvalue);
+ hasSetValue();
+ return;
+ }
+ else if (c0.isSimple() && path.numSubComponents() == 2) {
+ ObjectIdentifier::Component c1 = path.getPropertyComponent(1);
+
+ for (std::vector::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
+ if ((*it)->Name == c1.getName()) {
+ aboutToSetValue();
+ _lValueList[it - _lValueList.begin()]->setValue(dvalue);
+ hasSetValue();
+ return;
+ }
+ }
+ }
+ throw Base::Exception("Invalid constraint");
+}
+
+const Constraint * PropertyConstraintList::getConstraint(const ObjectIdentifier &path) const
+{
+ const ObjectIdentifier::Component & c0 = path.getPropertyComponent(0);
+
+ if (c0.isArray() && path.numSubComponents() == 1) {
+ if (c0.getIndex() < 0 || c0.getIndex() >= _lValueList.size())
+ throw Base::Exception("Array out of bounds");
+
+ return _lValueList[c0.getIndex()];
+ }
+ else if (c0.isSimple() && path.numSubComponents() == 2) {
+ ObjectIdentifier::Component c1 = path.getPropertyComponent(1);
+
+ for (std::vector::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
+ if ((*it)->Name == c1.getName())
+ return *it;
+ }
+ }
+ throw Base::Exception("Invalid constraint");
+}
+
+const boost::any PropertyConstraintList::getValue(const ObjectIdentifier &path) const
+{
+ return boost::any(getConstraint(path)->getValue());
+}
+
+const ObjectIdentifier PropertyConstraintList::canonicalPath(const ObjectIdentifier &p) const
+{
+ const ObjectIdentifier::Component & c0 = p.getPropertyComponent(0);
+
+ if (c0.isArray() && p.numSubComponents() == 1) {
+ if (c0.getIndex() >= 0 && c0.getIndex() < _lValueList.size() && _lValueList[c0.getIndex()]->Name.size() > 0)
+ return ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
+ << ObjectIdentifier::Component::SimpleComponent(_lValueList[c0.getIndex()]->Name);
+ return p;
+ }
+ else if (c0.isSimple() && p.numSubComponents() == 2) {
+ ObjectIdentifier::Component c1 = p.getPropertyComponent(1);
+
+ if (c1.isSimple())
+ return p;
+ }
+ throw Base::Exception("Invalid constraint");
+}
+
+void PropertyConstraintList::getPaths(std::vector &paths) const
+{
+ for (std::vector::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
+ if ((*it)->Name.size() > 0)
+ paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
+ << ObjectIdentifier::Component::SimpleComponent((*it)->Name));
+ }
+}
std::vector PropertyConstraintList::_emptyValueList(0);
diff --git a/src/Mod/Sketcher/App/PropertyConstraintList.h b/src/Mod/Sketcher/App/PropertyConstraintList.h
index 1726d7500e..8d6e59cea6 100644
--- a/src/Mod/Sketcher/App/PropertyConstraintList.h
+++ b/src/Mod/Sketcher/App/PropertyConstraintList.h
@@ -32,6 +32,8 @@
#include
#include
#include "Constraint.h"
+#include
+#include
namespace Base {
class Writer;
@@ -99,8 +101,35 @@ public:
bool scanGeometry(const std::vector &GeoList) const;
bool isGeometryInvalid(){return invalidGeometry;}
+
+ const Constraint *getConstraint(const App::ObjectIdentifier &path) const;
+ virtual void setValue(const App::ObjectIdentifier & path, const boost::any & value);
+ virtual const boost::any getValue(const App::ObjectIdentifier & path) const;
+ virtual const App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier & p) const;
+ virtual void getPaths(std::vector & paths) const;
+
+ typedef std::pair ConstraintInfo ;
+
+ boost::signal &)> signalConstraintsRenamed;
+ boost::signal &)> signalConstraintsRemoved;
+
+ static std::string getConstraintName(const std::string &name, int i);
+
+ static std::string getConstraintName(int i);
+
+ static int getIndexFromConstraintName(const std::string & name);
+
+ static bool validConstraintName(const std::string &name);
+
+ App::ObjectIdentifier createPath(int ConstrNbr) const;
+
private:
+ App::ObjectIdentifier makeArrayPath(int idx);
+ App::ObjectIdentifier makeSimplePath(const Constraint *c);
+ App::ObjectIdentifier makePath(int idx, const Constraint *c);
+
std::vector _lValueList;
+ boost::unordered_map valueMap;
std::vector validGeometryKeys;
bool invalidGeometry;
diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp
index 249616f1c8..49459d4210 100644
--- a/src/Mod/Sketcher/App/SketchObject.cpp
+++ b/src/Mod/Sketcher/App/SketchObject.cpp
@@ -46,6 +46,9 @@
# include
#endif // #ifndef _PreComp_
+#include
+
+#include
#include
#include
#include
@@ -93,6 +96,11 @@ SketchObject::SketchObject()
solverNeedsUpdate=false;
noRecomputes=false;
+
+ ExpressionEngine.setValidator(boost::bind(&Sketcher::SketchObject::validateExpression, this, _1, _2));
+
+ constraintsRemovedConn = Constraints.signalConstraintsRemoved.connect(boost::bind(&Sketcher::SketchObject::constraintsRemoved, this, _1));
+ constraintsRenamedConn = Constraints.signalConstraintsRenamed.connect(boost::bind(&Sketcher::SketchObject::constraintsRenamed, this, _1));
}
SketchObject::~SketchObject()
@@ -247,7 +255,7 @@ int SketchObject::setDatum(int ConstrId, double Datum)
std::vector newVals(vals);
// clone the changed Constraint
Constraint *constNew = vals[ConstrId]->clone();
- constNew->Value = Datum;
+ constNew->setValue(Datum);
newVals[ConstrId] = constNew;
this->Constraints.setValues(newVals);
delete constNew;
@@ -286,6 +294,8 @@ int SketchObject::setDriving(int ConstrId, bool isdriving)
constNew->isDriving = isdriving;
newVals[ConstrId] = constNew;
this->Constraints.setValues(newVals);
+ if (isdriving)
+ setExpression(Constraints.createPath(ConstrId), boost::shared_ptr());
delete constNew;
if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver
@@ -342,6 +352,8 @@ int SketchObject::toggleDriving(int ConstrId)
constNew->isDriving = !constNew->isDriving;
newVals[ConstrId] = constNew;
this->Constraints.setValues(newVals);
+ if (constNew->isDriving)
+ setExpression(Constraints.createPath(ConstrId), boost::shared_ptr());
delete constNew;
if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver
@@ -2268,7 +2280,7 @@ int SketchObject::addCopy(const std::vector &geoIdList, const Base::Vector3
constNew->Type = Sketcher::Distance;
constNew->First = rowrefgeoid;
constNew->FirstPos = Sketcher::none;
- constNew->Value = perpendicularDisplacement.Length();
+ constNew->setValue(perpendicularDisplacement.Length());
newconstrVals.push_back(constNew);
}
@@ -2329,14 +2341,14 @@ int SketchObject::addCopy(const std::vector &geoIdList, const Base::Vector3
constNew->Type = Sketcher::Distance;
constNew->First = colrefgeoid;
constNew->FirstPos = Sketcher::none;
- constNew->Value = displacement.Length();
+ constNew->setValue(displacement.Length());
newconstrVals.push_back(constNew);
constNew = new Constraint();
constNew->Type = Sketcher::Angle;
constNew->First = colrefgeoid;
constNew->FirstPos = Sketcher::none;
- constNew->Value = atan2(displacement.y,displacement.x);
+ constNew->setValue(atan2(displacement.y,displacement.x));
newconstrVals.push_back(constNew);
}
else { // any other element
@@ -3499,6 +3511,38 @@ void SketchObject::validateConstraints()
}
}
+std::string SketchObject::validateExpression(const App::ObjectIdentifier &path, boost::shared_ptr expr)
+{
+ const App::Property * prop = path.getProperty();
+
+ assert(expr != 0);
+
+ if (!prop)
+ return "Property not found";
+
+ if (prop == &Constraints) {
+ const Constraint * constraint = Constraints.getConstraint(path);
+
+ if (!constraint->isDriving)
+ return "Reference constraints cannot be set!";
+ }
+
+ std::set deps;
+ expr->getDeps(deps);
+
+ for (std::set::const_iterator i = deps.begin(); i != deps.end(); ++i) {
+ const App::Property * prop = (*i).getProperty();
+
+ if (prop == &Constraints) {
+ const Constraint * constraint = Constraints.getConstraint(*i);
+
+ if (!constraint->isDriving)
+ return "Reference constraint from this sketch cannot be used in this expression.";
+ }
+ }
+ return "";
+}
+
//This function is necessary for precalculation of an angle when adding
// an angle constraint. It is also used here, in SketchObject, to
// lock down the type of tangency/perpendicularity.
@@ -3546,6 +3590,23 @@ double SketchObject::calculateAngleViaPoint(int GeoId1, int GeoId2, double px, d
*/
}
+void SketchObject::constraintsRenamed(const std::map &renamed)
+{
+ ExpressionEngine.renameExpressions(renamed);
+
+ getDocument()->renameObjectIdentifiers(renamed);
+}
+
+void SketchObject::constraintsRemoved(const std::set &removed)
+{
+ std::set::const_iterator i = removed.begin();
+
+ while (i != removed.end()) {
+ ExpressionEngine.setValue(*i, boost::shared_ptr(), 0);
+ ++i;
+ }
+}
+
//Tests if the provided point lies exactly in a curve (satisfies
// point-on-object constraint). It is used to decide whether it is nesessary to
// constrain a point onto curves when 3-element selection tangent-via-point-like
@@ -3841,10 +3902,10 @@ bool SketchObject::AutoLockTangencyAndPerpty(Constraint *cstr, bool bForce, bool
{
try{
//assert ( cstr->Type == Tangent || cstr->Type == Perpendicular);
- if(cstr->Value != 0.0 && ! bForce) /*tangency type already set. If not bForce - don't touch.*/
+ if(cstr->getValue() != 0.0 && ! bForce) /*tangency type already set. If not bForce - don't touch.*/
return true;
if(!bLock){
- cstr->Value=0.0;//reset
+ cstr->setValue(0.0);//reset
} else {
//decide on tangency type. Write the angle value into the datum field of the constraint.
int geoId1, geoId2, geoIdPt;
@@ -3880,7 +3941,7 @@ bool SketchObject::AutoLockTangencyAndPerpty(Constraint *cstr, bool bForce, bool
if(fabs(angleErr) > M_PI/2 )
angleDesire += M_PI;
- cstr->Value = angleDesire + angleOffset; //external tangency. The angle stored is offset by Pi/2 so that a value of 0.0 is invalid and threated as "undecided".
+ cstr->setValue(angleDesire + angleOffset); //external tangency. The angle stored is offset by Pi/2 so that a value of 0.0 is invalid and threated as "undecided".
}
}
} catch (Base::Exception& e){
@@ -3891,6 +3952,15 @@ bool SketchObject::AutoLockTangencyAndPerpty(Constraint *cstr, bool bForce, bool
return true;
}
+void SketchObject::setExpression(const App::ObjectIdentifier &path, boost::shared_ptr expr, const char * comment)
+{
+ DocumentObject::setExpression(path, expr, comment);
+
+ if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver, constraints and UI
+ solve();
+}
+
+
// Python Sketcher feature ---------------------------------------------------------
namespace App {
diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h
index 43061bce0b..c060a9d935 100644
--- a/src/Mod/Sketcher/App/SketchObject.h
+++ b/src/Mod/Sketcher/App/SketchObject.h
@@ -23,6 +23,7 @@
#ifndef SKETCHER_SKETCHOBJECT_H
#define SKETCHER_SKETCHOBJECT_H
+#include
#include
#include
#include
@@ -248,6 +249,13 @@ protected:
/// get called by the container when a property has changed
virtual void onChanged(const App::Property* /*prop*/);
virtual void onDocumentRestored();
+
+ virtual void setExpression(const App::ObjectIdentifier &path, boost::shared_ptr expr, const char * comment = 0);
+
+ std::string validateExpression(const App::ObjectIdentifier &path, boost::shared_ptr expr);
+
+ void constraintsRenamed(const std::map &renamed);
+ void constraintsRemoved(const std::set &removed);
private:
std::vector ExternalGeo;
@@ -271,6 +279,9 @@ private:
std::vector lastConflicting;
std::vector lastRedundant;
+ boost::signals::scoped_connection constraintsRenamedConn;
+ boost::signals::scoped_connection constraintsRemovedConn;
+
bool AutoLockTangencyAndPerpty(Constraint* cstr, bool bForce = false, bool bLock = true);
};
diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp
index 03d628c700..bdaabbc66a 100644
--- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp
+++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp
@@ -329,6 +329,24 @@ PyObject* SketchObjectPy::renameConstraint(PyObject *args)
return 0;
}
+ if (strcmp(Name, "") != 0) {
+
+ if (!Sketcher::PropertyConstraintList::validConstraintName(Name)) {
+ std::stringstream str;
+ str << "Invalid constraint name with the given index: " << Index;
+ PyErr_SetString(PyExc_IndexError, str.str().c_str());
+ return 0;
+ }
+
+ const std::vector< Sketcher::Constraint * > &vals = getSketchObjectPtr()->Constraints.getValues();
+ for (std::size_t i = 0; i < vals.size(); ++i) {
+ if (static_cast(i) != Index && Name == vals[i]->Name) {
+ PyErr_SetString(PyExc_ValueError, "Duplicate constraint not allowed");
+ return 0;
+ }
+ }
+ }
+
Constraint* copy = this->getSketchObjectPtr()->Constraints[Index]->clone();
copy->Name = Name;
this->getSketchObjectPtr()->Constraints.set1Value(Index, copy);
@@ -537,15 +555,9 @@ PyObject* SketchObjectPy::getDatum(PyObject *args)
PyErr_Clear();
char* name;
if (PyArg_ParseTuple(args,"s", &name)) {
- int id = 1;
+ int id = 0;
for (std::vector::const_iterator it = vals.begin(); it != vals.end(); ++it, ++id) {
- std::string constrName = (*it)->Name;
- if (constrName.empty()) {
- std::stringstream str;
- str << "Constraint" << id;
- constrName = str.str();
- }
- if (constrName == name) {
+ if (Sketcher::PropertyConstraintList::getConstraintName((*it)->Name, id) == name) {
constr = *it;
break;
}
@@ -579,7 +591,7 @@ PyObject* SketchObjectPy::getDatum(PyObject *args)
}
Base::Quantity datum;
- datum.setValue(constr->Value);
+ datum.setValue(constr->getValue());
if (type == Angle) {
datum.setValue(Base::toDegrees(datum.getValue()));
datum.setUnit(Base::Unit::Angle);
diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp
index 84901095b7..10e703c5d0 100644
--- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp
+++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp
@@ -95,7 +95,7 @@ void openEditDatumDialog(Sketcher::SketchObject* sketch, int ConstrNbr)
Ui::InsertDatum ui_ins_datum;
ui_ins_datum.setupUi(&dlg);
- double datum = Constr->Value;
+ double datum = Constr->getValue();
Base::Quantity init_val;
if (Constr->Type == Sketcher::Angle) {
@@ -135,6 +135,8 @@ void openEditDatumDialog(Sketcher::SketchObject* sketch, int ConstrNbr)
ui_ins_datum.labelEdit->setValue(init_val);
ui_ins_datum.labelEdit->selectNumber();
+ ui_ins_datum.labelEdit->bind(sketch->Constraints.createPath(ConstrNbr));
+ ui_ins_datum.name->setText(Base::Tools::fromStdString(Constr->Name));
if (dlg.exec()) {
Base::Quantity newQuant = ui_ins_datum.labelEdit->value();
@@ -154,14 +156,30 @@ void openEditDatumDialog(Sketcher::SketchObject* sketch, int ConstrNbr)
}
try {
- Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.setDatum(%i,App.Units.Quantity('%f %s'))",
- sketch->getNameInDocument(),
- ConstrNbr, newDatum, (const char*)newQuant.getUnit().getString().toUtf8());
+ if (ui_ins_datum.labelEdit->hasExpression())
+ ui_ins_datum.labelEdit->apply();
+ else
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.setDatum(%i,App.Units.Quantity('%f %s'))",
+ sketch->getNameInDocument(),
+ ConstrNbr, newDatum, (const char*)newQuant.getUnit().getString().toUtf8());
+
+ QString constraintName = ui_ins_datum.name->text().trimmed();
+ if (Base::Tools::toStdString(constraintName) != sketch->Constraints[ConstrNbr]->Name) {
+ std::string escapedstr = Base::Tools::escapedUnicodeFromUtf8(constraintName.toUtf8().constData());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.renameConstraint(%d, '%s')",
+ sketch->getNameInDocument(),
+ ConstrNbr, escapedstr.c_str());
+ }
Gui::Command::commitCommand();
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
bool autoRecompute = hGrp->GetBool("AutoRecompute",false);
+ if (sketch->noRecomputes && sketch->ExpressionEngine.depsAreTouched()) {
+ sketch->ExpressionEngine.execute();
+ sketch->solve();
+ }
+
if(autoRecompute)
Gui::Command::updateActive();
}
@@ -2406,16 +2424,28 @@ void CmdSketcherConstrainRadius::activated(int iMsg)
ui_Datum.labelEdit->setValue(init_val);
ui_Datum.labelEdit->selectNumber();
+ if (constrainEqual || geoIdRadiusMap.size() == 1)
+ ui_Datum.labelEdit->bind(Obj->Constraints.createPath(indexConstr));
+ else
+ ui_Datum.name->setDisabled(true);
if (dlg.exec() == QDialog::Accepted) {
Base::Quantity newQuant = ui_Datum.labelEdit->value();
double newRadius = newQuant.getValue();
try {
- if (constrainEqual) {
+ if (constrainEqual || geoIdRadiusMap.size() == 1) {
doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.setDatum(%i,App.Units.Quantity('%f %s'))",
Obj->getNameInDocument(),
indexConstr, newRadius, (const char*)newQuant.getUnit().getString().toUtf8());
+
+ QString constraintName = ui_Datum.name->text().trimmed();
+ if (Base::Tools::toStdString(constraintName) != Obj->Constraints[indexConstr]->Name) {
+ std::string escapedstr = Base::Tools::escapedUnicodeFromUtf8(constraintName.toUtf8().constData());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.renameConstraint(%d, '%s')",
+ Obj->getNameInDocument(),
+ indexConstr, escapedstr.c_str());
+ }
}
else {
for (std::size_t i=0; iGetBool("AutoRecompute",false);
+ if (Obj->noRecomputes && Obj->ExpressionEngine.depsAreTouched()) {
+ Obj->ExpressionEngine.execute();
+ Obj->solve();
+ }
+
if(autoRecompute)
Gui::Command::updateActive();
@@ -3142,6 +3178,7 @@ void CmdSketcherConstrainSnellsLaw::activated(int iMsg)
ui_Datum.labelEdit->setParamGrpPath(QByteArray("User parameter:BaseApp/History/SketcherRefrIndexRatio"));
ui_Datum.labelEdit->setToLastUsedValue();
ui_Datum.labelEdit->selectNumber();
+ // Unable to bind, because the constraint does not yet exist
if (dlg.exec() != QDialog::Accepted) return;
ui_Datum.labelEdit->pushToHistory();
@@ -3711,7 +3748,7 @@ void CmdSketcherToggleDrivingConstraint::activated(int iMsg)
for (std::vector::const_iterator it=SubNames.begin();it!=SubNames.end();++it){
// only handle constraints
if (it->size() > 10 && it->substr(0,10) == "Constraint") {
- int ConstrId = std::atoi(it->substr(10,4000).c_str()) - 1;
+ int ConstrId = Sketcher::PropertyConstraintList::getIndexFromConstraintName(*it);
try {
// issue the actual commands to toggle
doCommand(Doc,"App.ActiveDocument.%s.toggleDriving(%d) ",selection[0].getFeatName(),ConstrId);
diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp
index 08e42b6805..ef223931a0 100644
--- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp
+++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp
@@ -319,7 +319,6 @@ void CmdSketcherSelectConstraints::activated(int iMsg)
std::string doc_name = Obj->getDocument()->getName();
std::string obj_name = Obj->getNameInDocument();
- std::stringstream ss;
getSelection().clearSelection();
@@ -330,13 +329,11 @@ void CmdSketcherSelectConstraints::activated(int iMsg)
int GeoId = std::atoi(it->substr(4,4000).c_str()) - 1;
// push all the constraints
- int i=1;
+ int i = 0;
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();
it != vals.end(); ++it,++i) {
if ( (*it)->First == GeoId || (*it)->Second == GeoId || (*it)->Third == GeoId){
- ss.str(std::string());
- ss << "Constraint" << i;
- Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
+ Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
}
}
}
@@ -507,7 +504,6 @@ void CmdSketcherSelectRedundantConstraints::activated(int iMsg)
std::string doc_name = Obj->getDocument()->getName();
std::string obj_name = Obj->getNameInDocument();
- std::stringstream ss;
// get the needed lists and objects
const std::vector< int > &solverredundant = dynamic_cast(doc->getInEdit())->getSketchObject()->getLastRedundant();
@@ -516,13 +512,11 @@ void CmdSketcherSelectRedundantConstraints::activated(int iMsg)
getSelection().clearSelection();
// push the constraints
- int i=1;
+ int i = 0;
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) {
for(std::vector< int >::const_iterator itc= solverredundant.begin();itc != solverredundant.end(); ++itc) {
- if ( (*itc) == i){
- ss.str(std::string());
- ss << "Constraint" << i;
- Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
+ if ( (*itc) - 1 == i){
+ Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
break;
}
}
@@ -571,13 +565,11 @@ void CmdSketcherSelectConflictingConstraints::activated(int iMsg)
getSelection().clearSelection();
// push the constraints
- int i=1;
+ int i = 0;
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) {
for(std::vector< int >::const_iterator itc= solverconflicting.begin();itc != solverconflicting.end(); ++itc) {
- if ( (*itc) == i){
- ss.str(std::string());
- ss << "Constraint" << i;
- Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
+ if ( (*itc) - 1 == i){
+ Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
break;
}
}
@@ -632,7 +624,7 @@ void CmdSketcherSelectElementsAssociatedWithConstraints::activated(int iMsg)
for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) {
// only handle constraints
if (it->size() > 10 && it->substr(0,10) == "Constraint") {
- int ConstrId = std::atoi(it->substr(10,4000).c_str()) - 1;
+ int ConstrId = Sketcher::PropertyConstraintList::getIndexFromConstraintName(*it);
if(ConstrId < static_cast(vals.size())){
if(vals[ConstrId]->First!=Constraint::GeoUndef){
diff --git a/src/Mod/Sketcher/Gui/EditDatumDialog.cpp b/src/Mod/Sketcher/Gui/EditDatumDialog.cpp
index ae53f487f2..adc62d3187 100644
--- a/src/Mod/Sketcher/Gui/EditDatumDialog.cpp
+++ b/src/Mod/Sketcher/Gui/EditDatumDialog.cpp
@@ -91,7 +91,7 @@ void EditDatumDialog::exec(bool atCursor)
Ui::InsertDatum ui_ins_datum;
ui_ins_datum.setupUi(&dlg);
- double datum = Constr->Value;
+ double datum = Constr->getValue();
Base::Quantity init_val;
if (Constr->Type == Sketcher::Angle) {
@@ -132,8 +132,13 @@ void EditDatumDialog::exec(bool atCursor)
else // show negative sign
init_val.setValue(datum);
+ // Enable label if we are modifying a driving constraint
+ ui_ins_datum.labelEdit->setEnabled(Constr->isDriving);
+
ui_ins_datum.labelEdit->setValue(init_val);
ui_ins_datum.labelEdit->selectNumber();
+ ui_ins_datum.labelEdit->bind(sketch->Constraints.createPath(ConstrNbr));
+ ui_ins_datum.name->setText(Base::Tools::fromStdString(Constr->Name));
if (atCursor)
dlg.setGeometry(QCursor::pos().x() - dlg.geometry().width() / 2, QCursor::pos().y(), dlg.geometry().width(), dlg.geometry().height());
@@ -157,14 +162,34 @@ void EditDatumDialog::exec(bool atCursor)
try {
Gui::Command::openCommand("Modify sketch constraints");
- Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.setDatum(%i,App.Units.Quantity('%f %s'))",
- sketch->getNameInDocument(),
- ConstrNbr, newDatum, (const char*)newQuant.getUnit().getString().toUtf8());
+
+ if (Constr->isDriving) {
+ if (ui_ins_datum.labelEdit->hasExpression())
+ ui_ins_datum.labelEdit->apply();
+ else
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.setDatum(%i,App.Units.Quantity('%f %s'))",
+ sketch->getNameInDocument(),
+ ConstrNbr, newDatum, (const char*)newQuant.getUnit().getString().toUtf8());
+ }
+
+ QString constraintName = ui_ins_datum.name->text().trimmed();
+ if (Base::Tools::toStdString(constraintName) != sketch->Constraints[ConstrNbr]->Name) {
+ std::string escapedstr = Base::Tools::escapedUnicodeFromUtf8(constraintName.toUtf8().constData());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.renameConstraint(%d, '%s')",
+ sketch->getNameInDocument(),
+ ConstrNbr, escapedstr.c_str());
+ }
+
Gui::Command::commitCommand();
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
bool autoRecompute = hGrp->GetBool("AutoRecompute",false);
+ if (sketch->noRecomputes && sketch->ExpressionEngine.depsAreTouched()) {
+ sketch->ExpressionEngine.execute();
+ sketch->solve();
+ }
+
if(autoRecompute)
Gui::Command::updateActive();
}
diff --git a/src/Mod/Sketcher/Gui/InsertDatum.ui b/src/Mod/Sketcher/Gui/InsertDatum.ui
index 93dea8e736..faa86b007b 100644
--- a/src/Mod/Sketcher/Gui/InsertDatum.ui
+++ b/src/Mod/Sketcher/Gui/InsertDatum.ui
@@ -9,8 +9,8 @@
0
0
- 178
- 72
+ 344
+ 122
@@ -18,16 +18,33 @@
-
-
-
-
+
+
-
datum:
- -
-
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+ Name (optional)
+
+
+
+ -
+
@@ -43,16 +60,15 @@
-
-
- Gui::PrefQuantitySpinBox
- QWidget
-
-
+
+ Gui::PrefQuantitySpinBox
+ QWidget
+
+
-
-
+
+
buttonBox
accepted()
diff --git a/src/Mod/Sketcher/Gui/PropertyConstraintListItem.cpp b/src/Mod/Sketcher/Gui/PropertyConstraintListItem.cpp
index 7ea6dad2db..1dcd339f22 100644
--- a/src/Mod/Sketcher/Gui/PropertyConstraintListItem.cpp
+++ b/src/Mod/Sketcher/Gui/PropertyConstraintListItem.cpp
@@ -150,13 +150,13 @@ QVariant PropertyConstraintListItem::value(const App::Property* prop) const
Base::Quantity quant;
if ((*it)->Type == Sketcher::Angle ) {
- double datum = Base::toDegrees((*it)->Value);
+ double datum = Base::toDegrees((*it)->getValue());
quant.setUnit(Base::Unit::Angle);
quant.setValue(datum);
}
else {
quant.setUnit(Base::Unit::Length);
- quant.setValue((*it)->Value);
+ quant.setValue((*it)->getValue());
}
quantities.append(quant);
@@ -228,7 +228,7 @@ bool PropertyConstraintListItem::event (QEvent* ev)
double datum = quant.getValue();
if ((*it)->Type == Sketcher::Angle)
datum = Base::toRadians(datum);
- const_cast((*it))->Value = datum;
+ const_cast((*it))->setValue(datum);
item->set1Value(id,(*it));
break;
}
diff --git a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp
index ed582d7e87..e8667e1abe 100644
--- a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp
+++ b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp
@@ -29,6 +29,10 @@
# include
# include
# include
+# include
+# include
+# include
+# include
#endif
#include "TaskSketcherConstrains.h"
@@ -46,9 +50,9 @@
#include
#include
#include
-#include
#include
#include
+#include
using namespace SketcherGui;
using namespace Gui::TaskView;
@@ -73,13 +77,10 @@ void ConstraintView::FUNC(){ \
class ConstraintItem : public QListWidgetItem
{
public:
- ConstraintItem(const QIcon & icon, const QString & text,int ConstNbr,Sketcher::ConstraintType t,bool isdriving=true, bool isenforceable=true)
- : QListWidgetItem(icon,text),ConstraintNbr(ConstNbr),Type(t),isDriving(isdriving),isEnforceable(isenforceable)
- {
- this->setFlags(this->flags() | Qt::ItemIsEditable);
- }
- ConstraintItem(const QString & text,int ConstNbr,Sketcher::ConstraintType t,bool isdriving=true, bool isenforceable=true)
- : QListWidgetItem(text),ConstraintNbr(ConstNbr),Type(t),isDriving(isdriving),isEnforceable(isenforceable)
+ ConstraintItem(const Sketcher::SketchObject * s, int ConstNbr)
+ : QListWidgetItem(QString()),
+ sketch(s),
+ ConstraintNbr(ConstNbr)
{
this->setFlags(this->flags() | Qt::ItemIsEditable);
}
@@ -88,36 +89,270 @@ public:
}
void setData(int role, const QVariant & value)
{
- if (role == Qt::UserRole) {
- quantity = value;
- return;
- }
+ if (role == Qt::EditRole)
+ this->value = value;
+
QListWidgetItem::setData(role, value);
}
+
QVariant data (int role) const
{
- if (role == Qt::UserRole) {
- return quantity;
+ if (ConstraintNbr < 0 || ConstraintNbr >= sketch->Constraints.getSize())
+ return QVariant();
+
+ const Sketcher::Constraint * constraint = sketch->Constraints[ConstraintNbr];
+
+ if (role == Qt::EditRole) {
+ if (value.isValid())
+ return value;
+ else
+ return Base::Tools::fromStdString(Sketcher::PropertyConstraintList::getConstraintName(constraint->Name, ConstraintNbr));
}
- else if (role == Qt::DisplayRole && quantity.isValid()) {
- return quantity;
+ else if (role == Qt::DisplayRole) {
+ QString name = Base::Tools::fromStdString(Sketcher::PropertyConstraintList::getConstraintName(constraint->Name, ConstraintNbr));
+
+ switch (constraint->Type) {
+ case Sketcher::Horizontal:
+ case Sketcher::Vertical:
+ case Sketcher::Coincident:
+ case Sketcher::PointOnObject:
+ case Sketcher::Parallel:
+ case Sketcher::Perpendicular:
+ case Sketcher::Tangent:
+ case Sketcher::Equal:
+ case Sketcher::Symmetric:
+ break;
+ case Sketcher::Distance:
+ name = QString::fromLatin1("%1 (%2)").arg(name).arg(Base::Quantity(constraint->getValue(),Base::Unit::Length).getUserString());
+ break;
+ case Sketcher::DistanceX:
+ name = QString::fromLatin1("%1 (%2)").arg(name).arg(Base::Quantity(std::abs(constraint->getValue()),Base::Unit::Length).getUserString());
+ break;
+ case Sketcher::DistanceY:
+ name = QString::fromLatin1("%1 (%2)").arg(name).arg(Base::Quantity(std::abs(constraint->getValue()),Base::Unit::Length).getUserString());
+ break;
+ case Sketcher::Radius:
+ name = QString::fromLatin1("%1 (%2)").arg(name).arg(Base::Quantity(constraint->getValue(),Base::Unit::Length).getUserString());
+ break;
+ case Sketcher::Angle:
+ name = QString::fromLatin1("%1 (%2)").arg(name).arg(Base::Quantity(Base::toDegrees(std::abs(constraint->getValue())),Base::Unit::Angle).getUserString());
+ break;
+ case Sketcher::SnellsLaw: {
+ double v = constraint->getValue();
+ double n1 = 1.0;
+ double n2 = 1.0;
+ if (fabs(v) >= 1) {
+ n2 = v;
+ } else {
+ n1 = 1/v;
+ }
+ name = QString::fromLatin1("%1 (%2/%3)").arg(name).arg(n2).arg(n1);
+ break;
+ }
+ case Sketcher::InternalAlignment:
+ break;
+ default:
+ break;
+ }
+ return name;
}
- return QListWidgetItem::data(role);
+ else if (role == Qt::DecorationRole) {
+ static QIcon hdist( Gui::BitmapFactory().pixmap("Constraint_HorizontalDistance") );
+ static QIcon vdist( Gui::BitmapFactory().pixmap("Constraint_VerticalDistance") );
+ static QIcon horiz( Gui::BitmapFactory().pixmap("Constraint_Horizontal") );
+ static QIcon vert ( Gui::BitmapFactory().pixmap("Constraint_Vertical") );
+ static QIcon lock ( Gui::BitmapFactory().pixmap("Sketcher_ConstrainLock") );
+ static QIcon coinc( Gui::BitmapFactory().pixmap("Constraint_PointOnPoint") );
+ static QIcon para ( Gui::BitmapFactory().pixmap("Constraint_Parallel") );
+ static QIcon perp ( Gui::BitmapFactory().pixmap("Constraint_Perpendicular") );
+ static QIcon tang ( Gui::BitmapFactory().pixmap("Constraint_Tangent") );
+ static QIcon dist ( Gui::BitmapFactory().pixmap("Constraint_Length") );
+ static QIcon radi ( Gui::BitmapFactory().pixmap("Constraint_Radius") );
+ static QIcon majradi ( Gui::BitmapFactory().pixmap("Constraint_Ellipse_Major_Radius") );
+ static QIcon minradi ( Gui::BitmapFactory().pixmap("Constraint_Ellipse_Minor_Radius") );
+ static QIcon angl ( Gui::BitmapFactory().pixmap("Constraint_InternalAngle") );
+ static QIcon ellipseXUAngl ( Gui::BitmapFactory().pixmap("Constraint_Ellipse_Axis_Angle") );
+ static QIcon equal( Gui::BitmapFactory().pixmap("Constraint_EqualLength") );
+ static QIcon pntoo( Gui::BitmapFactory().pixmap("Constraint_PointOnObject") );
+ static QIcon symm ( Gui::BitmapFactory().pixmap("Constraint_Symmetric") );
+ static QIcon snell ( Gui::BitmapFactory().pixmap("Constraint_SnellsLaw") );
+ static QIcon iaellipseminoraxis ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment_Ellipse_MinorAxis") );
+ static QIcon iaellipsemajoraxis ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment_Ellipse_MajorAxis") );
+ static QIcon iaellipsefocus1 ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment_Ellipse_Focus1") );
+ static QIcon iaellipsefocus2 ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment_Ellipse_Focus2") );
+ static QIcon iaellipseother ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment") );
+
+ static QIcon hdist_driven ( Gui::BitmapFactory().pixmap("Constraint_HorizontalDistance_Driven") );
+ static QIcon vdist_driven( Gui::BitmapFactory().pixmap("Constraint_VerticalDistance_Driven") );
+ static QIcon dist_driven ( Gui::BitmapFactory().pixmap("Constraint_Length_Driven") );
+ static QIcon radi_driven ( Gui::BitmapFactory().pixmap("Constraint_Radius_Driven") );
+ static QIcon angl_driven ( Gui::BitmapFactory().pixmap("Constraint_InternalAngle_Driven") );
+ static QIcon snell_driven ( Gui::BitmapFactory().pixmap("Constraint_SnellsLaw_Driven") );
+
+ switch(constraint->Type){
+ case Sketcher::Horizontal:
+ return horiz;
+ case Sketcher::Vertical:
+ return vert;
+ case Sketcher::Coincident:
+ return coinc;
+ case Sketcher::PointOnObject:
+ return pntoo;
+ case Sketcher::Parallel:
+ return para;
+ case Sketcher::Perpendicular:
+ return perp;
+ case Sketcher::Tangent:
+ return tang;
+ case Sketcher::Equal:
+ return equal;
+ case Sketcher::Symmetric:
+ return symm;
+ case Sketcher::Distance:
+ return constraint->isDriving ? dist : dist_driven;
+ case Sketcher::DistanceX:
+ return constraint->isDriving ? hdist : hdist_driven;
+ case Sketcher::DistanceY:
+ return constraint->isDriving ? vdist : vdist_driven;
+ case Sketcher::Radius:
+ return constraint->isDriving ? radi : radi_driven;
+ case Sketcher::Angle:
+ return constraint->isDriving ? angl : angl_driven;
+ case Sketcher::SnellsLaw:
+ return constraint->isDriving ? snell : snell_driven;
+ case Sketcher::InternalAlignment:
+ switch(constraint->AlignmentType){
+ case Sketcher::EllipseMajorDiameter:
+ return iaellipsemajoraxis;
+ case Sketcher::EllipseMinorDiameter:
+ return iaellipseminoraxis;
+ case Sketcher::EllipseFocus1:
+ return iaellipsefocus1;
+ case Sketcher::EllipseFocus2:
+ return iaellipsefocus2;
+ case Sketcher::Undef:
+ default:
+ return iaellipseother;
+ }
+ default:
+ return QVariant();
+ }
+ }
+ else if (role == Qt::ToolTipRole) {
+ App::ObjectIdentifier path = sketch->Constraints.createPath(ConstraintNbr);
+ App::PropertyExpressionEngine::ExpressionInfo expr_info = sketch->getExpression(path);
+
+ if (expr_info.expression)
+ return Base::Tools::fromStdString(expr_info.expression->toString());
+ else
+ return QVariant();
+ }
+ else
+ return QListWidgetItem::data(role);
}
- int ConstraintNbr;
- Sketcher::ConstraintType Type;
- bool isDriving;
- bool isEnforceable;
+ Sketcher::ConstraintType constraintType() const {
+ assert(ConstraintNbr >= 0 && ConstraintNbr < sketch->Constraints.getSize());
+ return sketch->Constraints[ConstraintNbr]->Type;
+ }
-private:
- QVariant quantity;
-
+ bool isEnforceable() const {
+ assert(ConstraintNbr >= 0 && ConstraintNbr < sketch->Constraints.getSize());
+
+ const Sketcher::Constraint * constraint = sketch->Constraints[ConstraintNbr];
+
+ switch (constraint->Type) {
+ case Sketcher::None:
+ assert( false );
+ return false;
+ case Sketcher::Horizontal:
+ case Sketcher::Vertical:
+ case Sketcher::Coincident:
+ case Sketcher::PointOnObject:
+ case Sketcher::Parallel:
+ case Sketcher::Perpendicular:
+ case Sketcher::Tangent:
+ case Sketcher::Equal:
+ case Sketcher::Symmetric:
+ return true;
+ case Sketcher::Distance:
+ case Sketcher::DistanceX:
+ case Sketcher::DistanceY:
+ case Sketcher::Radius:
+ case Sketcher::Angle:
+ case Sketcher::SnellsLaw:
+ return ( constraint->First >= 0 || constraint->Second >= 0 || constraint->Third >= 0 );
+ case Sketcher::InternalAlignment:
+ return true;
+ }
+ return false;
+ }
+
+ bool isDriving() const {
+ assert(ConstraintNbr >= 0 && ConstraintNbr < sketch->Constraints.getSize());
+
+ return sketch->Constraints[ConstraintNbr]->isDriving;
+ }
+
+ const Sketcher::SketchObject * sketch;
+ int ConstraintNbr;
+ QVariant value;
+};
+
+class ExpressionDelegate : public QStyledItemDelegate
+{
+public:
+ ExpressionDelegate(QListWidget * _view) : view(_view) { }
+protected:
+ QPixmap getIcon(const char* name, const QSize& size) const
+ {
+ QString key = QString::fromAscii("%1_%2x%3")
+ .arg(QString::fromAscii(name))
+ .arg(size.width())
+ .arg(size.height());
+ QPixmap icon;
+ if (QPixmapCache::find(key, icon))
+ return icon;
+
+ icon = Gui::BitmapFactory().pixmapFromSvg(name, size);
+ if (!icon.isNull())
+ QPixmapCache::insert(key, icon);
+ return icon;
+ }
+
+ void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const {
+ QStyleOptionViewItemV4 options = option;
+ initStyleOption(&options, index);
+
+ options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);
+
+ ConstraintItem * item = dynamic_cast(view->item(index.row()));
+ App::ObjectIdentifier path = item->sketch->Constraints.createPath(item->ConstraintNbr);
+ App::PropertyExpressionEngine::ExpressionInfo expr_info = item->sketch->getExpression(path);
+
+ if (item->sketch->Constraints[item->ConstraintNbr]->isDriving && expr_info.expression) {
+ // Paint pixmap
+ int s = 2 * options.rect.height() / 4;
+ int margin = s;
+ QPixmap pixmap = getIcon(":/icons/bound-expression.svg", QSize(s, s));
+ QRect r(options.rect);
+
+ r.setTop(r.top() + (r.height() - s) / 2);
+ r.setLeft(r.right() - s);
+ r.setHeight(s);
+ r.moveLeft(r.left() - margin);
+ painter->drawPixmap(r, pixmap);
+ }
+ }
+
+ QListWidget * view;
};
ConstraintView::ConstraintView(QWidget *parent)
: QListWidget(parent)
{
+ ExpressionDelegate * delegate = new ExpressionDelegate(this);
+ setItemDelegate(delegate);
}
ConstraintView::~ConstraintView()
@@ -140,13 +375,12 @@ void ConstraintView::contextMenuEvent (QContextMenuEvent* event)
QAction* driven = menu.addAction(tr("Toggle to/from reference"), this, SLOT(updateDrivingStatus()));
// if its the right constraint
- if ((it->Type == Sketcher::Distance ||
- it->Type == Sketcher::DistanceX ||
- it->Type == Sketcher::DistanceY ||
- it->Type == Sketcher::Radius ||
- it->Type == Sketcher::Angle ||
- it->Type == Sketcher::SnellsLaw) && it->isEnforceable) {
-
+ if ((it->constraintType() == Sketcher::Distance ||
+ it->constraintType() == Sketcher::DistanceX ||
+ it->constraintType() == Sketcher::DistanceY ||
+ it->constraintType() == Sketcher::Radius ||
+ it->constraintType() == Sketcher::Angle ||
+ it->constraintType() == Sketcher::SnellsLaw) && it->isEnforceable()) {
driven->setEnabled(true);
}
else{
@@ -156,7 +390,7 @@ void ConstraintView::contextMenuEvent (QContextMenuEvent* event)
QAction* change = menu.addAction(tr("Change value"), this, SLOT(modifyCurrentItem()));
QVariant v = item ? item->data(Qt::UserRole) : QVariant();
- change->setEnabled(v.isValid() && it->isDriving);
+ change->setEnabled(v.isValid() && it->isDriving());
}
QAction* rename = menu.addAction(tr("Rename"), this, SLOT(renameCurrentItem())
@@ -172,6 +406,10 @@ void ConstraintView::contextMenuEvent (QContextMenuEvent* event)
QAction* remove = menu.addAction(tr("Delete"), this, SLOT(deleteSelectedItems()),
QKeySequence(QKeySequence::Delete));
remove->setEnabled(!items.isEmpty());
+
+ QAction* swap = menu.addAction(tr("Swap constraint names"), this, SLOT(swapNamedOfSelectedItems()));
+ swap->setEnabled(items.size() == 2);
+
menu.exec(event->globalPos());
}
@@ -184,7 +422,7 @@ void ConstraintView::updateDrivingStatus()
if (item){
ConstraintItem *it = dynamic_cast(item);
- onUpdateDrivingStatus(item, !it->isDriving);
+ onUpdateDrivingStatus(item, !it->isDriving());
}
}
@@ -222,6 +460,35 @@ void ConstraintView::deleteSelectedItems()
doc->commitTransaction();
}
+void ConstraintView::swapNamedOfSelectedItems()
+{
+ QList items = selectedItems();
+
+ if (items.size() != 2)
+ return;
+
+ ConstraintItem * item1 = static_cast(items[0]);
+ std::string escapedstr1 = Base::Tools::escapedUnicodeFromUtf8(item1->sketch->Constraints[item1->ConstraintNbr]->Name.c_str());
+ ConstraintItem * item2 = static_cast(items[1]);
+ std::string escapedstr2 = Base::Tools::escapedUnicodeFromUtf8(item2->sketch->Constraints[item2->ConstraintNbr]->Name.c_str());
+ std::stringstream ss;
+
+ ss << "DummyConstraint" << rand();
+ std::string tmpname = ss.str();
+
+ Gui::Command::openCommand("Swap constraint names");
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.renameConstraint(%d, '%s')",
+ item1->sketch->getNameInDocument(),
+ item1->ConstraintNbr, tmpname.c_str());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.renameConstraint(%d, '%s')",
+ item2->sketch->getNameInDocument(),
+ item2->ConstraintNbr, escapedstr1.c_str());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.renameConstraint(%d, '%s')",
+ item1->sketch->getNameInDocument(),
+ item1->ConstraintNbr, escapedstr2.c_str());
+ Gui::Command::commitCommand();
+}
+
// ----------------------------------------------------------------------------
TaskSketcherConstrains::TaskSketcherConstrains(ViewProviderSketch *sketchView)
@@ -338,9 +605,9 @@ void TaskSketcherConstrains::on_listWidgetConstraints_itemSelectionChanged(void)
Gui::Selection().clearSelection();
QList items = ui->listWidgetConstraints->selectedItems();
for (QList::iterator it = items.begin(); it != items.end(); ++it) {
- std::stringstream ss;
- ss << "Constraint" << static_cast(*it)->ConstraintNbr + 1;
- Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
+ std::string constraint_name(Sketcher::PropertyConstraintList::getConstraintName(static_cast(*it)->ConstraintNbr));
+
+ Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), constraint_name.c_str());
}
this->blockConnection(block);
}
@@ -351,12 +618,12 @@ void TaskSketcherConstrains::on_listWidgetConstraints_itemActivated(QListWidgetI
if (!item) return;
// if its the right constraint
- if ((it->Type == Sketcher::Distance ||
- it->Type == Sketcher::DistanceX ||
- it->Type == Sketcher::DistanceY ||
- it->Type == Sketcher::Radius ||
- it->Type == Sketcher::Angle ||
- it->Type == Sketcher::SnellsLaw) && it->isDriving) {
+ if (it->constraintType() == Sketcher::Distance ||
+ it->constraintType() == Sketcher::DistanceX ||
+ it->constraintType() == Sketcher::DistanceY ||
+ it->constraintType() == Sketcher::Radius ||
+ it->constraintType() == Sketcher::Angle ||
+ it->constraintType() == Sketcher::SnellsLaw) {
EditDatumDialog *editDatumDialog = new EditDatumDialog(this->sketchView, it->ConstraintNbr);
editDatumDialog->exec(false);
@@ -377,227 +644,111 @@ void TaskSketcherConstrains::on_listWidgetConstraints_itemChanged(QListWidgetIte
{
if (!item || inEditMode)
return;
- ConstraintItem *it = dynamic_cast(item);
- const std::vector< Sketcher::Constraint * > &vals = sketchView->getSketchObject()->Constraints.getValues();
- Sketcher::Constraint* v = vals[it->ConstraintNbr];
- QString name = it->data(Qt::EditRole).toString();
- if (name.isEmpty())
- name = QString::fromLatin1("Constraint%1").arg(it->ConstraintNbr+1);
+ inEditMode = true;
- QString unitStr;
- switch(v->Type) {
- case Sketcher::Distance:
- case Sketcher::DistanceX:
- case Sketcher::DistanceY:
- case Sketcher::Radius:
- unitStr = Base::Quantity(v->Value,Base::Unit::Length).getUserString();
- break;
- case Sketcher::Angle:
- unitStr = Base::Quantity(Base::toDegrees(std::abs(v->Value)),Base::Unit::Angle).getUserString();
- break;
- case Sketcher::SnellsLaw:
- {
- double n1 = 1.0;
- double n2 = 1.0;
- if (fabs(v->Value) >= 1) {
- n2 = v->Value;
- } else {
- n1 = 1/v->Value;
- }
- unitStr = QString::fromLatin1("%1/%2").arg(n2).arg(n1);
+ const ConstraintItem *it = dynamic_cast(item);
+ const Sketcher::SketchObject * sketch = sketchView->getSketchObject();
+ const std::vector< Sketcher::Constraint * > &vals = sketch->Constraints.getValues();
+ const Sketcher::Constraint* v = vals[it->ConstraintNbr];
+ const std::string currConstraintName = v->Name;
+
+ std::string newName(Sketcher::PropertyConstraintList::getConstraintName(Base::Tools::toStdString(it->data(Qt::EditRole).toString()), it->ConstraintNbr));
+
+ if (newName != currConstraintName) {
+ std::string escapedstr = Base::Tools::escapedUnicodeFromUtf8(newName.c_str());
+
+ Gui::Command::openCommand("Rename sketch constraint");
+ try {
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.renameConstraint(%d, '%s')",
+ sketch->getNameInDocument(),
+ it->ConstraintNbr, escapedstr.c_str());
+ Gui::Command::commitCommand();
+ }
+ catch (const Base::Exception & e) {
+ Gui::Command::abortCommand();
+
+ QMessageBox::critical(Gui::MainWindow::getInstance(), QString::fromAscii("Error"),
+ QString::fromAscii(e.what()), QMessageBox::Ok, QMessageBox::Ok);
}
- break;
- default:
- break;
}
- v->Name = (const char*)name.toUtf8();
- if (!unitStr.isEmpty()) {
- inEditMode = true;
- item->setData(Qt::UserRole, QString::fromLatin1("%1 (%2)")
- .arg(name)
- .arg(unitStr));
- inEditMode = false;
- }
+ inEditMode = false;
}
void TaskSketcherConstrains::slotConstraintsChanged(void)
{
- QIcon hdist( Gui::BitmapFactory().pixmap("Constraint_HorizontalDistance") );
- QIcon vdist( Gui::BitmapFactory().pixmap("Constraint_VerticalDistance") );
- QIcon horiz( Gui::BitmapFactory().pixmap("Constraint_Horizontal") );
- QIcon vert ( Gui::BitmapFactory().pixmap("Constraint_Vertical") );
- QIcon lock ( Gui::BitmapFactory().pixmap("Sketcher_ConstrainLock") );
- QIcon coinc( Gui::BitmapFactory().pixmap("Constraint_PointOnPoint") );
- QIcon para ( Gui::BitmapFactory().pixmap("Constraint_Parallel") );
- QIcon perp ( Gui::BitmapFactory().pixmap("Constraint_Perpendicular") );
- QIcon tang ( Gui::BitmapFactory().pixmap("Constraint_Tangent") );
- QIcon dist ( Gui::BitmapFactory().pixmap("Constraint_Length") );
- QIcon radi ( Gui::BitmapFactory().pixmap("Constraint_Radius") );
- QIcon majradi ( Gui::BitmapFactory().pixmap("Constraint_Ellipse_Major_Radius") );
- QIcon minradi ( Gui::BitmapFactory().pixmap("Constraint_Ellipse_Minor_Radius") );
- QIcon angl ( Gui::BitmapFactory().pixmap("Constraint_InternalAngle") );
- QIcon ellipseXUAngl ( Gui::BitmapFactory().pixmap("Constraint_Ellipse_Axis_Angle") );
- QIcon equal( Gui::BitmapFactory().pixmap("Constraint_EqualLength") );
- QIcon pntoo( Gui::BitmapFactory().pixmap("Constraint_PointOnObject") );
- QIcon symm ( Gui::BitmapFactory().pixmap("Constraint_Symmetric") );
- QIcon snell ( Gui::BitmapFactory().pixmap("Constraint_SnellsLaw") );
- QIcon iaellipseminoraxis ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment_Ellipse_MinorAxis") );
- QIcon iaellipsemajoraxis ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment_Ellipse_MajorAxis") );
- QIcon iaellipsefocus1 ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment_Ellipse_Focus1") );
- QIcon iaellipsefocus2 ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment_Ellipse_Focus2") );
- QIcon iaellipseother ( Gui::BitmapFactory().pixmap("Constraint_InternalAlignment") );
-
- QIcon hdist_driven ( Gui::BitmapFactory().pixmap("Constraint_HorizontalDistance_Driven") );
- QIcon vdist_driven( Gui::BitmapFactory().pixmap("Constraint_VerticalDistance_Driven") );
- QIcon dist_driven ( Gui::BitmapFactory().pixmap("Constraint_Length_Driven") );
- QIcon radi_driven ( Gui::BitmapFactory().pixmap("Constraint_Radius_Driven") );
- QIcon angl_driven ( Gui::BitmapFactory().pixmap("Constraint_InternalAngle_Driven") );
- QIcon snell_driven ( Gui::BitmapFactory().pixmap("Constraint_SnellsLaw_Driven") );
-
assert(sketchView);
// Build up ListView with the constraints
- const std::vector< Sketcher::Constraint * > &vals = sketchView->getSketchObject()->Constraints.getValues();
+ const Sketcher::SketchObject * sketch = sketchView->getSketchObject();
+ const std::vector< Sketcher::Constraint * > &vals = sketch->Constraints.getValues();
- ui->listWidgetConstraints->clear();
- QString name;
+ /* Update constraint number */
+ for (int i = 0; i < ui->listWidgetConstraints->count(); ++i) {
+ ConstraintItem * it = dynamic_cast(ui->listWidgetConstraints->item(i));
+ assert(it != 0);
+
+ it->ConstraintNbr = i;
+ it->value = QVariant();
+ }
+
+ /* Remove entries, if any */
+ for (std::size_t i = ui->listWidgetConstraints->count(); i > vals.size(); --i)
+ delete ui->listWidgetConstraints->takeItem(i - 1);
+
+ /* Add new entries, if any */
+ for (std::size_t i = ui->listWidgetConstraints->count(); i < vals.size(); ++i)
+ ui->listWidgetConstraints->addItem(new ConstraintItem(sketch, i));
+
+ /* Update filtering */
int Filter = ui->comboBoxFilter->currentIndex();
+ for(std::size_t i = 0; i < vals.size(); ++i) {
+ const Sketcher::Constraint * constraint = vals[i];
+ ConstraintItem * it = static_cast(ui->listWidgetConstraints->item(i));
+ bool visible = true;
- int i=1;
- for(std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it!=vals.end();++it,++i){
- if ((*it)->Name.empty())
- name = QString::fromLatin1("Constraint%1").arg(i);
- else
- name = QString::fromUtf8((*it)->Name.c_str());
+ /* Filter
+ 0 <=> All
+ 1 <=> Normal
+ 2 <=> Datums
+ 3 <=> Named
+ 4 <=> Non-Driving
+ */
- /* Filter
- 0 <=> All
- 1 <=> Normal
- 2 <=> Datums
- 3 <=> Named
- 4 <=> Non-Driving
- */
- switch((*it)->Type){
- case Sketcher::Horizontal:
- if (Filter<2 || (Filter==3 && !(*it)->Name.empty()))
- ui->listWidgetConstraints->addItem(new ConstraintItem(horiz,name,i-1,(*it)->Type));
- break;
- case Sketcher::Vertical:
- if (Filter<2 || (Filter==3 && !(*it)->Name.empty()))
- ui->listWidgetConstraints->addItem(new ConstraintItem(vert,name,i-1,(*it)->Type));
- break;
- case Sketcher::Coincident:
- if (Filter<1 || (Filter==3 && !(*it)->Name.empty()))
- ui->listWidgetConstraints->addItem(new ConstraintItem(coinc,name,i-1,(*it)->Type));
- break;
- case Sketcher::PointOnObject:
- if (Filter<2 || (Filter==3 && !(*it)->Name.empty()))
- ui->listWidgetConstraints->addItem(new ConstraintItem(pntoo,name,i-1,(*it)->Type));
- break;
- case Sketcher::Parallel:
- if (Filter<2 || (Filter==3 && !(*it)->Name.empty()))
- ui->listWidgetConstraints->addItem(new ConstraintItem(para,name,i-1,(*it)->Type));
- break;
- case Sketcher::Perpendicular:
- if (Filter<2 || (Filter==3 && !(*it)->Name.empty()))
- ui->listWidgetConstraints->addItem(new ConstraintItem(perp,name,i-1,(*it)->Type));
- break;
- case Sketcher::Tangent:
- if (Filter<2 || (Filter==3 && !(*it)->Name.empty()))
- ui->listWidgetConstraints->addItem(new ConstraintItem(tang,name,i-1,(*it)->Type));
- break;
- case Sketcher::Equal:
- if (Filter<2 || (Filter==3 && !(*it)->Name.empty()))
- ui->listWidgetConstraints->addItem(new ConstraintItem(equal,name,i-1,(*it)->Type));
- break;
- case Sketcher::Symmetric:
- if (Filter<2 || (Filter==3 && !(*it)->Name.empty()))
- ui->listWidgetConstraints->addItem(new ConstraintItem(symm,name,i-1,(*it)->Type));
- break;
- case Sketcher::Distance:
- if (((Filter<3 || !(*it)->Name.empty())) || (Filter==4 && !(*it)->isDriving)) {
- ConstraintItem* item = new ConstraintItem((*it)->isDriving?dist:dist_driven,name,i-1,(*it)->Type,(*it)->isDriving, ((*it)->First>=0 || (*it)->Second>=0 || (*it)->Third>=0));
- name = QString::fromLatin1("%1 (%2)").arg(name).arg(Base::Quantity((*it)->Value,Base::Unit::Length).getUserString());
- item->setData(Qt::UserRole, name);
- ui->listWidgetConstraints->addItem(item);
- }
- break;
- case Sketcher::DistanceX:
- if (((Filter<3 || !(*it)->Name.empty())) || (Filter==4 && !(*it)->isDriving)) {
- ConstraintItem* item = new ConstraintItem((*it)->isDriving?hdist:hdist_driven,name,i-1,(*it)->Type,(*it)->isDriving, ((*it)->First>=0 || (*it)->Second>=0 || (*it)->Third>=0));
- name = QString::fromLatin1("%1 (%2)").arg(name).arg(Base::Quantity(std::abs((*it)->Value),Base::Unit::Length).getUserString());
- item->setData(Qt::UserRole, name);
- ui->listWidgetConstraints->addItem(item);
- }
- break;
- case Sketcher::DistanceY:
- if (((Filter<3 || !(*it)->Name.empty())) || (Filter==4 && !(*it)->isDriving)) {
- ConstraintItem* item = new ConstraintItem((*it)->isDriving?vdist:vdist_driven,name,i-1,(*it)->Type,(*it)->isDriving, ((*it)->First>=0 || (*it)->Second>=0 || (*it)->Third>=0));
- name = QString::fromLatin1("%1 (%2)").arg(name).arg(Base::Quantity(std::abs((*it)->Value),Base::Unit::Length).getUserString());
- item->setData(Qt::UserRole, name);
- ui->listWidgetConstraints->addItem(item);
- }
- break;
- case Sketcher::Radius:
- if (((Filter<3 || !(*it)->Name.empty())) || (Filter==4 && !(*it)->isDriving)) {
- ConstraintItem* item = new ConstraintItem((*it)->isDriving?radi:radi_driven,name,i-1,(*it)->Type,(*it)->isDriving, ((*it)->First>=0 || (*it)->Second>=0 || (*it)->Third>=0));
- name = QString::fromLatin1("%1 (%2)").arg(name).arg(Base::Quantity((*it)->Value,Base::Unit::Length).getUserString());
- item->setData(Qt::UserRole, name);
- ui->listWidgetConstraints->addItem(item);
- }
- break;
- case Sketcher::Angle:
- if (((Filter<3 || !(*it)->Name.empty())) || (Filter==4 && !(*it)->isDriving)) {
- ConstraintItem* item = new ConstraintItem((*it)->isDriving?angl:angl_driven,name,i-1,(*it)->Type,(*it)->isDriving, ((*it)->First>=0 || (*it)->Second>=0 || (*it)->Third>=0));
- name = QString::fromLatin1("%1 (%2)").arg(name).arg(Base::Quantity(Base::toDegrees(std::abs((*it)->Value)),Base::Unit::Angle).getUserString());
- item->setData(Qt::UserRole, name);
- ui->listWidgetConstraints->addItem(item);
- }
- break;
- case Sketcher::SnellsLaw:
- if (((Filter<3 || !(*it)->Name.empty())) || (Filter==4 && !(*it)->isDriving)) {
- ConstraintItem* item = new ConstraintItem((*it)->isDriving?snell:snell_driven,name,i-1,(*it)->Type,(*it)->isDriving, ((*it)->First>=0 || (*it)->Second>=0 || (*it)->Third>=0));
+ bool showNormal = (Filter < 2);
+ bool showDatums = (Filter < 3);
+ bool showNamed = (Filter == 3 && !(constraint->Name.empty()));
+ bool showNonDriving = (Filter == 4 && !constraint->isDriving);
- double v = (*it)->Value;
- double n1 = 1.0;
- double n2 = 1.0;
- if (fabs(v) >= 1) {
- n2 = v;
- } else {
- n1 = 1/v;
- }
- name = QString::fromLatin1("%1 (%2/%3)").arg(name).arg(n2).arg(n1);
- item->setData(Qt::UserRole, name);
- ui->listWidgetConstraints->addItem(item);
- }
- break;
- case Sketcher::InternalAlignment:
- if (Filter<2 || (Filter==3 && !(*it)->Name.empty()))
- switch((*it)->AlignmentType){
- case Sketcher::EllipseMajorDiameter:
- ui->listWidgetConstraints->addItem(new ConstraintItem(iaellipsemajoraxis,name,i-1,(*it)->Type));
- break;
- case Sketcher::EllipseMinorDiameter:
- ui->listWidgetConstraints->addItem(new ConstraintItem(iaellipseminoraxis,name,i-1,(*it)->Type));
- break;
- case Sketcher::EllipseFocus1:
- ui->listWidgetConstraints->addItem(new ConstraintItem(iaellipsefocus1,name,i-1,(*it)->Type));
- break;
- case Sketcher::EllipseFocus2:
- ui->listWidgetConstraints->addItem(new ConstraintItem(iaellipsefocus2,name,i-1,(*it)->Type));
- break;
- case Sketcher::Undef:
- default:
- ui->listWidgetConstraints->addItem(new ConstraintItem(iaellipseother,name,i-1,(*it)->Type));
- break;
- }
- break;
- default:
- ui->listWidgetConstraints->addItem(new ConstraintItem(name,i-1,(*it)->Type));
- break;
+ switch(constraint->Type) {
+ case Sketcher::Horizontal:
+ case Sketcher::Vertical:
+ case Sketcher::Coincident:
+ case Sketcher::PointOnObject:
+ case Sketcher::Parallel:
+ case Sketcher::Perpendicular:
+ case Sketcher::Tangent:
+ case Sketcher::Equal:
+ case Sketcher::Symmetric:
+ visible = showNormal || showNamed;
+ break;
+ case Sketcher::Distance:
+ case Sketcher::DistanceX:
+ case Sketcher::DistanceY:
+ case Sketcher::Radius:
+ case Sketcher::Angle:
+ case Sketcher::SnellsLaw:
+ visible = (showDatums || showNamed || showNonDriving);
+ break;
+ case Sketcher::InternalAlignment:
+ visible = (showNormal || showNamed);
+ default:
+ break;
}
+
+ it->setHidden(!visible);
+ it->setData(Qt::EditRole, Base::Tools::fromStdString(constraint->Name));
}
}
diff --git a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.h b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.h
index ee5dbd490c..04f8a81512 100644
--- a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.h
+++ b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.h
@@ -60,6 +60,7 @@ protected Q_SLOTS:
void deleteSelectedItems();
void doSelectConstraints();
void updateDrivingStatus();
+ void swapNamedOfSelectedItems();
};
class TaskSketcherConstrains : public Gui::TaskView::TaskBox, public Gui::SelectionObserver
diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
index 5721d5b80e..dc9bc0d3fd 100644
--- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
+++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
@@ -689,19 +689,18 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe
case STATUS_SELECT_Constraint:
if (pp) {
for(std::set::iterator it = edit->PreselectConstraintSet.begin(); it != edit->PreselectConstraintSet.end(); ++it) {
- std::stringstream ss;
- ss << "Constraint" << *it + 1;
+ std::string constraintName(Sketcher::PropertyConstraintList::getConstraintName(*it));
// If the constraint already selected remove
if (Gui::Selection().isSelected(getSketchObject()->getDocument()->getName()
- ,getSketchObject()->getNameInDocument(),ss.str().c_str()) ) {
+ ,getSketchObject()->getNameInDocument(),constraintName.c_str()) ) {
Gui::Selection().rmvSelection(getSketchObject()->getDocument()->getName()
- ,getSketchObject()->getNameInDocument(), ss.str().c_str());
+ ,getSketchObject()->getNameInDocument(), constraintName.c_str());
} else {
// Add constraint to current selection
Gui::Selection().addSelection(getSketchObject()->getDocument()->getName()
,getSketchObject()->getNameInDocument()
- ,ss.str().c_str()
+ ,constraintName.c_str()
,pp->getPoint()[0]
,pp->getPoint()[1]
,pp->getPoint()[2]);
@@ -1443,7 +1442,7 @@ void ViewProviderSketch::onSelectionChanged(const Gui::SelectionChanges& msg)
this->updateColor();
}
else if (shapetype.size() > 10 && shapetype.substr(0,10) == "Constraint") {
- int ConstrId = std::atoi(&shapetype[10]) - 1;
+ int ConstrId = Sketcher::PropertyConstraintList::getIndexFromConstraintName(shapetype);
edit->SelConstraintSet.insert(ConstrId);
this->drawConstraintIcons();
this->updateColor();
@@ -1488,7 +1487,7 @@ void ViewProviderSketch::onSelectionChanged(const Gui::SelectionChanges& msg)
this->updateColor();
}
else if (shapetype.size() > 10 && shapetype.substr(0,10) == "Constraint") {
- int ConstrId = std::atoi(&shapetype[10]) - 1;
+ int ConstrId = Sketcher::PropertyConstraintList::getIndexFromConstraintName(shapetype);
edit->SelConstraintSet.erase(ConstrId);
this->drawConstraintIcons();
this->updateColor();
@@ -1742,12 +1741,12 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point,
} else if (constrIndices.empty() == false && constrIndices != edit->PreselectConstraintSet) { // if a constraint is hit
bool accepted = true;
for(std::set::iterator it = constrIndices.begin(); it != constrIndices.end(); ++it) {
- std::stringstream ss;
- ss << "Constraint" << *it + 1;
+ std::string constraintName(Sketcher::PropertyConstraintList::getConstraintName(*it));
+
accepted &=
Gui::Selection().setPreselect(getSketchObject()->getDocument()->getName()
,getSketchObject()->getNameInDocument()
- ,ss.str().c_str()
+ ,constraintName.c_str()
,Point->getPoint()[0]
,Point->getPoint()[1]
,Point->getPoint()[2]);
@@ -3525,9 +3524,9 @@ Restart:
if ((Constr->Type == DistanceX || Constr->Type == DistanceY) &&
Constr->FirstPos != Sketcher::none && Constr->Second == Constraint::GeoUndef)
// display negative sign for absolute coordinates
- asciiText->string = SbString(Base::Quantity(Constr->Value,Base::Unit::Length).getUserString().toUtf8().constData());
+ asciiText->string = SbString(Base::Quantity(Constr->getValue(),Base::Unit::Length).getUserString().toUtf8().constData());
else // hide negative sign
- asciiText->string = SbString(Base::Quantity(std::abs(Constr->Value),Base::Unit::Length).getUserString().toUtf8().constData());
+ asciiText->string = SbString(Base::Quantity(std::abs(Constr->getValue()),Base::Unit::Length).getUserString().toUtf8().constData());
if (Constr->Type == Distance)
asciiText->datumtype = SoDatumLabel::DISTANCE;
@@ -3826,7 +3825,7 @@ Restart:
break;
SoDatumLabel *asciiText = dynamic_cast(sep->getChild(CONSTRAINT_SEPARATOR_INDEX_MATERIAL_OR_DATUMLABEL));
- asciiText->string = SbString(Base::Quantity(Base::toDegrees(std::abs(Constr->Value)),Base::Unit::Angle).getUserString().toUtf8().constData());
+ asciiText->string = SbString(Base::Quantity(Base::toDegrees(std::abs(Constr->getValue())),Base::Unit::Angle).getUserString().toUtf8().constData());
asciiText->datumtype = SoDatumLabel::ANGLE;
asciiText->param1 = Constr->LabelDistance;
asciiText->param2 = startangle;
@@ -3880,7 +3879,7 @@ Restart:
SbVec3f p2(pnt2.x,pnt2.y,zConstr);
SoDatumLabel *asciiText = dynamic_cast(sep->getChild(CONSTRAINT_SEPARATOR_INDEX_MATERIAL_OR_DATUMLABEL));
- asciiText->string = SbString(Base::Quantity(Constr->Value,Base::Unit::Length).getUserString().toUtf8().constData());
+ asciiText->string = SbString(Base::Quantity(Constr->getValue(),Base::Unit::Length).getUserString().toUtf8().constData());
asciiText->datumtype = SoDatumLabel::RADIUS;
asciiText->param1 = Constr->LabelDistance;
@@ -4129,7 +4128,9 @@ void ViewProviderSketch::updateData(const App::Property *prop)
if(getSketchObject()->getExternalGeometryCount()+getSketchObject()->getHighestCurveIndex() + 1 ==
getSketchObject()->getSolvedSketch().getGeometrySize()) {
- draw(false);
+ Gui::MDIView *mdi = Gui::Application::Instance->activeDocument()->getActiveView();
+ if (mdi->isDerivedFrom(Gui::View3DInventor::getClassTypeId()))
+ draw(false);
signalConstraintsChanged();
signalElementsChanged();
@@ -4778,7 +4779,7 @@ bool ViewProviderSketch::onDelete(const std::vector &subList)
} else if (*it == "RootPoint") {
delCoincidents.insert(-1);
} else if (it->size() > 10 && it->substr(0,10) == "Constraint") {
- int ConstrId = std::atoi(it->substr(10,4000).c_str()) - 1;
+ int ConstrId = Sketcher::PropertyConstraintList::getIndexFromConstraintName(*it);
delConstraints.insert(ConstrId);
}
}