Merge branch 'master' into bug/4466
This commit is contained in:
@@ -1189,6 +1189,8 @@ bool Document::saveAs(void)
|
||||
escapedstr = Base::Tools::escapeEncodeFilename(escapedstr);
|
||||
Command::doCommand(Command::Doc,"App.getDocument(\"%s\").saveAs(u\"%s\")"
|
||||
, DocName, escapedstr.c_str());
|
||||
// App::Document::saveAs() may modify the passed file name
|
||||
fi.setFile(QString::fromUtf8(d->_pcDocument->FileName.getValue()));
|
||||
setModified(false);
|
||||
getMainWindow()->appendRecentFile(fi.filePath());
|
||||
}
|
||||
|
||||
@@ -337,8 +337,20 @@ TaskDialogPython::~TaskDialogPython()
|
||||
std::vector< QPointer<QWidget> > guarded;
|
||||
guarded.insert(guarded.begin(), Content.begin(), Content.end());
|
||||
Content.clear();
|
||||
|
||||
Base::PyGILStateLocker lock;
|
||||
|
||||
// The widgets stored in the 'form' attribute will be deleted.
|
||||
// Thus, set this attribute to None to make sure that when using
|
||||
// the same dialog instance for a task panel won't segfault.
|
||||
if (this->dlg.hasAttr(std::string("form"))) {
|
||||
this->dlg.setAttr(std::string("form"), Py::None());
|
||||
}
|
||||
this->dlg = Py::None();
|
||||
|
||||
// Assigning None to 'dlg' may destroy some of the stored widgets.
|
||||
// By guarding them with QPointer their pointers will be set to null
|
||||
// so that the destructor of the base class can reliably call 'delete'.
|
||||
Content.insert(Content.begin(), guarded.begin(), guarded.end());
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ public:
|
||||
App::PropertyDistance OriginY;
|
||||
App::PropertyFloat TextWrapLen;
|
||||
App::PropertyDistance KinkLength;
|
||||
App::PropertyBool LineVisible;
|
||||
|
||||
short mustExecute() const override;
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 *);
|
||||
|
||||
Reference in New Issue
Block a user