Merge branch 'master' into feature/suppress-warnings-preferences

This commit is contained in:
sliptonic
2020-12-18 11:12:48 -06:00
committed by GitHub
23 changed files with 1409 additions and 802 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -105,7 +105,7 @@ Py::Dict TooltablePy::getTools(void) const
{
Py::Dict dict;
for(std::map<int,Path::Tool*>::iterator i = getTooltablePtr()->Tools.begin(); i != getTooltablePtr()->Tools.end(); ++i) {
PyObject *tool = new Path::ToolPy(i->second);
PyObject *tool = new Path::ToolPy(new Tool(*i->second));
dict.setItem(Py::Long(i->first), Py::asObject(tool));
}
return dict;

View File

@@ -35,13 +35,8 @@ __doc__ = "A collection of helper and utility functions for the Path GUI."
def translate(context, text, disambig=None):
return PySide.QtCore.QCoreApplication.translate(context, text, disambig)
LOGLEVEL = False
if LOGLEVEL:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
# PathLog.trackModule(PathLog.thisModule())
def updateInputField(obj, prop, widget, onBeforeChange=None):
@@ -53,7 +48,7 @@ def updateInputField(obj, prop, widget, onBeforeChange=None):
If onBeforeChange is specified it is called before a new value is assigned to the property.
Returns True if a new value was assigned, False otherwise (new value is the same as the current).
'''
value = FreeCAD.Units.Quantity(widget.text()).Value
value = widget.property('rawValue')
attr = PathUtil.getProperty(obj, prop)
attrValue = attr.Value if hasattr(attr, 'Value') else attr
@@ -72,10 +67,10 @@ def updateInputField(obj, prop, widget, onBeforeChange=None):
isDiff = True
break
if noExpr:
widget.setReadOnly(False)
widget.setProperty('readonly', False)
widget.setStyleSheet("color: black")
else:
widget.setReadOnly(True)
widget.setProperty('readonly', True)
widget.setStyleSheet("color: gray")
widget.update()
@@ -100,19 +95,26 @@ class QuantitySpinBox:
'''
def __init__(self, widget, obj, prop, onBeforeChange=None):
self.obj = obj
PathLog.track(widget)
self.widget = widget
self.prop = prop
self.onBeforeChange = onBeforeChange
self.attachTo(obj, prop)
attr = PathUtil.getProperty(self.obj, self.prop)
if attr is not None:
if hasattr(attr, 'Value'):
widget.setProperty('unit', attr.getUserPreferred()[2])
widget.setProperty('binding', "%s.%s" % (obj.Name, prop))
self.valid = True
def attachTo(self, obj, prop = None):
'''attachTo(obj, prop=None) ... use an existing editor for the given object and property'''
self.obj = obj
self.prop = prop
if obj and prop:
attr = PathUtil.getProperty(obj, prop)
if attr is not None:
if hasattr(attr, 'Value'):
self.widget.setProperty('unit', attr.getUserPreferred()[2])
self.widget.setProperty('binding', "%s.%s" % (obj.Name, prop))
self.valid = True
else:
PathLog.warning(translate('PathGui', "Cannot find property %s of %s") % (prop, obj.Label))
self.valid = False
else:
PathLog.warning(translate('PathGui', "Cannot find property %s of %s") % (prop, obj.Label))
self.valid = False
def expression(self):
@@ -122,6 +124,7 @@ class QuantitySpinBox:
return ''
def setMinimum(self, quantity):
'''setMinimum(quantity) ... set the minimum'''
if self.valid:
value = quantity.Value if hasattr(quantity, 'Value') else quantity
self.widget.setProperty('setMinimum', value)

View File

@@ -200,7 +200,9 @@ class ToolBit(object):
return [prop for prop in obj.PropertiesList if obj.getGroupOfProperty(prop) == PropertyGroupAttribute]
def onDocumentRestored(self, obj):
obj.setEditorMode('BitShape', 1)
# when files are shared it is essential to be able to change/set the shape file,
# otherwise the file is hard to use
# obj.setEditorMode('BitShape', 1)
obj.setEditorMode('BitBody', 2)
obj.setEditorMode('File', 1)
obj.setEditorMode('Shape', 2)
@@ -252,7 +254,7 @@ class ToolBit(object):
p = findShape(p)
if not path and p != obj.BitShape:
obj.BitShape = p
doc = FreeCAD.open(p)
doc = FreeCAD.openDocument(p, True)
obj.ShapeName = doc.Name
docOpened = True
return (doc, docOpened)
@@ -286,21 +288,22 @@ class ToolBit(object):
self._removeBitBody(obj)
def _setupBitShape(self, obj, path=None):
PathLog.track(obj.Label)
activeDoc = FreeCAD.ActiveDocument
(doc, docOpened) = self._loadBitBody(obj, path)
obj.Label = doc.RootObjects[0].Label
self._deleteBitSetup(obj)
obj.BitBody = obj.Document.copyObject(doc.RootObjects[0], True)
bitBody = obj.Document.copyObject(doc.RootObjects[0], True)
if docOpened:
FreeCAD.setActiveDocument(activeDoc.Name)
FreeCAD.closeDocument(doc.Name)
if obj.BitBody.ViewObject:
obj.BitBody.ViewObject.Visibility = False
self._copyBitShape(obj)
if bitBody.ViewObject:
bitBody.ViewObject.Visibility = False
for sketch in [o for o in obj.BitBody.Group if o.TypeId == 'Sketcher::SketchObject']:
for sketch in [o for o in bitBody.Group if o.TypeId == 'Sketcher::SketchObject']:
for constraint in [c for c in sketch.Constraints if c.Name != '']:
typ = ParameterTypeConstraint.get(constraint.Type)
PathLog.track(constraint, typ)
@@ -316,6 +319,9 @@ class ToolBit(object):
if constraint.Type == 'Angle':
value = value * 180 / math.pi
PathUtil.setProperty(obj, prop, value)
# has to happen last because it could trigger op.execute evaluations
obj.BitBody = bitBody
self._copyBitShape(obj)
def getBitThumbnail(self, obj):
if obj.BitShape:

View File

@@ -62,24 +62,60 @@ class ToolBitEditor(object):
if self.loadbitbody:
self.tool.Proxy.loadBitBody(self.tool)
# remove example widgets
layout = self.form.bitParams.layout()
for i in range(layout.rowCount() - 1, -1, -1):
layout.removeRow(i)
# used to track property widgets and editors
self.widgets = []
self.setupTool(self.tool)
self.setupAttributes(self.tool)
def setupTool(self, tool):
PathLog.track()
# Can't delete and add fields to the form because of dangling references in case of
# a focus change. see https://forum.freecadweb.org/viewtopic.php?f=10&t=52246#p458583
# Instead we keep widgets once created and use them for new properties, and hide all
# which aren't being needed anymore.
def labelText(name):
return re.sub('([A-Z][a-z]+)', r' \1', re.sub('([A-Z]+)', r' \1', name))
layout = self.form.bitParams.layout()
for i in range(layout.rowCount() - 1, -1, -1):
layout.removeRow(i)
editor = {}
ui = FreeCADGui.UiLoader()
nr = 0
# for all properties either assign them to existing labels and editors
# or create additional ones for them if not enough have already been
# created.
for name in tool.PropertiesList:
if tool.getGroupOfProperty(name) == PathToolBit.PropertyGroupBit:
qsb = ui.createWidget('Gui::QuantitySpinBox')
editor[name] = PathGui.QuantitySpinBox(qsb, tool, name)
label = QtGui.QLabel(re.sub('([A-Z][a-z]+)', r' \1',
re.sub('([A-Z]+)', r' \1', name)))
layout.addRow(label, qsb)
self.bitEditor = editor
if nr < len(self.widgets):
PathLog.debug("re-use row: {} [{}]".format(nr, name))
label, qsb, editor = self.widgets[nr]
label.setText(labelText(name))
editor.attachTo(tool, name)
label.show()
qsb.show()
else:
qsb = ui.createWidget('Gui::QuantitySpinBox')
editor = PathGui.QuantitySpinBox(qsb, tool, name)
label = QtGui.QLabel(labelText(name))
self.widgets.append((label, qsb, editor))
PathLog.debug("create row: {} [{}]".format(nr, name))
if nr >= layout.rowCount():
layout.addRow(label, qsb)
nr = nr + 1
# hide all rows which aren't being used
for i in range(nr, len(self.widgets)):
label, qsb, editor = self.widgets[i]
label.hide()
qsb.hide()
editor.attachTo(None)
PathLog.debug(" hide row: {}".format(i))
img = tool.Proxy.getBitThumbnail(tool)
if img:
self.form.image.setPixmap(QtGui.QPixmap(QtGui.QImage.fromData(img)))
@@ -189,25 +225,28 @@ class ToolBitEditor(object):
self.form.toolName.setText(self.tool.Label)
self.form.shapePath.setText(self.tool.BitShape)
for editor in self.bitEditor:
self.bitEditor[editor].updateSpinBox()
for lbl, qsb, editor in self.widgets:
editor.updateSpinBox()
def updateShape(self):
PathLog.track()
self.tool.BitShape = str(self.form.shapePath.text())
self.setupTool(self.tool)
self.form.toolName.setText(self.tool.Label)
shapePath = str(self.form.shapePath.text())
# Only need to go through this exercise if the shape actually changed.
if self.tool.BitShape != shapePath:
self.tool.BitShape = shapePath
self.setupTool(self.tool)
self.form.toolName.setText(self.tool.Label)
for editor in self.bitEditor:
self.bitEditor[editor].updateSpinBox()
for lbl, qsb, editor in self.widgets:
editor.updateSpinBox()
def updateTool(self):
PathLog.track()
self.tool.Label = str(self.form.toolName.text())
self.tool.BitShape = str(self.form.shapePath.text())
for editor in self.bitEditor:
self.bitEditor[editor].updateProperty()
for lbl, qsb, editor in self.widgets:
editor.updateProperty()
# self.tool.Proxy._updateBitShape(self.tool)

View File

@@ -152,7 +152,9 @@ G0 Z0.500000
table.addTools(t2)
self.assertEqual(len(table.Tools), 2)
self.assertEqual(str(table.Tools), '{1: Tool 12.7mm Drill Bit, 2: Tool my other tool}' )
# gcc7 build needs some special treatment (makes 1L out of a 1) ...
if str(table.Tools) != '{1L: Tool 12.7mm Drill Bit, 2L: Tool my other tool}':
self.assertEqual(str(table.Tools), '{1: Tool 12.7mm Drill Bit, 2: Tool my other tool}')
def test50(self):
"""Test Path.Length calculation"""

View File

@@ -5987,7 +5987,7 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
std::swap(PosId1,PosId2);
}
if(isBsplinePole(Obj, GeoId1) || isBsplinePole(Obj, GeoId2)) {
if(isBsplinePole(Obj, GeoId1) || (GeoId2 != Constraint::GeoUndef && isBsplinePole(Obj, GeoId2))) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select an edge that is not a B-spline weight"));
return;
@@ -6538,14 +6538,14 @@ void CmdSketcherConstrainEqual::applyConstraint(std::vector<SelIdPair> &selSeq,
const Part::Geometry *geo1 = Obj->getGeometry(GeoId1);
const Part::Geometry *geo2 = Obj->getGeometry(GeoId2);
if ( (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() && geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId()) ||
(geo1->getTypeId() == Part::GeomHyperbola::getClassTypeId() && geo2->getTypeId() != Part::GeomHyperbola::getClassTypeId()) ||
(geo1->getTypeId() == Part::GeomParabola::getClassTypeId() && geo2->getTypeId() != Part::GeomParabola::getClassTypeId()) ||
(isBsplinePole(geo1) && !isBsplinePole(geo1)) ||
if ( (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() && geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId()) ||
(geo1->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() && geo2->getTypeId() != Part::GeomArcOfHyperbola::getClassTypeId()) ||
(geo1->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() && geo2->getTypeId() != Part::GeomArcOfParabola::getClassTypeId()) ||
(isBsplinePole(geo1) && !isBsplinePole(geo2)) ||
( (geo1->getTypeId() == Part::GeomCircle::getClassTypeId() || geo1->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) &&
(geo2->getTypeId() != Part::GeomCircle::getClassTypeId() || geo2->getTypeId() != Part::GeomArcOfCircle::getClassTypeId())) ||
!(geo2->getTypeId() == Part::GeomCircle::getClassTypeId() || geo2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId())) ||
( (geo1->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) &&
(geo2->getTypeId() != Part::GeomEllipse::getClassTypeId() || geo2->getTypeId() != Part::GeomArcOfEllipse::getClassTypeId())) ){
!(geo2->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId())) ){
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select two or more edges of similar type"));

View File

@@ -6106,9 +6106,9 @@ bool ViewProviderSketch::setEdit(int ModNum)
// is loaded into the solver, which ensures that any prospective draw using temporal
// geometry (draw with first parameter true) has the right ViewProvider geometry extensions
// set - This fixes Weight constraint dragging on a just opened sketch.
draw(false,true);
getSketchObject()->solve(false);
UpdateSolverInformation();
draw(false,true);
connectUndoDocument = getDocument()
->signalUndoDocument.connect(boost::bind(&ViewProviderSketch::slotUndoDocument, this, bp::_1));

View File

@@ -65,7 +65,7 @@ using namespace TechDraw;
App::PropertyFloatConstraint::Constraints DrawViewBalloon::SymbolScaleRange = { Precision::Confusion(),
std::numeric_limits<double>::max(),
(1.0) };
(0.1) };
//===========================================================================
// DrawViewBalloon
@@ -99,22 +99,20 @@ DrawViewBalloon::DrawViewBalloon(void)
EndType.setEnums(ArrowPropEnum::ArrowTypeEnums);
ADD_PROPERTY(EndType,(prefEnd()));
ADD_PROPERTY_TYPE(EndTypeScale,(1.0),"",(App::PropertyType)(App::Prop_None),"EndType shape scale");
EndTypeScale.setConstraints(&SymbolScaleRange);
BubbleShape.setEnums(balloonTypeEnums);
ADD_PROPERTY(BubbleShape,(prefShape()));
ADD_PROPERTY_TYPE(ShapeScale,(1.0),"",(App::PropertyType)(App::Prop_None),"Balloon shape scale");
ShapeScale.setConstraints(&SymbolScaleRange);
ADD_PROPERTY_TYPE(EndTypeScale,(1.0),"",(App::PropertyType)(App::Prop_None),"EndType shape scale");
ShapeScale.setConstraints(&SymbolScaleRange);
ADD_PROPERTY_TYPE(TextWrapLen,(-1),"",(App::PropertyType)(App::Prop_None),"Text wrap length; -1 means no wrap");
ADD_PROPERTY_TYPE(KinkLength,(prefKinkLength()),"",(App::PropertyType)(App::Prop_None),
"Distance from symbol to leader kink");
ADD_PROPERTY_TYPE(LineVisible,(true),"",(App::PropertyType)(App::Prop_None),"Balloon line visible or hidden");
SourceView.setScope(App::LinkScope::Global);
Rotation.setStatus(App::Property::Hidden,true);
Caption.setStatus(App::Property::Hidden,true);
@@ -130,8 +128,12 @@ void DrawViewBalloon::onChanged(const App::Property* prop)
if (!isRestoring()) {
if ( (prop == &EndType) ||
(prop == &BubbleShape) ||
(prop == &ShapeScale) ||
(prop == &Text) ||
(prop == &KinkLength) ) {
(prop == &KinkLength) ||
(prop == &EndTypeScale) ||
(prop == &OriginX) ||
(prop == &OriginY) ) {
requestPaint();
}
}

View File

@@ -59,7 +59,6 @@ public:
App::PropertyDistance OriginY;
App::PropertyFloat TextWrapLen;
App::PropertyDistance KinkLength;
App::PropertyBool LineVisible;
short mustExecute() const override;

View File

@@ -106,8 +106,8 @@ DrawViewDimension::DrawViewDimension(void)
References3D.setScope(App::LinkScope::Global);
ADD_PROPERTY_TYPE(FormatSpec,(getDefaultFormatSpec()) , "Format", App::Prop_Output,"Dimension Format");
ADD_PROPERTY_TYPE(FormatSpecOverTolerance,("%+g") , "Format", App::Prop_Output,"Dimension Overtolerance Format");
ADD_PROPERTY_TYPE(FormatSpecUnderTolerance,("%+g") , "Format", App::Prop_Output,"Dimension Undertolerance Format");
ADD_PROPERTY_TYPE(FormatSpecOverTolerance,(getDefaultFormatSpec(true)) , "Format", App::Prop_Output,"Dimension Overtolerance Format");
ADD_PROPERTY_TYPE(FormatSpecUnderTolerance,(getDefaultFormatSpec(true)) , "Format", App::Prop_Output,"Dimension Undertolerance Format");
ADD_PROPERTY_TYPE(Arbitrary,(false) ,"Format", App::Prop_Output,"Value overridden by user");
ADD_PROPERTY_TYPE(ArbitraryTolerances,(false) ,"Format", App::Prop_Output,"Tolerance values overridden by user");
@@ -1300,7 +1300,7 @@ std::string DrawViewDimension::getPrefix() const
return result;
}
std::string DrawViewDimension::getDefaultFormatSpec() const
std::string DrawViewDimension::getDefaultFormatSpec(bool isToleranceFormat) const
{
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Dimensions");
@@ -1333,6 +1333,10 @@ std::string DrawViewDimension::getDefaultFormatSpec() const
}
if (isToleranceFormat) {
formatSpec.replace(QString::fromUtf8("%"), QString::fromUtf8("%+"));
}
return Base::Tools::toStdString(formatSpec);
}

View File

@@ -171,7 +171,7 @@ protected:
virtual void onChanged(const App::Property* prop) override;
virtual void onDocumentRestored() override;
std::string getPrefix() const;
std::string getDefaultFormatSpec() const;
std::string getDefaultFormatSpec(bool isToleranceFormat = false) const;
virtual pointPair getPointsOneEdge();
virtual pointPair getPointsTwoEdges();
virtual pointPair getPointsTwoVerts();

View File

@@ -766,7 +766,7 @@ void QGIViewBalloon::draw()
balloonLines->setPath(dLinePath);
// This overwrites the previously created QPainterPath with empty one, in case it should be hidden. Should be refactored.
if (!balloon->LineVisible.getValue()) {
if (!vp->LineVisible.getValue()) {
arrow->hide();
balloonLines->setPath(QPainterPath());
}

View File

@@ -75,6 +75,7 @@ ViewProviderBalloon::ViewProviderBalloon()
double weight = lg->getWeight("Thin");
delete lg; //Coverity CID 174670
ADD_PROPERTY_TYPE(LineWidth,(weight),group,(App::PropertyType)(App::Prop_None),"Leader line width");
ADD_PROPERTY_TYPE(LineVisible,(true),group,(App::PropertyType)(App::Prop_None),"Balloon line visible or hidden");
ADD_PROPERTY_TYPE(Color,(PreferencesGui::dimColor()),
group,App::Prop_None,"Color of the balloon");
@@ -148,7 +149,8 @@ void ViewProviderBalloon::onChanged(const App::Property* p)
if ((p == &Font) ||
(p == &Fontsize) ||
(p == &Color) ||
(p == &LineWidth)) {
(p == &LineWidth) ||
(p == &LineVisible)) {
QGIView* qgiv = getQView();
if (qgiv) {
qgiv->updateView(true);

View File

@@ -48,6 +48,7 @@ public:
App::PropertyFont Font;
App::PropertyLength Fontsize;
App::PropertyLength LineWidth;
App::PropertyBool LineVisible;
App::PropertyColor Color;
virtual void attach(App::DocumentObject *);