tibbs / rpms / freecad

Forked from rpms/freecad 5 years ago
Clone
Blob Blame History Raw
From aa0f6b54d497eb810cc2774fa01ac0bb0408541a Mon Sep 17 00:00:00 2001
From: wmayer <wmayer@users.sourceforge.net>
Date: Tue, 10 Apr 2018 10:51:34 +0200
Subject: [PATCH 01/33] fixes #0003424: 'basic_string::_M_construct null not
 valid' when opening a v0.16 project with v0.17

---
 src/App/FeaturePython.cpp             | 32 +++++++++++++++++----------
 src/Gui/ViewProviderPythonFeature.cpp | 16 +++++++++-----
 2 files changed, 30 insertions(+), 18 deletions(-)

diff --git a/src/App/FeaturePython.cpp b/src/App/FeaturePython.cpp
index 0a90b43a066..9d04fecad3c 100644
--- a/src/App/FeaturePython.cpp
+++ b/src/App/FeaturePython.cpp
@@ -108,17 +108,21 @@ void FeaturePythonImp::onBeforeChange(const Property* prop)
                 if (feature.hasAttr("__object__")) {
                     Py::Callable method(feature.getAttr(std::string("onBeforeChange")));
                     Py::Tuple args(1);
-                    std::string prop_name = object->getPropertyName(prop);
-                    args.setItem(0, Py::String(prop_name));
-                    method.apply(args);
+                    const char* prop_name = object->getPropertyName(prop);
+                    if (prop_name) {
+                        args.setItem(0, Py::String(prop_name));
+                        method.apply(args);
+                    }
                 }
                 else {
                     Py::Callable method(feature.getAttr(std::string("onBeforeChange")));
                     Py::Tuple args(2);
                     args.setItem(0, Py::Object(object->getPyObject(), true));
-                    std::string prop_name = object->getPropertyName(prop);
-                    args.setItem(1, Py::String(prop_name));
-                    method.apply(args);
+                    const char* prop_name = object->getPropertyName(prop);
+                    if (prop_name) {
+                        args.setItem(1, Py::String(prop_name));
+                        method.apply(args);
+                    }
                 }
             }
         }
@@ -141,17 +145,21 @@ void FeaturePythonImp::onChanged(const Property* prop)
                 if (feature.hasAttr("__object__")) {
                     Py::Callable method(feature.getAttr(std::string("onChanged")));
                     Py::Tuple args(1);
-                    std::string prop_name = object->getPropertyName(prop);
-                    args.setItem(0, Py::String(prop_name));
-                    method.apply(args);
+                    const char* prop_name = object->getPropertyName(prop);
+                    if (prop_name) {
+                        args.setItem(0, Py::String(prop_name));
+                        method.apply(args);
+                    }
                 }
                 else {
                     Py::Callable method(feature.getAttr(std::string("onChanged")));
                     Py::Tuple args(2);
                     args.setItem(0, Py::Object(object->getPyObject(), true));
-                    std::string prop_name = object->getPropertyName(prop);
-                    args.setItem(1, Py::String(prop_name));
-                    method.apply(args);
+                    const char* prop_name = object->getPropertyName(prop);
+                    if (prop_name) {
+                        args.setItem(1, Py::String(prop_name));
+                        method.apply(args);
+                    }
                 }
             }
         }
diff --git a/src/Gui/ViewProviderPythonFeature.cpp b/src/Gui/ViewProviderPythonFeature.cpp
index 92755706852..2fe1c4fd1af 100644
--- a/src/Gui/ViewProviderPythonFeature.cpp
+++ b/src/Gui/ViewProviderPythonFeature.cpp
@@ -643,17 +643,21 @@ void ViewProviderPythonFeatureImp::onChanged(const App::Property* prop)
                 if (vp.hasAttr("__object__")) {
                     Py::Callable method(vp.getAttr(std::string("onChanged")));
                     Py::Tuple args(1);
-                    std::string prop_name = object->getPropertyName(prop);
-                    args.setItem(0, Py::String(prop_name));
-                    method.apply(args);
+                    const char* prop_name = object->getPropertyName(prop);
+                    if (prop_name) {
+                        args.setItem(0, Py::String(prop_name));
+                        method.apply(args);
+                    }
                 }
                 else {
                     Py::Callable method(vp.getAttr(std::string("onChanged")));
                     Py::Tuple args(2);
                     args.setItem(0, Py::Object(object->getPyObject(), true));
-                    std::string prop_name = object->getPropertyName(prop);
-                    args.setItem(1, Py::String(prop_name));
-                    method.apply(args);
+                    const char* prop_name = object->getPropertyName(prop);
+                    if (prop_name) {
+                        args.setItem(1, Py::String(prop_name));
+                        method.apply(args);
+                    }
                 }
             }
         }

From 5773170777f424c932f2088ef92d5f664b7d3c23 Mon Sep 17 00:00:00 2001
From: WandererFan <wandererfan@gmail.com>
Date: Mon, 5 Mar 2018 10:38:36 -0500
Subject: [PATCH 02/33] Sync TechDraw what's this with Wiki page names

---
 src/Mod/TechDraw/Gui/Command.cpp           | 16 ++++++++--------
 src/Mod/TechDraw/Gui/CommandCreateDims.cpp | 14 +++++++-------
 src/Mod/TechDraw/Gui/CommandDecorate.cpp   |  8 ++++----
 3 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/src/Mod/TechDraw/Gui/Command.cpp b/src/Mod/TechDraw/Gui/Command.cpp
index 02f0103d2f1..bec54ae8fae 100644
--- a/src/Mod/TechDraw/Gui/Command.cpp
+++ b/src/Mod/TechDraw/Gui/Command.cpp
@@ -92,7 +92,7 @@ CmdTechDrawNewPageDef::CmdTechDrawNewPageDef()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Insert new default drawing page");
     sToolTipText    = QT_TR_NOOP("Insert new default drawing page");
-    sWhatsThis      = "TechDraw_NewPageDef";
+    sWhatsThis      = "TechDraw_New_Default";
     sStatusTip      = sToolTipText;
     sPixmap         = "actions/techdraw-new-default";
 }
@@ -162,7 +162,7 @@ CmdTechDrawNewPage::CmdTechDrawNewPage()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Insert new drawing page from template");
     sToolTipText    = QT_TR_NOOP("Insert new drawing page from template");
-    sWhatsThis      = "TechDraw_NewPage";
+    sWhatsThis      = "TechDraw_New_Pick";
     sStatusTip      = sToolTipText;
     sPixmap         = "actions/techdraw-new-pick";
 }
@@ -302,7 +302,7 @@ CmdTechDrawNewViewSection::CmdTechDrawNewViewSection()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Insert section view in drawing");
     sToolTipText    = QT_TR_NOOP("Insert a new Section View of a Part in the active drawing");
-    sWhatsThis      = "TechDraw_NewViewSecton";
+    sWhatsThis      = "TechDraw_NewSection";
     sStatusTip      = sToolTipText;
     sPixmap         = "actions/techdraw-viewsection";
 }
@@ -371,7 +371,7 @@ CmdTechDrawNewViewDetail::CmdTechDrawNewViewDetail()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Insert detail view in drawing");
     sToolTipText    = QT_TR_NOOP("Insert a new Detail View of a Part in the active drawing");
-    sWhatsThis      = "TechDraw_NewViewDetail";
+    sWhatsThis      = "TechDraw_NewProjGroup";
     sStatusTip      = sToolTipText;
     sPixmap         = "actions/techdraw-viewdetail";
 }
@@ -562,7 +562,7 @@ CmdTechDrawAnnotation::CmdTechDrawAnnotation()
     sGroup        = QT_TR_NOOP("TechDraw");
     sMenuText     = QT_TR_NOOP("&Annotation");
     sToolTipText  = QT_TR_NOOP("Inserts an Annotation in the active drawing");
-    sWhatsThis    = "TechDraw_Annotation";
+    sWhatsThis    = "TechDraw_NewAnnotation";
     sStatusTip    = QT_TR_NOOP("Inserts an Annotation in the active drawing");
     sPixmap       = "actions/techdraw-annotation";
 }
@@ -855,7 +855,7 @@ CmdTechDrawDraftView::CmdTechDrawDraftView()
     sGroup        = QT_TR_NOOP("TechDraw");
     sMenuText     = QT_TR_NOOP("Insert a DraftView");
     sToolTipText  = QT_TR_NOOP("Inserts a Draft WB object into the active drawing");
-    sWhatsThis    = "TechDraw_DraftView";
+    sWhatsThis    = "TechDraw_NewDraft";
     sStatusTip    = QT_TR_NOOP("Inserts a Draft WB object into the active drawing");
     sPixmap       = "actions/techdraw-draft-view";
 }
@@ -908,7 +908,7 @@ CmdTechDrawArchView::CmdTechDrawArchView()
     sGroup        = QT_TR_NOOP("TechDraw");
     sMenuText     = QT_TR_NOOP("Insert an ArchView");
     sToolTipText  = QT_TR_NOOP("Inserts a view of an Arch Section Plane into the active drawing");
-    sWhatsThis    = "TechDraw_ArchView";
+    sWhatsThis    = "TechDraw_NewArch";
     sStatusTip    = QT_TR_NOOP("Inserts a view of an Arch Section Plane into the active drawing");
     sPixmap       = "actions/techdraw-arch-view";
 }
@@ -1024,7 +1024,7 @@ CmdTechDrawExportPage::CmdTechDrawExportPage()
     sGroup        = QT_TR_NOOP("File");
     sMenuText     = QT_TR_NOOP("&Export page...");
     sToolTipText  = QT_TR_NOOP("Export a page to an SVG file");
-    sWhatsThis    = "TechDraw_ExportPage";
+    sWhatsThis    = "TechDraw_SaveSVG";
     sStatusTip    = QT_TR_NOOP("Export a page to an SVG file");
     sPixmap       = "actions/techdraw-saveSVG";
 }
diff --git a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp
index f5324cc3bb2..5fa0b0bf94b 100644
--- a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp
+++ b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp
@@ -236,7 +236,7 @@ CmdTechDrawNewRadiusDimension::CmdTechDrawNewRadiusDimension()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Insert a new radius dimension into the drawing");
     sToolTipText    = QT_TR_NOOP("Insert a new radius dimension feature for the selected view");
-    sWhatsThis      = "TechDraw_NewRadiusDimension";
+    sWhatsThis      = "TechDraw_Dimension_Radius";
     sStatusTip      = sToolTipText;
     sPixmap         = "TechDraw_Dimension_Radius";
 }
@@ -323,7 +323,7 @@ CmdTechDrawNewDiameterDimension::CmdTechDrawNewDiameterDimension()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Insert a new diameter dimension into the drawing");
     sToolTipText    = QT_TR_NOOP("Insert a new diameter dimension feature for the selected view");
-    sWhatsThis      = "TechDraw_NewDiameterDimension";
+    sWhatsThis      = "TechDraw_Dimension_Diameter";
     sStatusTip      = sToolTipText;
     sPixmap         = "TechDraw_Dimension_Diameter";
 }
@@ -410,7 +410,7 @@ CmdTechDrawNewLengthDimension::CmdTechDrawNewLengthDimension()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Insert a new length dimension into the drawing");
     sToolTipText    = QT_TR_NOOP("Insert a new length dimension");
-    sWhatsThis      = "TechDraw_NewLengthDimension";
+    sWhatsThis      = "TechDraw_Dimension_Length";
     sStatusTip      = sToolTipText;
     sPixmap         = "TechDraw_Dimension_Length";
 }
@@ -518,7 +518,7 @@ CmdTechDrawNewDistanceXDimension::CmdTechDrawNewDistanceXDimension()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Insert a new horizontal dimension into the drawing");
     sToolTipText    = QT_TR_NOOP("Insert a new horizontal-distance dimension");
-    sWhatsThis      = "TechDraw_NewDistanceXDimension";
+    sWhatsThis      = "TechDraw_Dimension_Horizontal";
     sStatusTip      = sToolTipText;
     sPixmap         = "TechDraw_Dimension_Horizontal";
 }
@@ -626,7 +626,7 @@ CmdTechDrawNewDistanceYDimension::CmdTechDrawNewDistanceYDimension()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Insert a new vertical dimension into the drawing");
     sToolTipText    = QT_TR_NOOP("Insert a new vertical distance dimension");
-    sWhatsThis      = "TechDraw_NewDistanceYDimension";
+    sWhatsThis      = "TechDraw_Dimension_Vertical";
     sStatusTip      = sToolTipText;
     sPixmap         = "TechDraw_Dimension_Vertical";
 }
@@ -733,7 +733,7 @@ CmdTechDrawNewAngleDimension::CmdTechDrawNewAngleDimension()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Insert a new angle dimension into the drawing");
     sToolTipText    = QT_TR_NOOP("Insert a new angle dimension");
-    sWhatsThis      = "TechDraw_NewAngleDimension";
+    sWhatsThis      = "TechDraw_Dimension_Angle";
     sStatusTip      = sToolTipText;
     sPixmap         = "TechDraw_Dimension_Angle";
 }
@@ -822,7 +822,7 @@ CmdTechDrawLinkDimension::CmdTechDrawLinkDimension()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Link a dimension to 3D geometry");
     sToolTipText    = QT_TR_NOOP("Link a dimension to 3D geometry");
-    sWhatsThis      = "TechDraw_LinkDimension";
+    sWhatsThis      = "TechDraw_Dimension_Link";
     sStatusTip      = sToolTipText;
     sPixmap         = "TechDraw_Dimension_Link";
 }
diff --git a/src/Mod/TechDraw/Gui/CommandDecorate.cpp b/src/Mod/TechDraw/Gui/CommandDecorate.cpp
index 9edf97d0058..b6cb5dab074 100644
--- a/src/Mod/TechDraw/Gui/CommandDecorate.cpp
+++ b/src/Mod/TechDraw/Gui/CommandDecorate.cpp
@@ -80,7 +80,7 @@ CmdTechDrawNewHatch::CmdTechDrawNewHatch()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Hatch a Face using image file");
     sToolTipText    = QT_TR_NOOP("Hatch a Face using image file");
-    sWhatsThis      = "TechDraw_NewHatch";
+    sWhatsThis      = "TechDraw_Hatch";
     sStatusTip      = sToolTipText;
     sPixmap         = "actions/techdraw-hatch";
 }
@@ -142,7 +142,7 @@ CmdTechDrawNewGeomHatch::CmdTechDrawNewGeomHatch()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Apply geometric hatch to a Face");
     sToolTipText    = QT_TR_NOOP("Apply geometric hatch to a Face");
-    sWhatsThis      = "TechDraw_NewGeomHatch";
+    sWhatsThis      = "TechDraw_GeomHatch";
     sStatusTip      = sToolTipText;
     sPixmap         = "actions/techdraw-geomhatch";
 }
@@ -264,7 +264,7 @@ CmdTechDrawToggleFrame::CmdTechDrawToggleFrame()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Turn View Frames on or off");
     sToolTipText    = QT_TR_NOOP("Turn View Frames on or off");
-    sWhatsThis      = "TechDraw_ToggleFrame";
+    sWhatsThis      = "TechDraw_Toggle";
     sStatusTip      = sToolTipText;
     sPixmap         = "actions/techdraw-toggleframe";
 }
@@ -311,7 +311,7 @@ CmdTechDrawRedrawPage::CmdTechDrawRedrawPage()
     sGroup          = QT_TR_NOOP("TechDraw");
     sMenuText       = QT_TR_NOOP("Redraw a page");
     sToolTipText    = QT_TR_NOOP("Redraw a page");
-    sWhatsThis      = "TechDraw_RedrawPage";
+    sWhatsThis      = "TechDraw_Redraw";
     sStatusTip      = sToolTipText;
     sPixmap         = "TechDraw_Tree_Page_Sync";
 }

From 6a25fe9ce5c88280360d71a09cda19cd93010728 Mon Sep 17 00:00:00 2001
From: DeepSOIC <vv.titov@gmail.com>
Date: Wed, 11 Apr 2018 18:21:23 +0300
Subject: [PATCH 03/33] PartDesign: fix #2758 Datum Point persistence, again

---
 src/Mod/PartDesign/App/DatumPoint.cpp | 8 +++++---
 src/Mod/PartDesign/App/DatumPoint.h   | 4 +++-
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/Mod/PartDesign/App/DatumPoint.cpp b/src/Mod/PartDesign/App/DatumPoint.cpp
index 297d562769d..5a65f09a645 100644
--- a/src/Mod/PartDesign/App/DatumPoint.cpp
+++ b/src/Mod/PartDesign/App/DatumPoint.cpp
@@ -99,12 +99,12 @@ void Point::onChanged(const App::Property* prop)
     Superclass::onChanged(prop);
 }
 
-void Point::Restore(Base::XMLReader& r)
+void Point::onDocumentRestored()
 {
-    Superclass::Restore(r);
     //fix for #0002758 Datum point moves to (0,0,0) when reopening the file.
     //recreate shape, as the restored one has old Placement burned into it.
     this->makeShape();
+    Superclass::onDocumentRestored();
 }
 
 void Point::makeShape()
@@ -114,7 +114,9 @@ void Point::makeShape()
     BRepBuilderAPI_MakeVertex builder(gp_Pnt(0,0,0));
     if (!builder.IsDone())
         return;
-    Shape.setValue(builder.Shape());
+    Part::TopoShape tshape(builder.Shape());
+    tshape.setPlacement(this->Placement.getValue());
+    Shape.setValue(tshape);
 }
 
 Base::Vector3d Point::getPoint()
diff --git a/src/Mod/PartDesign/App/DatumPoint.h b/src/Mod/PartDesign/App/DatumPoint.h
index 19dfdbeb41c..e00cf6434e2 100644
--- a/src/Mod/PartDesign/App/DatumPoint.h
+++ b/src/Mod/PartDesign/App/DatumPoint.h
@@ -50,9 +50,11 @@ class PartDesignExport Point : public Part::Datum
 
 protected:
     virtual void onChanged(const App::Property* prop);
-    virtual void Restore(Base::XMLReader& r);
+    virtual void onDocumentRestored() override;
+
 private:
     void makeShape();
+
 };
 
 } //namespace PartDesign

From 551c504649450c77445dd62d3ae134620ca00370 Mon Sep 17 00:00:00 2001
From: wmayer <wmayer@users.sourceforge.net>
Date: Sat, 14 Apr 2018 18:45:37 +0200
Subject: [PATCH 04/33] initialize member to fix possible crash

---
 src/Mod/Mesh/App/MeshPy.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Mod/Mesh/App/MeshPy.xml b/src/Mod/Mesh/App/MeshPy.xml
index c71944df602..76bc4618a3f 100644
--- a/src/Mod/Mesh/App/MeshPy.xml
+++ b/src/Mod/Mesh/App/MeshPy.xml
@@ -520,7 +520,7 @@ for p in mesh.Facets:
 		</Attribute>
 		<ClassDeclarations>private:
     friend class PropertyMeshKernel;
-    class PropertyMeshKernel* parentProperty;
+    class PropertyMeshKernel* parentProperty = nullptr;
 		</ClassDeclarations>
 	</PythonExport>
 </GenerateModel>

From acdde5b2467fcc1d64fa1b713fb386abf468bbb2 Mon Sep 17 00:00:00 2001
From: Yorik van Havre <yorik@uncreated.net>
Date: Tue, 17 Apr 2018 11:18:23 -0300
Subject: [PATCH 05/33] Arch: Fixed leftover encoding bug (backported to 0.17)

---
 src/Mod/Arch/ArchStructure.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/Mod/Arch/ArchStructure.py b/src/Mod/Arch/ArchStructure.py
index 1a442dff2a3..a0ec64d5647 100644
--- a/src/Mod/Arch/ArchStructure.py
+++ b/src/Mod/Arch/ArchStructure.py
@@ -152,7 +152,7 @@ def Activated(self):
             st = Draft.getObjectsOfType(sel,"Structure")
             ax = Draft.getObjectsOfType(sel,"Axis")
             if ax:
-                FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Structural System")))
+                FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Structural System"))
                 FreeCADGui.addModule("Arch")
                 if st:
                     FreeCADGui.doCommand("obj = Arch.makeStructuralSystem(" + ArchCommands.getStringList(st) + "," + ArchCommands.getStringList(ax) + ")")
@@ -164,7 +164,7 @@ def Activated(self):
                 FreeCAD.ActiveDocument.recompute()
                 return
             elif not(ax) and not(st):
-                FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Structure")))
+                FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Structure"))
                 FreeCADGui.addModule("Arch")
                 for obj in sel:
                     FreeCADGui.doCommand("obj = Arch.makeStructure(FreeCAD.ActiveDocument." + obj.Name + ")")
@@ -194,7 +194,7 @@ def getPoint(self,point=None,obj=None):
         self.tracker.finalize()
         if point == None:
             return
-        FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Structure")))
+        FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Structure"))
         FreeCADGui.addModule("Arch")
         if self.Profile is not None:
             if "Precast" in self.Profile:

From e17b340949b75a226cc7d89989b0aa238ccfc75f Mon Sep 17 00:00:00 2001
From: Peter Lama <peterldev94@gmail.com>
Date: Mon, 16 Apr 2018 14:55:03 -0700
Subject: [PATCH 06/33] Fix #3426: Hierarchical step export not working with
 occt 7.2

---
 src/Mod/Import/Gui/AppImportGuiPy.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/Mod/Import/Gui/AppImportGuiPy.cpp b/src/Mod/Import/Gui/AppImportGuiPy.cpp
index b83092d9ed3..6c20eb94cc4 100644
--- a/src/Mod/Import/Gui/AppImportGuiPy.cpp
+++ b/src/Mod/Import/Gui/AppImportGuiPy.cpp
@@ -541,7 +541,12 @@ class Module : public Py::ExtensionModule<Module>
             // the App Code.
             std::vector< std::vector<App::Color> > Colors;
             get_parts_colors(hierarchical_part,FreeLabels,part_id,Colors);
-            ocaf.reallocateFreeShape(hierarchical_part,FreeLabels,part_id,Colors);
+            ocaf.reallocateFreeShape(hierarchical_part,FreeLabels,part_id,Colors);
+
+#if OCC_VERSION_HEX >= 0x070200
+            // Update is not performed automatically anymore: https://tracker.dev.opencascade.org/view.php?id=28055
+            XCAFDoc_DocumentTool::ShapeTool(hDoc->Main())->UpdateAssemblies();
+#endif
 
             Base::FileInfo file(Utf8Name.c_str());
             if (file.hasExtension("stp") || file.hasExtension("step")) {

From f522116a7051fa20f44ada46151f87ec1c085caf Mon Sep 17 00:00:00 2001
From: Eivind Kvedalen <eivind@kvedalen.name>
Date: Fri, 20 Apr 2018 19:49:13 +0200
Subject: [PATCH 07/33] Expressions: Fixed issue #3432; aggregate functions
 sometimes ignore some of their arguments.

Also updated regression tests in Spreadsheet module.
---
 src/App/Expression.cpp                 |  5 +----
 src/Mod/Spreadsheet/TestSpreadsheet.py | 10 ++++++++++
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/src/App/Expression.cpp b/src/App/Expression.cpp
index 6f6fb6cbabc..471c0742878 100644
--- a/src/App/Expression.cpp
+++ b/src/App/Expression.cpp
@@ -897,16 +897,13 @@ Expression * FunctionExpression::evalAggregate() const
                     throw Exception("Invalid property type for aggregate");
             } while (range.next());
         }
-        else if (args[i]->isDerivedFrom(App::VariableExpression::getClassTypeId())) {
+        else {
             std::unique_ptr<Expression> e(args[i]->eval());
             NumberExpression * n(freecad_dynamic_cast<NumberExpression>(e.get()));
 
             if (n)
                 c->collect(n->getQuantity());
         }
-        else if (args[i]->isDerivedFrom(App::NumberExpression::getClassTypeId())) {
-            c->collect(static_cast<NumberExpression*>(args[i])->getQuantity());
-        }
     }
 
     return new NumberExpression(owner, c->getQuantity());
diff --git a/src/Mod/Spreadsheet/TestSpreadsheet.py b/src/Mod/Spreadsheet/TestSpreadsheet.py
index 56a0acf92e5..19ed6be8d4b 100644
--- a/src/Mod/Spreadsheet/TestSpreadsheet.py
+++ b/src/Mod/Spreadsheet/TestSpreadsheet.py
@@ -851,6 +851,16 @@ def testIssue3363(self):
         self.assertEqual(sheet.getContents('B1'), '=A1 == 1 ? 11 : (A1 == 2 ? 12 : 13)')
         self.assertEqual(sheet.getContents('C1'), '=A1 == 1 ? (A1 == 2 ? 12 : 13) : 11')
 
+    def testIssue3432(self):
+        """ Regression test for issue 3432; numbers with units are ignored from aggregates"""
+        sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
+        sheet.set('A1', '1mm')
+        sheet.set('B1', '2mm')
+        sheet.set('C1', '=max(A1:B1;3mm)')
+        self.doc.recompute()
+        self.assertEqual(sheet.get('C1'), Units.Quantity('3 mm'))
+
+
     def tearDown(self):
         #closing doc
         FreeCAD.closeDocument(self.doc.Name)

From e540e1bba3de415f0a135efda441af9ae99c4141 Mon Sep 17 00:00:00 2001
From: Abdullah Tahiri <abdullah.tahiri.yo@gmail.com>
Date: Sun, 22 Apr 2018 05:59:51 +0200
Subject: [PATCH 08/33] Sketcher: fix menu periodic bspline call

---
 src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
index 83c6c6007c2..3d970960342 100644
--- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
+++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
@@ -4867,7 +4867,7 @@ CmdSketcherCreatePeriodicBSpline::CmdSketcherCreatePeriodicBSpline()
 void CmdSketcherCreatePeriodicBSpline::activated(int iMsg)
 {
     Q_UNUSED(iMsg);
-    ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerEllipse(1) );
+    ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerBSpline(1) );
 }
 
 bool CmdSketcherCreatePeriodicBSpline::isActive(void)

From d436c4549823ce636381b1626d8b6a6f68ef0776 Mon Sep 17 00:00:00 2001
From: wandererfan <wandererfan@gmail.com>
Date: Fri, 20 Apr 2018 11:18:45 -0400
Subject: [PATCH 09/33] Fix add ArchSection w/ multiple Pages

---
 src/Mod/TechDraw/Gui/Command.cpp | 36 +++++++++++++++++++++++++-------
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/src/Mod/TechDraw/Gui/Command.cpp b/src/Mod/TechDraw/Gui/Command.cpp
index bec54ae8fae..de4f5ff8e03 100644
--- a/src/Mod/TechDraw/Gui/Command.cpp
+++ b/src/Mod/TechDraw/Gui/Command.cpp
@@ -78,6 +78,16 @@
 using namespace TechDrawGui;
 using namespace std;
 
+bool isArchSection(App::DocumentObject* obj)
+{
+    bool result = true;
+    App::Property* prop1 = obj->getPropertyByName("Objects");
+    App::Property* prop2 = obj->getPropertyByName("OnlySolids");
+    if ( (!prop1) || (!prop2) ) {
+        result = false;
+    }
+    return result;
+}
 
 //===========================================================================
 // TechDraw_NewPageDef (default template)
@@ -869,6 +879,7 @@ void CmdTechDrawDraftView::activated(int iMsg)
     }
 
 //TODO: shouldn't this be checking for a Draft object only?
+//      there is no obvious way of check for a Draft object.  Could be App::FeaturePython, Part::Part2DObject, ???
     std::vector<App::DocumentObject*> objects = getSelection().getObjectsOfType(App::DocumentObject::getClassTypeId());
     if (objects.empty()) {
         QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
@@ -894,7 +905,6 @@ bool CmdTechDrawDraftView::isActive(void)
     return DrawGuiUtil::needPage(this);
 }
 
-//TODO: shouldn't this be checking for an Arch object only?
 //===========================================================================
 // TechDraw_ArchView
 //===========================================================================
@@ -922,23 +932,33 @@ void CmdTechDrawArchView::activated(int iMsg)
     }
 
     std::vector<App::DocumentObject*> objects = getSelection().getObjectsOfType(App::DocumentObject::getClassTypeId());
-    if (objects.size() != 1) {
+    if (objects.empty()) {
         QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
-            QObject::tr("Select exactly one Arch Section Plane object."));
+            QObject::tr("Select at least one object."));
         return;
     }
-    App::Property* prop1 = objects[0]->getPropertyByName("Objects");
-    App::Property* prop2 = objects[0]->getPropertyByName("OnlySolids");
-    if ( (!prop1) || (!prop2) ) {
+    int ifound = 0;
+    bool found = false;
+    for (auto& obj: objects) {
+        if (isArchSection(obj)) {
+            found = true;
+            break;
+        }
+        ifound++;
+    }
+    App::DocumentObject* archObj;
+    if (found) {
+        archObj = objects[ifound];
+    } else {
         QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
-            QObject::tr("The selected object is not an Arch Section Plane."));
+            QObject::tr("There is no Arch Section Plane in selection."));
         return;
     }
 
     std::string PageName = page->getNameInDocument();
 
     std::string FeatName = getUniqueObjectName("ArchView");
-    std::string SourceName = objects[0]->getNameInDocument();
+    std::string SourceName = archObj->getNameInDocument();
     openCommand("Create ArchView");
     doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewArch','%s')",FeatName.c_str());
     doCommand(Doc,"App.activeDocument().%s.Source = App.activeDocument().%s",FeatName.c_str(),SourceName.c_str());

From 1a8b868018f45ea486c0023fdbfeb06febc1fb89 Mon Sep 17 00:00:00 2001
From: Peter Lama <peterldev94@gmail.com>
Date: Fri, 20 Apr 2018 11:07:53 -0700
Subject: [PATCH 10/33] Fix finding boost python >= 1.67

Boost >= 1.67 requires a version suffix (on macOS at least)
---
 src/Mod/Path/libarea/CMakeLists.txt | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/src/Mod/Path/libarea/CMakeLists.txt b/src/Mod/Path/libarea/CMakeLists.txt
index ef95c29d37d..087c911ddda 100644
--- a/src/Mod/Path/libarea/CMakeLists.txt
+++ b/src/Mod/Path/libarea/CMakeLists.txt
@@ -16,13 +16,17 @@ OPTION(USE_BOOST_PYTHON "use BOOST_PYTHON, otherwise use PYBIND11" ON)
 
 if(USE_BOOST_PYTHON)
     if(NOT FREECAD_LIBPACK_USE OR FREECAD_LIBPACK_CHECKFILE_CLBUNDLER)
-        if(NOT PYTHON_VERSION_MAJOR LESS 3)
-            find_package( Boost COMPONENTS python3)
-            if (NOT Boost_PYTHON3_FOUND)
+        # boost-python >= 1.67 on some platforms has suffix
+        set(BOOST_PY_SUFFIX ${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR})
+
+        find_package( Boost COMPONENTS python${BOOST_PY_SUFFIX} )
+        if (NOT Boost_PYTHON${BOOST_PY_SUFFIX}_FOUND)
+            # try just the major version
+            find_package( Boost COMPONENTS python${PYTHON_VERSION_MAJOR} )
+            if (NOT Boost_PYTHON${PYTHON_VERSION_MAJOR}_FOUND)
+                # unversioned
                 find_package( Boost COMPONENTS python REQUIRED)
             endif()
-        else()
-            find_package( Boost COMPONENTS python REQUIRED)  # find BOOST and boost-python
         endif()
 
         if(Boost_FOUND)

From f0e4c419c20de298ad521dc9e643a3e0ba83457b Mon Sep 17 00:00:00 2001
From: Markus Lampert <markus@bibi.ca>
Date: Sun, 29 Apr 2018 21:26:35 -0700
Subject: [PATCH 11/33] Changed grbl feed rate output to mm/min.

---
 src/Mod/Path/PathScripts/post/grbl_post.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Mod/Path/PathScripts/post/grbl_post.py b/src/Mod/Path/PathScripts/post/grbl_post.py
index 536c2cf5493..9ad09924339 100644
--- a/src/Mod/Path/PathScripts/post/grbl_post.py
+++ b/src/Mod/Path/PathScripts/post/grbl_post.py
@@ -261,7 +261,7 @@ def parse(pathobj):
                 if param in c.Parameters:
                     if param == 'F':
                         if command not in RAPID_MOVES:
-                            outstring.append(param + format(c.Parameters['F'], '.2f'))
+                            outstring.append(param + format(c.Parameters['F'] * 60, '.2f'))
                     elif param == 'T':
                         outstring.append(param + str(c.Parameters['T']))
                     else:

From 3bb5ff4e70c0c526f2d9dd69b1004155b2f527f2 Mon Sep 17 00:00:00 2001
From: wmayer <wmayer@users.sourceforge.net>
Date: Tue, 8 May 2018 15:25:00 +0200
Subject: [PATCH 12/33] 0003461: FreeCAD crashes when changing language setting

---
 src/Gui/DlgGeneralImp.cpp | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/src/Gui/DlgGeneralImp.cpp b/src/Gui/DlgGeneralImp.cpp
index 0ec847af0dd..4126a8046b5 100644
--- a/src/Gui/DlgGeneralImp.cpp
+++ b/src/Gui/DlgGeneralImp.cpp
@@ -130,14 +130,16 @@ void DlgGeneralImp::saveSettings()
     PythonWordWrap->onSave();
   
     QWidget* pc = DockWindowManager::instance()->getDockWindow("Python console");
-    PythonConsole *pcPython = static_cast<PythonConsole*>(pc);
-    bool pythonWordWrap = App::GetApplication().GetUserParameter().
-        GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("General")->GetBool("PythonWordWrap", true);
-
-    if (pythonWordWrap) {
-      pcPython->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
-    } else {
-      pcPython->setWordWrapMode(QTextOption::NoWrap);
+    PythonConsole *pcPython = qobject_cast<PythonConsole*>(pc);
+    if (pcPython) {
+        bool pythonWordWrap = App::GetApplication().GetUserParameter().
+            GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("General")->GetBool("PythonWordWrap", true);
+
+        if (pythonWordWrap) {
+            pcPython->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+        } else {
+            pcPython->setWordWrapMode(QTextOption::NoWrap);
+        }
     }
 
     // set new user defined style

From 84d61285966f0753251d62033963f33aa04e8ea9 Mon Sep 17 00:00:00 2001
From: Yorik van Havre <yorik@uncreated.net>
Date: Mon, 21 May 2018 12:11:46 -0300
Subject: [PATCH 13/33] Fixed wrong encoding in App.openTransaction

---
 src/App/DocumentPyImp.cpp | 2 +-
 src/Mod/Arch/ArchWall.py  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/App/DocumentPyImp.cpp b/src/App/DocumentPyImp.cpp
index bfcbf04b71e..cd27cd49009 100644
--- a/src/App/DocumentPyImp.cpp
+++ b/src/App/DocumentPyImp.cpp
@@ -341,7 +341,7 @@ PyObject*  DocumentPy::openTransaction(PyObject *args)
     }
 #else
     else if (PyUnicode_Check(value)) {
-        PyObject* unicode = PyUnicode_AsLatin1String(value);
+        PyObject* unicode = PyUnicode_AsUTF8String(value);
         cmd = PyString_AsString(unicode);
         Py_DECREF(unicode);
     }
diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py
index 9f7eefca355..82ea0226a22 100644
--- a/src/Mod/Arch/ArchWall.py
+++ b/src/Mod/Arch/ArchWall.py
@@ -271,7 +271,7 @@ def getPoint(self,point=None,obj=None):
                 self.Activated()
 
     def addDefault(self,l):
-        FreeCADGui.doCommand('base=FreeCAD.ActiveDocument.addObject("Sketcher::SketchObject","'+translate('Arch','WallTrace')+'")')
+        FreeCADGui.doCommand('base=FreeCAD.ActiveDocument.addObject("Sketcher::SketchObject","WallTrace")')
         FreeCADGui.doCommand('base.Placement = FreeCAD.DraftWorkingPlane.getPlacement()')
         FreeCADGui.doCommand('base.addGeometry(trace)')
         FreeCADGui.doCommand('wall = Arch.makeWall(base,width='+str(self.Width)+',height='+str(self.Height)+',align="'+str(self.Align)+'")')

From b9160032150f3bcaf0976e3f52c9e1d4f900052c Mon Sep 17 00:00:00 2001
From: Yorik van Havre <yorik@uncreated.net>
Date: Mon, 18 Jun 2018 22:14:05 -0300
Subject: [PATCH 14/33] Arch: Fixed export of included windows to IFC

---
 src/Mod/Draft/Draft.py | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py
index ce92eb43e42..461e52c64db 100644
--- a/src/Mod/Draft/Draft.py
+++ b/src/Mod/Draft/Draft.py
@@ -356,6 +356,15 @@ def getWindows(obj):
         if getType(obj) in ["Wall","Structure"]:
             for o in obj.OutList:
                 l.extend(getWindows(o))
+            for i in obj.InList:
+                if (getType(i) in ["Window"]) or isClone(obj,"Window"):
+                    if hasattr(i,"Hosts"):
+                        if obj in i.Hosts:
+                            l.append(i)
+                elif (getType(i) in ["Rebar"]) or isClone(obj,"Rebar"):
+                    if hasattr(i,"Host"):
+                        if obj == i.Host:
+                            l.append(i)
         elif (getType(obj) in ["Window","Rebar"]) or isClone(obj,["Window","Rebar"]):
             l.append(obj)
         return l

From 8b68af0bac83b90ec769d457f3792a98a51a18b1 Mon Sep 17 00:00:00 2001
From: Yorik van Havre <yorik@uncreated.net>
Date: Tue, 26 Jun 2018 15:17:22 -0300
Subject: [PATCH 15/33] Arch: Fixed IFC export of window openings

---
 src/Mod/Arch/importIFC.py | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py
index 2563c133d45..0b20d4a5fcb 100644
--- a/src/Mod/Arch/importIFC.py
+++ b/src/Mod/Arch/importIFC.py
@@ -1195,8 +1195,15 @@ def export(exportList,filename):
                 ifcfile.createIfcRelAggregates(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'Addition','',product,[prod2])
 
         # subtractions
+        guests = []
+        for o in obj.InList:
+            if hasattr(o,"Hosts"):
+                for co in o.Hosts:
+                    if co == obj:
+                        if not o in guests:
+                            guests.append(o)
         if hasattr(obj,"Subtractions") and (shapetype == "extrusion"):
-            for o in obj.Subtractions:
+            for o in obj.Subtractions + guests:
                 r2,p2,c2 = getRepresentation(ifcfile,context,o,forcebrep=True,subtraction=True)
                 if DEBUG: print("      subtracting ",c2," : ",o.Label)
                 prod2 = ifcfile.createIfcOpeningElement(ifcopenshell.guid.compress(uuid.uuid1().hex),history,o.Label.encode("utf8"),None,None,p2,r2,None)

From 1889f1f86293958d4ff40bca1172f21bd1485702 Mon Sep 17 00:00:00 2001
From: wandererfan <wandererfan@gmail.com>
Date: Wed, 4 Apr 2018 18:52:26 -0400
Subject: [PATCH 16/33] Fix #3401 warning on multiple solid

- PartDesign only uses the first result shape
  of an operation and discards the rest without
  warning.

- this also fixes #1707
---
 src/Mod/PartDesign/App/Feature.cpp            | 15 +++++++++++++++
 src/Mod/PartDesign/App/Feature.h              |  1 +
 src/Mod/PartDesign/App/FeatureBoolean.cpp     |  5 +++++
 src/Mod/PartDesign/App/FeatureChamfer.cpp     |  4 ++++
 src/Mod/PartDesign/App/FeatureDraft.cpp       |  5 +++++
 src/Mod/PartDesign/App/FeatureFillet.cpp      |  5 +++++
 src/Mod/PartDesign/App/FeatureGroove.cpp      |  5 +++++
 src/Mod/PartDesign/App/FeatureHole.cpp        |  6 ++++++
 src/Mod/PartDesign/App/FeatureLoft.cpp        |  8 ++++++++
 src/Mod/PartDesign/App/FeaturePad.cpp         | 13 ++++++++++++-
 src/Mod/PartDesign/App/FeaturePipe.cpp        | 10 ++++++++++
 src/Mod/PartDesign/App/FeaturePocket.cpp      | 13 +++++++++++++
 src/Mod/PartDesign/App/FeaturePrimitive.cpp   | 12 +++++++++++-
 src/Mod/PartDesign/App/FeatureTransformed.cpp |  6 ++++++
 14 files changed, 106 insertions(+), 2 deletions(-)

diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp
index 7f19a9516dc..6a58a3915fd 100644
--- a/src/Mod/PartDesign/App/Feature.cpp
+++ b/src/Mod/PartDesign/App/Feature.cpp
@@ -79,6 +79,21 @@ TopoDS_Shape Feature::getSolid(const TopoDS_Shape& shape)
     return TopoDS_Shape();
 }
 
+int Feature::countSolids(const TopoDS_Shape& shape, TopAbs_ShapeEnum type)
+{
+    int result = 0;
+    if (shape.IsNull())
+        return result;
+    TopExp_Explorer xp;
+    xp.Init(shape,type);
+    for (; xp.More(); xp.Next()) {
+        result++;
+    }
+    return result;
+}
+
+
+
 const gp_Pnt Feature::getPointFromFace(const TopoDS_Face& f)
 {
     if (!f.Infinite()) {
diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h
index 0689d849e47..ce393fbb2b2 100644
--- a/src/Mod/PartDesign/App/Feature.h
+++ b/src/Mod/PartDesign/App/Feature.h
@@ -83,6 +83,7 @@ class PartDesignExport Feature : public Part::Feature
      * Get a solid of the given shape. If no solid is found an exception is raised.
      */
     static TopoDS_Shape getSolid(const TopoDS_Shape&);    
+    static int countSolids(const TopoDS_Shape&, TopAbs_ShapeEnum type = TopAbs_SOLID );    
 
     /// Grab any point from the given face
     static const gp_Pnt getPointFromFace(const TopoDS_Face& f);    
diff --git a/src/Mod/PartDesign/App/FeatureBoolean.cpp b/src/Mod/PartDesign/App/FeatureBoolean.cpp
index af3eb0dda65..a1f7fbbea84 100644
--- a/src/Mod/PartDesign/App/FeatureBoolean.cpp
+++ b/src/Mod/PartDesign/App/FeatureBoolean.cpp
@@ -141,6 +141,11 @@ App::DocumentObjectExecReturn *Boolean::execute(void)
 
         result = boolOp; // Use result of this operation for fuse/cut of next body
     }
+
+    int solidCount = countSolids(result);
+    if (solidCount > 1) {
+        return new App::DocumentObjectExecReturn("Boolean: Result has multiple solids. Check parameters.");
+    }
 
     this->Shape.setValue(getSolid(result));
     return App::DocumentObject::StdReturn;
diff --git a/src/Mod/PartDesign/App/FeatureChamfer.cpp b/src/Mod/PartDesign/App/FeatureChamfer.cpp
index 10bd843fef9..8f39b18b050 100644
--- a/src/Mod/PartDesign/App/FeatureChamfer.cpp
+++ b/src/Mod/PartDesign/App/FeatureChamfer.cpp
@@ -125,6 +125,10 @@ App::DocumentObjectExecReturn *Chamfer::execute(void)
                 return new App::DocumentObjectExecReturn("Resulting shape is invalid");
             }
         }
+        int solidCount = countSolids(shape);
+        if (solidCount > 1) {
+            return new App::DocumentObjectExecReturn("Chamfer: Result has multiple solids. Check parameters.");
+        }
 
         this->Shape.setValue(getSolid(shape));
         return App::DocumentObject::StdReturn;
diff --git a/src/Mod/PartDesign/App/FeatureDraft.cpp b/src/Mod/PartDesign/App/FeatureDraft.cpp
index 9397a3e763d..e94a230b37f 100644
--- a/src/Mod/PartDesign/App/FeatureDraft.cpp
+++ b/src/Mod/PartDesign/App/FeatureDraft.cpp
@@ -304,6 +304,11 @@ App::DocumentObjectExecReturn *Draft::execute(void)
         if (shape.IsNull())
             return new App::DocumentObjectExecReturn("Resulting shape is null");
 
+        int solidCount = countSolids(shape);
+        if (solidCount > 1) {
+            return new App::DocumentObjectExecReturn("Fuse: Result has multiple solids. Check parameters.");
+        }
+
         this->Shape.setValue(getSolid(shape));
         return App::DocumentObject::StdReturn;
     }
diff --git a/src/Mod/PartDesign/App/FeatureFillet.cpp b/src/Mod/PartDesign/App/FeatureFillet.cpp
index ad4f79e96c9..66c01e02bf4 100644
--- a/src/Mod/PartDesign/App/FeatureFillet.cpp
+++ b/src/Mod/PartDesign/App/FeatureFillet.cpp
@@ -118,6 +118,11 @@ App::DocumentObjectExecReturn *Fillet::execute(void)
             }
         }
 
+        int solidCount = countSolids(shape);
+        if (solidCount > 1) {
+            return new App::DocumentObjectExecReturn("Fillet: Result has multiple solids. Check parameters.");
+        }
+
         this->Shape.setValue(getSolid(shape));
         return App::DocumentObject::StdReturn;
     }
diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp
index b2af6fc91af..c27613aa801 100644
--- a/src/Mod/PartDesign/App/FeatureGroove.cpp
+++ b/src/Mod/PartDesign/App/FeatureGroove.cpp
@@ -155,6 +155,11 @@ App::DocumentObjectExecReturn *Groove::execute(void)
             TopoDS_Shape solRes = this->getSolid(mkCut.Shape());
             if (solRes.IsNull())
                 return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
+
+            int solidCount = countSolids(result);
+            if (solidCount > 1) {
+                return new App::DocumentObjectExecReturn("Groove: Result has multiple solids. Check parameters.");
+            }
 
             solRes = refineShapeIfActive(solRes);
             this->Shape.setValue(getSolid(solRes));
diff --git a/src/Mod/PartDesign/App/FeatureHole.cpp b/src/Mod/PartDesign/App/FeatureHole.cpp
index 88f821f61f0..c1459337e6e 100644
--- a/src/Mod/PartDesign/App/FeatureHole.cpp
+++ b/src/Mod/PartDesign/App/FeatureHole.cpp
@@ -1256,6 +1256,12 @@ App::DocumentObjectExecReturn *Hole::execute(void)
         this->AddSubShape.setValue( holes );
 
         remapSupportShape(base);
+
+        int solidCount = countSolids(base);
+        if (solidCount > 1) {
+            return new App::DocumentObjectExecReturn("Hole: Result has multiple solids. Check parameters.");
+        }
+
         this->Shape.setValue(base);
 
         return App::DocumentObject::StdReturn;
diff --git a/src/Mod/PartDesign/App/FeatureLoft.cpp b/src/Mod/PartDesign/App/FeatureLoft.cpp
index fbf080d07b5..a8d3606e95f 100644
--- a/src/Mod/PartDesign/App/FeatureLoft.cpp
+++ b/src/Mod/PartDesign/App/FeatureLoft.cpp
@@ -193,6 +193,10 @@ App::DocumentObjectExecReturn *Loft::execute(void)
             // lets check if the result is a solid
             if (boolOp.IsNull())
                 return new App::DocumentObjectExecReturn("Loft: Resulting shape is not a solid");
+            int solidCount = countSolids(boolOp);
+            if (solidCount > 1) {
+                return new App::DocumentObjectExecReturn("Loft: Result has multiple solids. Check parameters.");
+            }
             
             boolOp = refineShapeIfActive(boolOp);
             Shape.setValue(getSolid(boolOp));
@@ -207,6 +211,10 @@ App::DocumentObjectExecReturn *Loft::execute(void)
             // lets check if the result is a solid
             if (boolOp.IsNull())
                 return new App::DocumentObjectExecReturn("Loft: Resulting shape is not a solid");
+            int solidCount = countSolids(boolOp);
+            if (solidCount > 1) {
+                return new App::DocumentObjectExecReturn("Loft: Result has multiple solids. Check parameters.");
+            }
             
             boolOp = refineShapeIfActive(boolOp);
             Shape.setValue(getSolid(boolOp));
diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp
index 0762844cf8a..f8e03716a2b 100644
--- a/src/Mod/PartDesign/App/FeaturePad.cpp
+++ b/src/Mod/PartDesign/App/FeaturePad.cpp
@@ -225,10 +225,21 @@ App::DocumentObjectExecReturn *Pad::execute(void)
             // lets check if the result is a solid
             if (solRes.IsNull())
                 return new App::DocumentObjectExecReturn("Pad: Resulting shape is not a solid");
+
+            int solidCount = countSolids(result);
+            if (solidCount > 1) {
+                return new App::DocumentObjectExecReturn("Pad: Result has multiple solids. Check parameters.");
+            }
+
             solRes = refineShapeIfActive(solRes);
             this->Shape.setValue(getSolid(solRes));
         } else {
-            this->Shape.setValue(getSolid(prism));
+            int solidCount = countSolids(prism);
+            if (solidCount > 1) {
+                return new App::DocumentObjectExecReturn("Pad: Result has multiple solids. Check parameters.");
+            }
+
+           this->Shape.setValue(getSolid(prism));
         }
 
         return App::DocumentObject::StdReturn;
diff --git a/src/Mod/PartDesign/App/FeaturePipe.cpp b/src/Mod/PartDesign/App/FeaturePipe.cpp
index 0af70f71e56..351584b6c5c 100644
--- a/src/Mod/PartDesign/App/FeaturePipe.cpp
+++ b/src/Mod/PartDesign/App/FeaturePipe.cpp
@@ -313,6 +313,11 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
             // lets check if the result is a solid
             if (boolOp.IsNull())
                 return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
+
+            int solidCount = countSolids(boolOp);
+            if (solidCount > 1) {
+                return new App::DocumentObjectExecReturn("Pipe: Result has multiple solids. Check parameters.");
+            }
 
             boolOp = refineShapeIfActive(boolOp);
             Shape.setValue(getSolid(boolOp));
@@ -327,6 +332,11 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
             // lets check if the result is a solid
             if (boolOp.IsNull())
                 return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
+
+            int solidCount = countSolids(boolOp);
+            if (solidCount > 1) {
+                return new App::DocumentObjectExecReturn("Pipe: Result has multiple solids. Check parameters.");
+            }
 
             boolOp = refineShapeIfActive(boolOp);
             Shape.setValue(getSolid(boolOp));
diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp
index 87267f1b47a..f3d9dbfe09c 100644
--- a/src/Mod/PartDesign/App/FeaturePocket.cpp
+++ b/src/Mod/PartDesign/App/FeaturePocket.cpp
@@ -43,6 +43,7 @@
 # include <BRepAlgoAPI_Common.hxx>
 #endif
 
+#include <Base/Console.h>
 #include <Base/Exception.h>
 #include <Base/Placement.h>
 #include <App/Document.h>
@@ -181,6 +182,12 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
             // FIXME: In some cases this affects the Shape property: It is set to the same shape as the SubShape!!!!
             TopoDS_Shape result = refineShapeIfActive(mkCut.Shape());
             this->AddSubShape.setValue(result);
+
+            int prismCount = countSolids(prism);
+            if (prismCount > 1) {
+                return new App::DocumentObjectExecReturn("Pocket: Result has multiple solids. Check parameters.");
+            }
+
             this->Shape.setValue(getSolid(prism));
         } else {
             TopoDS_Shape prism;
@@ -203,6 +210,12 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
             TopoDS_Shape solRes = this->getSolid(result);
             if (solRes.IsNull())
                 return new App::DocumentObjectExecReturn("Pocket: Resulting shape is not a solid");
+
+            int solidCount = countSolids(result);
+            if (solidCount > 1) {
+                return new App::DocumentObjectExecReturn("Pocket: Result has multiple solids. Check parameters.");
+
+            }
             solRes = refineShapeIfActive(solRes);
             remapSupportShape(solRes);
             this->Shape.setValue(getSolid(solRes));
diff --git a/src/Mod/PartDesign/App/FeaturePrimitive.cpp b/src/Mod/PartDesign/App/FeaturePrimitive.cpp
index a60befb7573..56638c69dd6 100644
--- a/src/Mod/PartDesign/App/FeaturePrimitive.cpp
+++ b/src/Mod/PartDesign/App/FeaturePrimitive.cpp
@@ -124,7 +124,12 @@ App::DocumentObjectExecReturn* FeaturePrimitive::execute(const TopoDS_Shape& pri
             // lets check if the result is a solid
             if (boolOp.IsNull())
                 return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
-            
+
+            int solidCount = countSolids(boolOp);
+            if (solidCount > 1) {
+                return new App::DocumentObjectExecReturn("Additive: Result has multiple solids. Check parameters.");
+            }
+
             boolOp = refineShapeIfActive(boolOp);
             Shape.setValue(getSolid(boolOp));
             AddSubShape.setValue(primitiveShape);
@@ -139,6 +144,11 @@ App::DocumentObjectExecReturn* FeaturePrimitive::execute(const TopoDS_Shape& pri
             // lets check if the result is a solid
             if (boolOp.IsNull())
                 return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
+
+            int solidCount = countSolids(boolOp);
+            if (solidCount > 1) {
+                return new App::DocumentObjectExecReturn("Subtractive: Result has multiple solids. Check parameters.");
+            }
             
             boolOp = refineShapeIfActive(boolOp);
             Shape.setValue(getSolid(boolOp));
diff --git a/src/Mod/PartDesign/App/FeatureTransformed.cpp b/src/Mod/PartDesign/App/FeatureTransformed.cpp
index b4ce20879c7..85655e9880c 100644
--- a/src/Mod/PartDesign/App/FeatureTransformed.cpp
+++ b/src/Mod/PartDesign/App/FeatureTransformed.cpp
@@ -331,6 +331,7 @@ App::DocumentObjectExecReturn *Transformed::execute(void)
                         // lets check if the result is a solid
                         if (current.IsNull())
                             return new App::DocumentObjectExecReturn("Resulting shape is not a solid", *o);
+
                         /*std::vector<TopoDS_Shape>::const_iterator individualIt;
                         for (individualIt = individualTools.begin(); individualIt != individualTools.end(); ++individualIt)
                         {
@@ -377,6 +378,11 @@ App::DocumentObjectExecReturn *Transformed::execute(void)
     for (rej_it_map::const_iterator it = nointersect_trsfms.begin(); it != nointersect_trsfms.end(); ++it)
         for (trsf_it::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2)
             rejected[it->first].push_back(**it2);
+
+    int solidCount = countSolids(support);
+    if (solidCount > 1) {
+        return new App::DocumentObjectExecReturn("Transformed: Result has multiple solids. Check parameters.");
+    }
 
     this->Shape.setValue(getSolid(support));
 

From 1dd565ee21e1bc8893429b257f127bd8c71ebed4 Mon Sep 17 00:00:00 2001
From: wandererfan <wandererfan@gmail.com>
Date: Mon, 9 Apr 2018 14:42:22 -0400
Subject: [PATCH 17/33] Fix PD Pocket Through All Unit Test

- test for Pocket Through All case
  generated a multi-solid solution.
  Now returns single solid.
---
 src/Mod/PartDesign/PartDesignTests/TestPocket.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Mod/PartDesign/PartDesignTests/TestPocket.py b/src/Mod/PartDesign/PartDesignTests/TestPocket.py
index 14f58e5aa96..6fec9beabea 100644
--- a/src/Mod/PartDesign/PartDesignTests/TestPocket.py
+++ b/src/Mod/PartDesign/PartDesignTests/TestPocket.py
@@ -76,14 +76,14 @@ def testPocketThroughAllCase(self):
         self.PocketSketch1.MapMode = 'FlatFace'
         self.PocketSketch1.Support = (self.Doc.XZ_Plane, [''])
         self.Doc.recompute()
-        TestSketcherApp.CreateRectangleSketch(self.PocketSketch1, (2.5, -1), (5, 1))
+        TestSketcherApp.CreateRectangleSketch(self.PocketSketch1, (2.5, -0.75), (5, 0.50))
         self.Doc.recompute()
         self.Pocket001 = self.Doc.addObject("PartDesign::Pocket", "Pocket001")
         self.Body.addObject(self.Pocket001)
         self.Pocket001.Profile = self.PocketSketch1
         self.Pocket001.Type = 1
         self.Doc.recompute()
-        self.assertAlmostEqual(self.Pocket001.Shape.Volume, 25.0)
+        self.assertAlmostEqual(self.Pocket001.Shape.Volume, 62.5)
 
     def testPocketToFirstCase(self):
         self.Body = self.Doc.addObject('PartDesign::Body','Body')

From 5c3f7bf8ec51e2c7187789f7edba71a7aa82a88b Mon Sep 17 00:00:00 2001
From: wandererfan <wandererfan@gmail.com>
Date: Wed, 4 Jul 2018 19:17:50 -0400
Subject: [PATCH 18/33] Revise multiple solids message

---
 src/Mod/PartDesign/App/FeatureBoolean.cpp     | 2 +-
 src/Mod/PartDesign/App/FeatureChamfer.cpp     | 2 +-
 src/Mod/PartDesign/App/FeatureDraft.cpp       | 2 +-
 src/Mod/PartDesign/App/FeatureFillet.cpp      | 2 +-
 src/Mod/PartDesign/App/FeatureGroove.cpp      | 2 +-
 src/Mod/PartDesign/App/FeatureHole.cpp        | 2 +-
 src/Mod/PartDesign/App/FeatureLoft.cpp        | 4 ++--
 src/Mod/PartDesign/App/FeaturePad.cpp         | 4 ++--
 src/Mod/PartDesign/App/FeaturePipe.cpp        | 4 ++--
 src/Mod/PartDesign/App/FeaturePocket.cpp      | 4 ++--
 src/Mod/PartDesign/App/FeaturePrimitive.cpp   | 4 ++--
 src/Mod/PartDesign/App/FeatureTransformed.cpp | 2 +-
 12 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/src/Mod/PartDesign/App/FeatureBoolean.cpp b/src/Mod/PartDesign/App/FeatureBoolean.cpp
index a1f7fbbea84..51faf094e36 100644
--- a/src/Mod/PartDesign/App/FeatureBoolean.cpp
+++ b/src/Mod/PartDesign/App/FeatureBoolean.cpp
@@ -144,7 +144,7 @@ App::DocumentObjectExecReturn *Boolean::execute(void)
 
     int solidCount = countSolids(result);
     if (solidCount > 1) {
-        return new App::DocumentObjectExecReturn("Boolean: Result has multiple solids. Check parameters.");
+        return new App::DocumentObjectExecReturn("Boolean: Result has multiple solids. This is not supported at this time.");
     }
 
     this->Shape.setValue(getSolid(result));
diff --git a/src/Mod/PartDesign/App/FeatureChamfer.cpp b/src/Mod/PartDesign/App/FeatureChamfer.cpp
index 8f39b18b050..7eeee53b158 100644
--- a/src/Mod/PartDesign/App/FeatureChamfer.cpp
+++ b/src/Mod/PartDesign/App/FeatureChamfer.cpp
@@ -127,7 +127,7 @@ App::DocumentObjectExecReturn *Chamfer::execute(void)
         }
         int solidCount = countSolids(shape);
         if (solidCount > 1) {
-            return new App::DocumentObjectExecReturn("Chamfer: Result has multiple solids. Check parameters.");
+            return new App::DocumentObjectExecReturn("Chamfer: Result has multiple solids. This is not supported at this time.");
         }
 
         this->Shape.setValue(getSolid(shape));
diff --git a/src/Mod/PartDesign/App/FeatureDraft.cpp b/src/Mod/PartDesign/App/FeatureDraft.cpp
index e94a230b37f..1e3188e59e5 100644
--- a/src/Mod/PartDesign/App/FeatureDraft.cpp
+++ b/src/Mod/PartDesign/App/FeatureDraft.cpp
@@ -306,7 +306,7 @@ App::DocumentObjectExecReturn *Draft::execute(void)
 
         int solidCount = countSolids(shape);
         if (solidCount > 1) {
-            return new App::DocumentObjectExecReturn("Fuse: Result has multiple solids. Check parameters.");
+            return new App::DocumentObjectExecReturn("Fuse: Result has multiple solids. This is not supported at this time.");
         }
 
         this->Shape.setValue(getSolid(shape));
diff --git a/src/Mod/PartDesign/App/FeatureFillet.cpp b/src/Mod/PartDesign/App/FeatureFillet.cpp
index 66c01e02bf4..37a9286dfb1 100644
--- a/src/Mod/PartDesign/App/FeatureFillet.cpp
+++ b/src/Mod/PartDesign/App/FeatureFillet.cpp
@@ -120,7 +120,7 @@ App::DocumentObjectExecReturn *Fillet::execute(void)
 
         int solidCount = countSolids(shape);
         if (solidCount > 1) {
-            return new App::DocumentObjectExecReturn("Fillet: Result has multiple solids. Check parameters.");
+            return new App::DocumentObjectExecReturn("Fillet: Result has multiple solids. This is not supported at this time.");
         }
 
         this->Shape.setValue(getSolid(shape));
diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp
index c27613aa801..ab97d79a2b9 100644
--- a/src/Mod/PartDesign/App/FeatureGroove.cpp
+++ b/src/Mod/PartDesign/App/FeatureGroove.cpp
@@ -158,7 +158,7 @@ App::DocumentObjectExecReturn *Groove::execute(void)
 
             int solidCount = countSolids(result);
             if (solidCount > 1) {
-                return new App::DocumentObjectExecReturn("Groove: Result has multiple solids. Check parameters.");
+                return new App::DocumentObjectExecReturn("Groove: Result has multiple solids. This is not supported at this time.");
             }
 
             solRes = refineShapeIfActive(solRes);
diff --git a/src/Mod/PartDesign/App/FeatureHole.cpp b/src/Mod/PartDesign/App/FeatureHole.cpp
index c1459337e6e..4da6482bf55 100644
--- a/src/Mod/PartDesign/App/FeatureHole.cpp
+++ b/src/Mod/PartDesign/App/FeatureHole.cpp
@@ -1259,7 +1259,7 @@ App::DocumentObjectExecReturn *Hole::execute(void)
 
         int solidCount = countSolids(base);
         if (solidCount > 1) {
-            return new App::DocumentObjectExecReturn("Hole: Result has multiple solids. Check parameters.");
+            return new App::DocumentObjectExecReturn("Hole: Result has multiple solids. This is not supported at this time.");
         }
 
         this->Shape.setValue(base);
diff --git a/src/Mod/PartDesign/App/FeatureLoft.cpp b/src/Mod/PartDesign/App/FeatureLoft.cpp
index a8d3606e95f..020c85c8429 100644
--- a/src/Mod/PartDesign/App/FeatureLoft.cpp
+++ b/src/Mod/PartDesign/App/FeatureLoft.cpp
@@ -195,7 +195,7 @@ App::DocumentObjectExecReturn *Loft::execute(void)
                 return new App::DocumentObjectExecReturn("Loft: Resulting shape is not a solid");
             int solidCount = countSolids(boolOp);
             if (solidCount > 1) {
-                return new App::DocumentObjectExecReturn("Loft: Result has multiple solids. Check parameters.");
+                return new App::DocumentObjectExecReturn("Loft: Result has multiple solids. This is not supported at this time.");
             }
             
             boolOp = refineShapeIfActive(boolOp);
@@ -213,7 +213,7 @@ App::DocumentObjectExecReturn *Loft::execute(void)
                 return new App::DocumentObjectExecReturn("Loft: Resulting shape is not a solid");
             int solidCount = countSolids(boolOp);
             if (solidCount > 1) {
-                return new App::DocumentObjectExecReturn("Loft: Result has multiple solids. Check parameters.");
+                return new App::DocumentObjectExecReturn("Loft: Result has multiple solids. This is not supported at this time.");
             }
             
             boolOp = refineShapeIfActive(boolOp);
diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp
index f8e03716a2b..8bd0de633c4 100644
--- a/src/Mod/PartDesign/App/FeaturePad.cpp
+++ b/src/Mod/PartDesign/App/FeaturePad.cpp
@@ -228,7 +228,7 @@ App::DocumentObjectExecReturn *Pad::execute(void)
 
             int solidCount = countSolids(result);
             if (solidCount > 1) {
-                return new App::DocumentObjectExecReturn("Pad: Result has multiple solids. Check parameters.");
+                return new App::DocumentObjectExecReturn("Pad: Result has multiple solids. This is not supported at this time.");
             }
 
             solRes = refineShapeIfActive(solRes);
@@ -236,7 +236,7 @@ App::DocumentObjectExecReturn *Pad::execute(void)
         } else {
             int solidCount = countSolids(prism);
             if (solidCount > 1) {
-                return new App::DocumentObjectExecReturn("Pad: Result has multiple solids. Check parameters.");
+                return new App::DocumentObjectExecReturn("Pad: Result has multiple solids. This is not supported at this time.");
             }
 
            this->Shape.setValue(getSolid(prism));
diff --git a/src/Mod/PartDesign/App/FeaturePipe.cpp b/src/Mod/PartDesign/App/FeaturePipe.cpp
index 351584b6c5c..7c1391ffc74 100644
--- a/src/Mod/PartDesign/App/FeaturePipe.cpp
+++ b/src/Mod/PartDesign/App/FeaturePipe.cpp
@@ -316,7 +316,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
 
             int solidCount = countSolids(boolOp);
             if (solidCount > 1) {
-                return new App::DocumentObjectExecReturn("Pipe: Result has multiple solids. Check parameters.");
+                return new App::DocumentObjectExecReturn("Pipe: Result has multiple solids. This is not supported at this time.");
             }
 
             boolOp = refineShapeIfActive(boolOp);
@@ -335,7 +335,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void)
 
             int solidCount = countSolids(boolOp);
             if (solidCount > 1) {
-                return new App::DocumentObjectExecReturn("Pipe: Result has multiple solids. Check parameters.");
+                return new App::DocumentObjectExecReturn("Pipe: Result has multiple solids. This is not supported at this time.");
             }
 
             boolOp = refineShapeIfActive(boolOp);
diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp
index f3d9dbfe09c..c9d49a58789 100644
--- a/src/Mod/PartDesign/App/FeaturePocket.cpp
+++ b/src/Mod/PartDesign/App/FeaturePocket.cpp
@@ -185,7 +185,7 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
 
             int prismCount = countSolids(prism);
             if (prismCount > 1) {
-                return new App::DocumentObjectExecReturn("Pocket: Result has multiple solids. Check parameters.");
+                return new App::DocumentObjectExecReturn("Pocket: Result has multiple solids. This is not supported at this time.");
             }
 
             this->Shape.setValue(getSolid(prism));
@@ -213,7 +213,7 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
 
             int solidCount = countSolids(result);
             if (solidCount > 1) {
-                return new App::DocumentObjectExecReturn("Pocket: Result has multiple solids. Check parameters.");
+                return new App::DocumentObjectExecReturn("Pocket: Result has multiple solids. This is not supported at this time.");
 
             }
             solRes = refineShapeIfActive(solRes);
diff --git a/src/Mod/PartDesign/App/FeaturePrimitive.cpp b/src/Mod/PartDesign/App/FeaturePrimitive.cpp
index 56638c69dd6..92f322d4324 100644
--- a/src/Mod/PartDesign/App/FeaturePrimitive.cpp
+++ b/src/Mod/PartDesign/App/FeaturePrimitive.cpp
@@ -127,7 +127,7 @@ App::DocumentObjectExecReturn* FeaturePrimitive::execute(const TopoDS_Shape& pri
 
             int solidCount = countSolids(boolOp);
             if (solidCount > 1) {
-                return new App::DocumentObjectExecReturn("Additive: Result has multiple solids. Check parameters.");
+                return new App::DocumentObjectExecReturn("Additive: Result has multiple solids. This is not supported at this time.");
             }
 
             boolOp = refineShapeIfActive(boolOp);
@@ -147,7 +147,7 @@ App::DocumentObjectExecReturn* FeaturePrimitive::execute(const TopoDS_Shape& pri
 
             int solidCount = countSolids(boolOp);
             if (solidCount > 1) {
-                return new App::DocumentObjectExecReturn("Subtractive: Result has multiple solids. Check parameters.");
+                return new App::DocumentObjectExecReturn("Subtractive: Result has multiple solids. This is not supported at this time.");
             }
             
             boolOp = refineShapeIfActive(boolOp);
diff --git a/src/Mod/PartDesign/App/FeatureTransformed.cpp b/src/Mod/PartDesign/App/FeatureTransformed.cpp
index 85655e9880c..b279540cfed 100644
--- a/src/Mod/PartDesign/App/FeatureTransformed.cpp
+++ b/src/Mod/PartDesign/App/FeatureTransformed.cpp
@@ -381,7 +381,7 @@ App::DocumentObjectExecReturn *Transformed::execute(void)
 
     int solidCount = countSolids(support);
     if (solidCount > 1) {
-        return new App::DocumentObjectExecReturn("Transformed: Result has multiple solids. Check parameters.");
+        return new App::DocumentObjectExecReturn("Transformed: Result has multiple solids. This is not supported at this time.");
     }
 
     this->Shape.setValue(getSolid(support));

From 1bf6c6aa143447ae645c1eff96cf06d61b0d6eea Mon Sep 17 00:00:00 2001
From: Eivind Kvedalen <eivind@kvedalen.name>
Date: Sun, 29 Jul 2018 00:59:57 +0200
Subject: [PATCH 19/33] Fix for issue #3541: Normalize xDir vector for Hole
 feature to correct hole diameter.

---
 src/Mod/PartDesign/App/FeatureHole.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/Mod/PartDesign/App/FeatureHole.cpp b/src/Mod/PartDesign/App/FeatureHole.cpp
index 4da6482bf55..2848cd02aab 100644
--- a/src/Mod/PartDesign/App/FeatureHole.cpp
+++ b/src/Mod/PartDesign/App/FeatureHole.cpp
@@ -985,6 +985,9 @@ App::DocumentObjectExecReturn *Hole::execute(void)
         else
             xDir = gp_Vec(0, -zDir.Z(), zDir.Y());
 
+        // Normalize xDir; this is needed as the computation above does not necessarily give a unit-length vector.
+        xDir.Normalize();
+
         if ( method == "Dimension" )
             length = Depth.getValue();
         else if ( method == "UpToFirst" ) {

From f157a99d2eb60c94f015260df34520b6392fe03e Mon Sep 17 00:00:00 2001
From: Ryan Pavlik <ryan.pavlik@gmail.com>
Date: Fri, 15 Jun 2018 11:32:48 -0500
Subject: [PATCH 20/33] Clean up and improve "COPY_IF_DIFFERENT" CMake macro

---
 cMake/FreeCadMacros.cmake | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/cMake/FreeCadMacros.cmake b/cMake/FreeCadMacros.cmake
index 60d6bc5eadc..7680a808e96 100644
--- a/cMake/FreeCadMacros.cmake
+++ b/cMake/FreeCadMacros.cmake
@@ -14,7 +14,7 @@ MACRO(COPY_IF_DIFFERENT FROM_DIR TO_DIR FILES TARGETS TAGS)
 #   TAGS     - Since only the file name is used
 #              to generate rules, pre-pend a user 
 #              supplied tag to prevent duplicate rule errors. 
-SET(AddTargets "")
+SET(AddTargets)
 FOREACH(SRC ${FILES})
     GET_FILENAME_COMPONENT(SRCFILE ${SRC} NAME) 
     # Command to copy the files to ${STEP1}/src, if changed.
@@ -31,11 +31,11 @@ FOREACH(SRC ${FILES})
     ENDIF("${TO_DIR}" STREQUAL "")
     ADD_CUSTOM_COMMAND(
         OUTPUT  ${TARGET}
-        COMMAND ${CMAKE_COMMAND}
-        ARGS    -E copy_if_different ${FROM} ${TO}
+        COMMAND "${CMAKE_COMMAND}"
+        ARGS    -E copy_if_different "${FROM}" "${TO}"
         COMMENT "Copying ${SRCFILE} ${TO_DIR}"
         )
-    SET(AddTargets ${AddTargets} ${TARGET})
+    list(APPEND AddTargets ${TARGET})
 ENDFOREACH(SRC ${FILES})
 SET(${TARGETS} ${AddTargets})
 ENDMACRO(COPY_IF_DIFFERENT FROM_DIR TO_DIR FILES TARGETS TAGS)
@@ -236,15 +236,15 @@ MACRO(SET_BIN_DIR ProjectName OutputName)
     if(WIN32)
         set_target_properties(${ProjectName} PROPERTIES DEBUG_OUTPUT_NAME ${OutputName}_d)
     else(WIN32)
-        # FreeCADBase, SMDS, Driver, MEFISTO2 and area-native libs don't depend on parts from CMAKE_INSTALL_LIBDIR
-        if(NOT ${ProjectName} MATCHES "^(FreeCADBase|SMDS|Driver|MEFISTO2|area-native)$")
-            if(${ARGC} STREQUAL 4)
-                set_property(TARGET ${ProjectName} APPEND PROPERTY INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}${ARGV3})
-            else(${ARGC} STREQUAL 4)
-                set_property(TARGET ${ProjectName} APPEND PROPERTY INSTALL_RPATH ${CMAKE_INSTALL_LIBDIR})
-            endif()
-        endif()
-    endif(WIN32)
+        # FreeCADBase, SMDS, Driver, MEFISTO2 and area-native libs don't depend on parts from CMAKE_INSTALL_LIBDIR
+        if(NOT ${ProjectName} MATCHES "^(FreeCADBase|SMDS|Driver|MEFISTO2|area-native)$")
+            if(${ARGC} STREQUAL 4)
+                set_property(TARGET ${ProjectName} APPEND PROPERTY INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}${ARGV3})
+            else(${ARGC} STREQUAL 4)
+                set_property(TARGET ${ProjectName} APPEND PROPERTY INSTALL_RPATH ${CMAKE_INSTALL_LIBDIR})
+            endif()
+        endif()
+    endif(WIN32)
 ENDMACRO(SET_BIN_DIR)
 
 # Set python prefix & suffix together
@@ -255,8 +255,8 @@ MACRO(SET_PYTHON_PREFIX_SUFFIX ProjectName)
     
     if(WIN32)
         set_target_properties(${ProjectName} PROPERTIES SUFFIX ".pyd")
-    # 0000661: cmake build on Mac OS: dealing with dylib versus so
-    elseif(APPLE)
+    # 0000661: cmake build on Mac OS: dealing with dylib versus so
+    elseif(APPLE)
         set_target_properties(${ProjectName} PROPERTIES SUFFIX ".so")
     endif(WIN32)
-ENDMACRO(SET_PYTHON_PREFIX_SUFFIX)
+ENDMACRO(SET_PYTHON_PREFIX_SUFFIX)

From ed0578e2f132fae8058b9f00a41c3965d931f268 Mon Sep 17 00:00:00 2001
From: Ryan Pavlik <ryan.pavlik@gmail.com>
Date: Fri, 15 Jun 2018 11:49:39 -0500
Subject: [PATCH 21/33] Clean up and improve fc_copy_sources and
 fc_target_copy_resource CMake macros

The previous steps of TO_NATIVE_PATH followed by ABSOLUTE
is not meaningful or reliable: output of ABSOLUTE is always in
"cmake" path format, not native path format. Native path input to
CMake commands may not do what you want.
---
 cMake/FreeCadMacros.cmake | 27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/cMake/FreeCadMacros.cmake b/cMake/FreeCadMacros.cmake
index 7680a808e96..3ac60b1845a 100644
--- a/cMake/FreeCadMacros.cmake
+++ b/cMake/FreeCadMacros.cmake
@@ -42,16 +42,14 @@ ENDMACRO(COPY_IF_DIFFERENT FROM_DIR TO_DIR FILES TARGETS TAGS)
 
 MACRO (fc_copy_sources target_name outpath)
 	foreach(it ${ARGN})
-		file(TO_NATIVE_PATH "${outpath}/${it}" outfile)
 		get_filename_component(infile ${it} ABSOLUTE)
-		get_filename_component(outfile ${outfile} ABSOLUTE)
-		add_file_dependencies(${infile} ${outfile})
+		get_filename_component(outfile "${outpath}/${it}" ABSOLUTE)
+		add_file_dependencies("${infile}" "${outfile}")
 		ADD_CUSTOM_COMMAND(
-			SOURCE    ${infile}
-			COMMAND   ${CMAKE_COMMAND}
-			ARGS      -E copy ${infile} ${outfile}
+			SOURCE    "${infile}"
+			COMMAND   "${CMAKE_COMMAND}" -E copy "${infile}" "${outfile}"
 			TARGET    ${target_name}
-			OUTPUTS   ${outfile}
+			OUTPUTS   "${outfile}"
 		)
 	endforeach(it)
 	ADD_CUSTOM_COMMAND(
@@ -63,17 +61,14 @@ ENDMACRO(fc_copy_sources)
 
 MACRO (fc_target_copy_resource target_name inpath outpath)
 	foreach(it ${ARGN})
-		file(TO_NATIVE_PATH "${inpath}/${it}" infile)
-		file(TO_NATIVE_PATH "${outpath}/${it}" outfile)
-		get_filename_component(infile ${infile} ABSOLUTE)
-		get_filename_component(outfile ${outfile} ABSOLUTE)
-		add_file_dependencies(${infile} ${outfile})
+		get_filename_component(infile "${inpath}/${it}" ABSOLUTE)
+		get_filename_component(outfile "${outpath}/${it}" ABSOLUTE)
+		add_file_dependencies("${infile}" "${outfile}")
 		ADD_CUSTOM_COMMAND(
-			SOURCE    ${infile}
-			COMMAND   ${CMAKE_COMMAND}
-			ARGS      -E copy ${infile} ${outfile}
+			SOURCE    "${infile}"
+			COMMAND   "${CMAKE_COMMAND}" -E copy "${infile}" "${outfile}"
 			TARGET    ${target_name}
-			OUTPUTS   ${outfile}
+			OUTPUTS   "${outfile}"
 		)
 	endforeach(it)
 	ADD_CUSTOM_COMMAND(

From 47df62e31d867705e21a8e140a2d2efc5f1bf414 Mon Sep 17 00:00:00 2001
From: Ryan Pavlik <ryan.pavlik@gmail.com>
Date: Fri, 15 Jun 2018 11:56:09 -0500
Subject: [PATCH 22/33] Clean up and fix generate_from_py and generate_from_xml
 CMake macros

Includes native-path-usage fixing like the previous commit.
---
 cMake/FreeCadMacros.cmake | 51 ++++++++++++++++++++++-----------------
 1 file changed, 29 insertions(+), 22 deletions(-)

diff --git a/cMake/FreeCadMacros.cmake b/cMake/FreeCadMacros.cmake
index 3ac60b1845a..7d0dbe12444 100644
--- a/cMake/FreeCadMacros.cmake
+++ b/cMake/FreeCadMacros.cmake
@@ -123,39 +123,46 @@ endmacro(copy_to_main_output_paths)
 # It would be a bit cleaner to generate these files in ${CMAKE_CURRENT_BINARY_DIR}
 
 macro(generate_from_xml BASE_NAME)
-    file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR}/src/Tools/generate.py TOOL_PATH)
-    file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${BASE_NAME}.xml SOURCE_PATH)
+    set(TOOL_PATH "${CMAKE_SOURCE_DIR}/src/Tools/generate.py")
+    file(TO_NATIVE_PATH "${TOOL_PATH}" TOOL_NATIVE_PATH)
+    file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${BASE_NAME}.xml" SOURCE_NATIVE_PATH)
 
-    file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${BASE_NAME}.cpp SOURCE_CPP_PATH)
+    set(SOURCE_CPP_PATH "${CMAKE_CURRENT_BINARY_DIR}/${BASE_NAME}.cpp" )
+    
     # BASE_NAME may include also a path name
-    GET_FILENAME_COMPONENT(OUTPUT_PATH ${SOURCE_CPP_PATH} PATH)
-    if (NOT EXISTS ${SOURCE_CPP_PATH})
+    GET_FILENAME_COMPONENT(OUTPUT_PATH "${SOURCE_CPP_PATH}" PATH)
+    file(TO_NATIVE_PATH "${OUTPUT_PATH}" OUTPUT_NATIVE_PATH)
+    if(NOT EXISTS "${SOURCE_CPP_PATH}")
         # assures the source files are generated at least once
-        message(STATUS "${SOURCE_CPP_PATH}")
-        execute_process(COMMAND ${PYTHON_EXECUTABLE} ${TOOL_PATH} --outputPath ${OUTPUT_PATH} ${SOURCE_PATH}
-                        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+        
+        execute_process(COMMAND "${PYTHON_EXECUTABLE}" "${TOOL_NATIVE_PATH}" --outputPath "${OUTPUT_NATIVE_PATH}" "${SOURCE_NATIVE_PATH}"
+                        WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
         )
-    endif (NOT EXISTS ${SOURCE_CPP_PATH})
+    endif()
 
     add_custom_command(
-        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BASE_NAME}.h ${CMAKE_CURRENT_BINARY_DIR}/${BASE_NAME}.cpp
-        COMMAND ${PYTHON_EXECUTABLE} ${TOOL_PATH} --outputPath ${OUTPUT_PATH} ${BASE_NAME}.xml
-        MAIN_DEPENDENCY ${BASE_NAME}.xml
-        DEPENDS ${CMAKE_SOURCE_DIR}/src/Tools/generateTemplates/templateClassPyExport.py
-        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-        COMMENT Building ${BASE_NAME}.h/.cpp out of ${BASE_NAME}.xml
+        OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${BASE_NAME}.h" "${CMAKE_CURRENT_BINARY_DIR}/${BASE_NAME}.cpp"
+        COMMAND ${PYTHON_EXECUTABLE} "${TOOL_NATIVE_PATH}" --outputPath "${OUTPUT_NATIVE_PATH}" ${BASE_NAME}.xml
+        MAIN_DEPENDENCY "${SOURCE_PATH}"
+        DEPENDS
+        "${CMAKE_SOURCE_DIR}/src/Tools/generateTemplates/templateClassPyExport.py"
+        "${TOOL_PATH}"
+        WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+        COMMENT "Building ${BASE_NAME}.h/.cpp out of ${BASE_NAME}.xml"
     )
 endmacro(generate_from_xml)
 
 macro(generate_from_py BASE_NAME OUTPUT_FILE)
-		 file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR}/src/Tools/PythonToCPP.py TOOL_PATH)
-		 file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${BASE_NAME}.py SOURCE_PATH)
+		set(TOOL_PATH "${CMAKE_SOURCE_DIR}/src/Tools/PythonToCPP.py")
+		file(TO_NATIVE_PATH "${TOOL_PATH}" TOOL_NATIVE_PATH)
+		file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${BASE_NAME}.py" SOURCE_NATIVE_PATH)
 		 add_custom_command(
-		 		 OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}
-		 		 COMMAND ${PYTHON_EXECUTABLE} ${TOOL_PATH} ${SOURCE_PATH} ${OUTPUT_FILE}
-		 		 MAIN_DEPENDENCY ${BASE_NAME}.py
-		 		 WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-		 		 COMMENT Building files out of ${BASE_NAME}.py)
+		 		OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}"
+		 		COMMAND "${PYTHON_EXECUTABLE}" "${TOOL_NATIVE_PATH}" "${SOURCE_NATIVE_PATH}" "${OUTPUT_FILE}"
+				MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/${BASE_NAME}.py"
+				DEPENDS "${TOOL_PATH}"
+				WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+				COMMENT "Building files out of ${BASE_NAME}.py")
 endmacro(generate_from_py)
 
 

From a730446f45cfa2cd356a67f3121cfa5468c4a841 Mon Sep 17 00:00:00 2001
From: Ryan Pavlik <ryan.pavlik@gmail.com>
Date: Fri, 15 Jun 2018 11:57:05 -0500
Subject: [PATCH 23/33] Add fc_target_copy_resource/fc_copy_sources build
 message

Includes optional verbosity param for tracking down "two rules for..."
ninja/etc warnings.
---
 cMake/FreeCadMacros.cmake | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/cMake/FreeCadMacros.cmake b/cMake/FreeCadMacros.cmake
index 7d0dbe12444..bbf504f4356 100644
--- a/cMake/FreeCadMacros.cmake
+++ b/cMake/FreeCadMacros.cmake
@@ -41,6 +41,11 @@ SET(${TARGETS} ${AddTargets})
 ENDMACRO(COPY_IF_DIFFERENT FROM_DIR TO_DIR FILES TARGETS TAGS)
 
 MACRO (fc_copy_sources target_name outpath)
+	if(BUILD_VERBOSE_GENERATION)
+		set(fc_details " (fc_copy_sources called from ${CMAKE_CURRENT_SOURCE_DIR})")
+	else()
+		set(fc_details "")
+	endif()
 	foreach(it ${ARGN})
 		get_filename_component(infile ${it} ABSOLUTE)
 		get_filename_component(outfile "${outpath}/${it}" ABSOLUTE)
@@ -50,6 +55,7 @@ MACRO (fc_copy_sources target_name outpath)
 			COMMAND   "${CMAKE_COMMAND}" -E copy "${infile}" "${outfile}"
 			TARGET    ${target_name}
 			OUTPUTS   "${outfile}"
+			COMMENT "Copying ${infile} to ${outfile}${fc_details}"
 		)
 	endforeach(it)
 	ADD_CUSTOM_COMMAND(
@@ -60,6 +66,11 @@ MACRO (fc_copy_sources target_name outpath)
 ENDMACRO(fc_copy_sources)
 
 MACRO (fc_target_copy_resource target_name inpath outpath)
+	if(BUILD_VERBOSE_GENERATION)
+		set(fc_details " (fc_target_copy_resource called from ${CMAKE_CURRENT_SOURCE_DIR})")
+	else()
+		set(fc_details "")
+	endif()
 	foreach(it ${ARGN})
 		get_filename_component(infile "${inpath}/${it}" ABSOLUTE)
 		get_filename_component(outfile "${outpath}/${it}" ABSOLUTE)
@@ -69,6 +80,7 @@ MACRO (fc_target_copy_resource target_name inpath outpath)
 			COMMAND   "${CMAKE_COMMAND}" -E copy "${infile}" "${outfile}"
 			TARGET    ${target_name}
 			OUTPUTS   "${outfile}"
+			COMMENT "Copying ${infile} to ${outfile}${fc_details}"
 		)
 	endforeach(it)
 	ADD_CUSTOM_COMMAND(
@@ -156,7 +168,7 @@ macro(generate_from_py BASE_NAME OUTPUT_FILE)
 		set(TOOL_PATH "${CMAKE_SOURCE_DIR}/src/Tools/PythonToCPP.py")
 		file(TO_NATIVE_PATH "${TOOL_PATH}" TOOL_NATIVE_PATH)
 		file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${BASE_NAME}.py" SOURCE_NATIVE_PATH)
-		 add_custom_command(
+		add_custom_command(
 		 		OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}"
 		 		COMMAND "${PYTHON_EXECUTABLE}" "${TOOL_NATIVE_PATH}" "${SOURCE_NATIVE_PATH}" "${OUTPUT_FILE}"
 				MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/${BASE_NAME}.py"

From 69277bce61c7d828e3c8e382fc98863c8b3e4fa8 Mon Sep 17 00:00:00 2001
From: Ryan Pavlik <ryan.pavlik@gmail.com>
Date: Fri, 15 Jun 2018 11:58:23 -0500
Subject: [PATCH 24/33] Clean up and make FindPySideTools CMake module more
 robust

---
 cMake/FindPySideTools.cmake | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/cMake/FindPySideTools.cmake b/cMake/FindPySideTools.cmake
index 1a421bbfa76..e04ddb985bd 100644
--- a/cMake/FindPySideTools.cmake
+++ b/cMake/FindPySideTools.cmake
@@ -45,7 +45,7 @@ MACRO(PYSIDE_WRAP_UI outfiles)
           OUTPUT_FILE ${outfile}
         )
     endif(WIN32)
-    SET(${outfiles} ${${outfiles}} ${outfile})
+    list(APPEND ${outfiles} ${outfile})
   ENDFOREACH(it)
 ENDMACRO (PYSIDE_WRAP_UI)
 
@@ -53,7 +53,7 @@ MACRO(PYSIDE_WRAP_RC outfiles)
   FOREACH(it ${ARGN})
     GET_FILENAME_COMPONENT(outfile ${it} NAME_WE)
     GET_FILENAME_COMPONENT(infile ${it} ABSOLUTE)
-    SET(outfile ${CMAKE_CURRENT_BINARY_DIR}/${outfile}_rc.py)
+    SET(outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}_rc.py")
     #ADD_CUSTOM_TARGET(${it} ALL
     #  DEPENDS ${outfile}
     #)
@@ -76,7 +76,7 @@ MACRO(PYSIDE_WRAP_RC outfiles)
           OUTPUT_FILE ${outfile}
        )
     endif(WIN32)
-    SET(${outfiles} ${${outfiles}} ${outfile})
+    list(APPEND ${outfiles} ${outfile})
   ENDFOREACH(it)
 ENDMACRO (PYSIDE_WRAP_RC)
 

From 56f40a5a08226035768d126f456eaeacd1f0a845 Mon Sep 17 00:00:00 2001
From: Ryan Pavlik <ryan.pavlik@gmail.com>
Date: Fri, 15 Jun 2018 12:01:20 -0500
Subject: [PATCH 25/33] Fix policy warning with CMake (regarding "no rules to
 generate")

Fixed by using add_custom_command instead of execute_process,
with an in-place sed command included to strip timestamp just like
previous code.
---
 cMake/FindPySideTools.cmake | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/cMake/FindPySideTools.cmake b/cMake/FindPySideTools.cmake
index e04ddb985bd..c6e64540de5 100644
--- a/cMake/FindPySideTools.cmake
+++ b/cMake/FindPySideTools.cmake
@@ -38,11 +38,12 @@ MACRO(PYSIDE_WRAP_UI outfiles)
         )
     else(WIN32)
         # Especially on Open Build Service we don't want changing date like
-        # pyside-uic generates in comments at beginning.
-        EXECUTE_PROCESS(
-          COMMAND ${PYSIDEUIC4BINARY} ${infile}
-          COMMAND sed "/^# /d"
-          OUTPUT_FILE ${outfile}
+        # pyside-uic generates in comments at beginning, which is why
+        # we follow the tool command with in-place sed.
+        ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
+          COMMAND ${PYSIDEUIC4BINARY} "${infile}" -o "${outfile}"
+          COMMAND sed -i "/^# /d" "${outfile}"
+          MAIN_DEPENDENCY ${infile}
         )
     endif(WIN32)
     list(APPEND ${outfiles} ${outfile})
@@ -69,12 +70,13 @@ MACRO(PYSIDE_WRAP_RC outfiles)
         )
     else(WIN32)
         # Especially on Open Build Service we don't want changing date like
-        # pyside-rcc generates in comments at beginning.
-        EXECUTE_PROCESS(
-          COMMAND ${PYSIDERCC4BINARY} ${infile} ${PY_ATTRIBUTE}
-          COMMAND sed "/^# /d"
-          OUTPUT_FILE ${outfile}
-       )
+        # pyside-rcc generates in comments at beginning, which is why
+        # we follow the tool command with in-place sed.
+        ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
+          COMMAND ${PYSIDERCC4BINARY} "${infile}" ${PY_ATTRIBUTE} -o "${outfile}"
+          COMMAND sed -i "/^# /d" "${outfile}"
+          MAIN_DEPENDENCY ${infile}
+        )
     endif(WIN32)
     list(APPEND ${outfiles} ${outfile})
   ENDFOREACH(it)

From 55f23fa6756afeda028681ca8fb903713f5617d0 Mon Sep 17 00:00:00 2001
From: Ryan Pavlik <ryan.pavlik@gmail.com>
Date: Fri, 15 Jun 2018 12:02:16 -0500
Subject: [PATCH 26/33] Fix ninja warnings about duplicate rules for
 Mod/Path/Init.py

Both Path/App and Path/PathSimulator/App were copying it.
---
 src/Mod/Path/PathSimulator/App/CMakeLists.txt | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/src/Mod/Path/PathSimulator/App/CMakeLists.txt b/src/Mod/Path/PathSimulator/App/CMakeLists.txt
index b76804e8037..3f4de55fbc4 100644
--- a/src/Mod/Path/PathSimulator/App/CMakeLists.txt
+++ b/src/Mod/Path/PathSimulator/App/CMakeLists.txt
@@ -44,12 +44,6 @@ SOURCE_GROUP("Python" FILES ${Python_SRCS})
 add_library(PathSimulator SHARED ${PathSimulator_SRCS})
 target_link_libraries(PathSimulator ${PathSimulator_LIBS})
 
-
-fc_target_copy_resource(PathSimulator 
-    ${CMAKE_SOURCE_DIR}/src/Mod/Path
-    ${CMAKE_BINARY_DIR}/Mod/Path
-    Init.py)
-
 SET_BIN_DIR(PathSimulator PathSimulator /Mod/Path)
 SET_PYTHON_PREFIX_SUFFIX(PathSimulator)
 

From cf20bdf108f62b683e7f0ebbdd0539b957dcfcd4 Mon Sep 17 00:00:00 2001
From: Ryan Pavlik <ryan.pavlik@gmail.com>
Date: Fri, 15 Jun 2018 12:02:56 -0500
Subject: [PATCH 27/33] Fix ninja warnings about duplicate rules for
 Mod/Web/Init.py

Both Web/App and Web/Gui were copying it.
---
 src/Mod/Web/Gui/CMakeLists.txt | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/Mod/Web/Gui/CMakeLists.txt b/src/Mod/Web/Gui/CMakeLists.txt
index d054d4787ec..1c7b1d17ace 100644
--- a/src/Mod/Web/Gui/CMakeLists.txt
+++ b/src/Mod/Web/Gui/CMakeLists.txt
@@ -51,8 +51,7 @@ target_link_libraries(WebGui ${WebGui_LIBS})
 fc_target_copy_resource(WebGui 
     ${CMAKE_SOURCE_DIR}/src/Mod/Web
     ${CMAKE_BINARY_DIR}/Mod/Web
-    ${Web_Scripts}
-    Init.py InitGui.py)
+    InitGui.py)
 
 SET_BIN_DIR(WebGui WebGui /Mod/Web)
 SET_PYTHON_PREFIX_SUFFIX(WebGui)

From 91fd37648da10ae829f3b1bf0fdee57a8284b379 Mon Sep 17 00:00:00 2001
From: Ryan Pavlik <ryan.pavlik@gmail.com>
Date: Fri, 15 Jun 2018 13:22:39 -0500
Subject: [PATCH 28/33] Quote paths used in FindPySideTools.cmake

---
 cMake/FindPySideTools.cmake | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/cMake/FindPySideTools.cmake b/cMake/FindPySideTools.cmake
index c6e64540de5..ca1d4fe0539 100644
--- a/cMake/FindPySideTools.cmake
+++ b/cMake/FindPySideTools.cmake
@@ -41,9 +41,9 @@ MACRO(PYSIDE_WRAP_UI outfiles)
         # pyside-uic generates in comments at beginning, which is why
         # we follow the tool command with in-place sed.
         ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
-          COMMAND ${PYSIDEUIC4BINARY} "${infile}" -o "${outfile}"
+          COMMAND "${PYSIDEUIC4BINARY}" "${infile}" -o "${outfile}"
           COMMAND sed -i "/^# /d" "${outfile}"
-          MAIN_DEPENDENCY ${infile}
+          MAIN_DEPENDENCY "${infile}"
         )
     endif(WIN32)
     list(APPEND ${outfiles} ${outfile})
@@ -72,10 +72,10 @@ MACRO(PYSIDE_WRAP_RC outfiles)
         # Especially on Open Build Service we don't want changing date like
         # pyside-rcc generates in comments at beginning, which is why
         # we follow the tool command with in-place sed.
-        ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
-          COMMAND ${PYSIDERCC4BINARY} "${infile}" ${PY_ATTRIBUTE} -o "${outfile}"
+        ADD_CUSTOM_COMMAND(OUTPUT "${outfile}"
+          COMMAND "${PYSIDERCC4BINARY}" "${infile}" ${PY_ATTRIBUTE} -o "${outfile}"
           COMMAND sed -i "/^# /d" "${outfile}"
-          MAIN_DEPENDENCY ${infile}
+          MAIN_DEPENDENCY "${infile}"
         )
     endif(WIN32)
     list(APPEND ${outfiles} ${outfile})

From fe7e6a3e2a0dd1073e44eeef9cb5ee405e67e2d9 Mon Sep 17 00:00:00 2001
From: Ryan Pavlik <ryan.pavlik@gmail.com>
Date: Fri, 15 Jun 2018 13:23:50 -0500
Subject: [PATCH 29/33] Fix typo in FreeCadMacros.cmake

---
 cMake/FreeCadMacros.cmake | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/cMake/FreeCadMacros.cmake b/cMake/FreeCadMacros.cmake
index bbf504f4356..6e2b7995e45 100644
--- a/cMake/FreeCadMacros.cmake
+++ b/cMake/FreeCadMacros.cmake
@@ -103,15 +103,15 @@ macro(copy_to_local_output_paths SOURCE_PATHS)
 		 endif(CMAKE_CFG_INTDIR STREQUAL .)
 		 file(TO_NATIVE_PATH ${SOURCE_PATHS} NATIVE_SOURCE)
 		 file(TO_NATIVE_PATH ${DEBUG_LOCAL_OUTPUT_PATH}/ NATIVE_DEBUG_DESTINATION)
-		 file(TO_NATIVE_PATH ${RELEASE_LOCAL_OUTPUT_PATH}/ NATIVE_RELESE_DESTINATION)
+		 file(TO_NATIVE_PATH ${RELEASE_LOCAL_OUTPUT_PATH}/ NATIVE_RELEASE_DESTINATION)
 		 message(STATUS "${PLATFORM_CP} ${NATIVE_SOURCE} ${NATIVE_DEBUG_DESTINATION}")
 		 execute_process(
 		 		 COMMAND ${PLATFORM_CP} ${NATIVE_SOURCE} ${NATIVE_DEBUG_DESTINATION}
 		 		 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 		 if(NOT ${DEBUG_LOCAL_OUTPUT_PATH} STREQUAL ${RELEASE_LOCAL_OUTPUT_PATH})
-		 		 message(STATUS "${PLATFORM_CP} ${NATIVE_SOURCE} ${NATIVE_RELESE_DESTINATION}")
+		 		 message(STATUS "${PLATFORM_CP} ${NATIVE_SOURCE} ${NATIVE_RELEASE_DESTINATION}")
 		 		 execute_process(
-		 		 		 COMMAND ${PLATFORM_CP} ${NATIVE_SOURCE} ${NATIVE_RELESE_DESTINATION}
+		 		 		 COMMAND ${PLATFORM_CP} ${NATIVE_SOURCE} ${NATIVE_RELEASE_DESTINATION}
 		 		 		 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 		 endif(NOT ${DEBUG_LOCAL_OUTPUT_PATH} STREQUAL ${RELEASE_LOCAL_OUTPUT_PATH})
 endmacro(copy_to_local_output_paths)
@@ -119,15 +119,15 @@ endmacro(copy_to_local_output_paths)
 macro(copy_to_main_output_paths SOURCE_PATHS)
 		 file(TO_NATIVE_PATH ${SOURCE_PATHS} NATIVE_SOURCE)
 		 file(TO_NATIVE_PATH ${DEBUG_MAIN_OUTPUT_PATH}/ NATIVE_DEBUG_DESTINATION)
-		 file(TO_NATIVE_PATH ${RELEASE_MAIN_OUTPUT_PATH}/ NATIVE_RELESE_DESTINATION)
+		 file(TO_NATIVE_PATH ${RELEASE_MAIN_OUTPUT_PATH}/ NATIVE_RELEASE_DESTINATION)
 		 message(STATUS "${PLATFORM_CP} ${NATIVE_SOURCE} ${NATIVE_DEBUG_DESTINATION}")
 		 execute_process(
 		 		 COMMAND ${PLATFORM_CP} ${NATIVE_SOURCE} ${NATIVE_DEBUG_DESTINATION}
 		 		 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 		 if(NOT ${DEBUG_MAIN_OUTPUT_PATH} STREQUAL ${RELEASE_MAIN_OUTPUT_PATH})
-		 		 message(STATUS "${PLATFORM_CP} ${NATIVE_SOURCE} ${NATIVE_RELESE_DESTINATION}")
+		 		 message(STATUS "${PLATFORM_CP} ${NATIVE_SOURCE} ${NATIVE_RELEASE_DESTINATION}")
 		 		 execute_process(
-		 		 		 COMMAND ${PLATFORM_CP} ${NATIVE_SOURCE} ${NATIVE_RELESE_DESTINATION}
+		 		 		 COMMAND ${PLATFORM_CP} ${NATIVE_SOURCE} ${NATIVE_RELEASE_DESTINATION}
 		 		 		 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 		 endif(NOT ${DEBUG_MAIN_OUTPUT_PATH} STREQUAL ${RELEASE_MAIN_OUTPUT_PATH})
 endmacro(copy_to_main_output_paths)
@@ -146,12 +146,10 @@ macro(generate_from_xml BASE_NAME)
     file(TO_NATIVE_PATH "${OUTPUT_PATH}" OUTPUT_NATIVE_PATH)
     if(NOT EXISTS "${SOURCE_CPP_PATH}")
         # assures the source files are generated at least once
-        
         execute_process(COMMAND "${PYTHON_EXECUTABLE}" "${TOOL_NATIVE_PATH}" --outputPath "${OUTPUT_NATIVE_PATH}" "${SOURCE_NATIVE_PATH}"
                         WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
         )
     endif()
-
     add_custom_command(
         OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${BASE_NAME}.h" "${CMAKE_CURRENT_BINARY_DIR}/${BASE_NAME}.cpp"
         COMMAND ${PYTHON_EXECUTABLE} "${TOOL_NATIVE_PATH}" --outputPath "${OUTPUT_NATIVE_PATH}" ${BASE_NAME}.xml

From 42e5f287e9f882a961a50d702db01abf0496a727 Mon Sep 17 00:00:00 2001
From: Ryan Pavlik <ryan.pavlik@gmail.com>
Date: Fri, 15 Jun 2018 13:44:28 -0500
Subject: [PATCH 30/33] Apply equivalent changes to FindPySide2Tools as
 FindPySideTools.

These are largely matching files, potential to de-duplicate them, but this
just ports the changes over for now.
---
 cMake/FindPySide2Tools.cmake | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/cMake/FindPySide2Tools.cmake b/cMake/FindPySide2Tools.cmake
index 89044043138..a8894cdfc81 100644
--- a/cMake/FindPySide2Tools.cmake
+++ b/cMake/FindPySide2Tools.cmake
@@ -38,14 +38,15 @@ MACRO(PYSIDE_WRAP_UI outfiles)
         )
     else(WIN32)
         # Especially on Open Build Service we don't want changing date like
-        # pyside2-uic generates in comments at beginning.
-        EXECUTE_PROCESS(
-          COMMAND ${PYSIDE2UICBINARY} ${infile}
-          COMMAND sed "/^# /d"
-          OUTPUT_FILE ${outfile}
+        # pyside2-uic generates in comments at beginning., which is why
+        # we follow the tool command with in-place sed.
+        ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
+          COMMAND "${PYSIDE2UICBINARY}" "${infile}" -o "${outfile}"
+          COMMAND sed -i "/^# /d" "${outfile}"
+          MAIN_DEPENDENCY "${infile}"
         )
     endif(WIN32)
-    SET(${outfiles} ${${outfiles}} ${outfile})
+    list(APPEND ${outfiles} ${outfile})
   ENDFOREACH(it)
 ENDMACRO (PYSIDE_WRAP_UI)
 
@@ -53,7 +54,7 @@ MACRO(PYSIDE_WRAP_RC outfiles)
   FOREACH(it ${ARGN})
     GET_FILENAME_COMPONENT(outfile ${it} NAME_WE)
     GET_FILENAME_COMPONENT(infile ${it} ABSOLUTE)
-    SET(outfile ${CMAKE_CURRENT_BINARY_DIR}/${outfile}_rc.py)
+    SET(outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}_rc.py")
     #ADD_CUSTOM_TARGET(${it} ALL
     #  DEPENDS ${outfile}
     #)
@@ -64,14 +65,15 @@ MACRO(PYSIDE_WRAP_RC outfiles)
         )
     else(WIN32)
         # Especially on Open Build Service we don't want changing date like
-        # pyside2-rcc generates in comments at beginning.
-        EXECUTE_PROCESS(
-          COMMAND ${PYSIDE2RCCBINARY} ${infile}
-          COMMAND sed "/^# /d"
-          OUTPUT_FILE ${outfile}
-       )
+        # pyside-rcc generates in comments at beginning, which is why
+        # we follow the tool command with in-place sed.
+        ADD_CUSTOM_COMMAND(OUTPUT "${outfile}"
+          COMMAND "${PYSIDE2RCCBINARY}" "${infile}" ${PY_ATTRIBUTE} -o "${outfile}"
+          COMMAND sed -i "/^# /d" "${outfile}"
+          MAIN_DEPENDENCY "${infile}"
+        )
     endif(WIN32)
-    SET(${outfiles} ${${outfiles}} ${outfile})
+    list(APPEND ${outfiles} ${outfile})
   ENDFOREACH(it)
 ENDMACRO (PYSIDE_WRAP_RC)
 

From 9948ee4f1570df9216862a79705afb367b2c6ffb Mon Sep 17 00:00:00 2001
From: Peter Lama <peterldev94@gmail.com>
Date: Tue, 14 Aug 2018 19:47:23 -0700
Subject: [PATCH 31/33] Fix build error on MacOS due to sed command usage

Non GNU sed on macOS expects suffix after -i option (can be empty str).
However, removing the comments from the pyside generated files is not a necessary
operation (presumably done to avoid a diff when no code changed), so simply skip the operation on macOS
---
 cMake/FindPySide2Tools.cmake | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/cMake/FindPySide2Tools.cmake b/cMake/FindPySide2Tools.cmake
index a8894cdfc81..9c975148887 100644
--- a/cMake/FindPySide2Tools.cmake
+++ b/cMake/FindPySide2Tools.cmake
@@ -31,12 +31,12 @@ MACRO(PYSIDE_WRAP_UI outfiles)
     #ADD_CUSTOM_TARGET(${it} ALL
     #  DEPENDS ${outfile}
     #)
-    if(WIN32)
+    if(WIN32 OR APPLE)
         ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
           COMMAND ${PYSIDE2UICBINARY} ${infile} -o ${outfile}
           MAIN_DEPENDENCY ${infile}
         )
-    else(WIN32)
+    else()
         # Especially on Open Build Service we don't want changing date like
         # pyside2-uic generates in comments at beginning., which is why
         # we follow the tool command with in-place sed.
@@ -45,7 +45,7 @@ MACRO(PYSIDE_WRAP_UI outfiles)
           COMMAND sed -i "/^# /d" "${outfile}"
           MAIN_DEPENDENCY "${infile}"
         )
-    endif(WIN32)
+    endif()
     list(APPEND ${outfiles} ${outfile})
   ENDFOREACH(it)
 ENDMACRO (PYSIDE_WRAP_UI)
@@ -58,12 +58,12 @@ MACRO(PYSIDE_WRAP_RC outfiles)
     #ADD_CUSTOM_TARGET(${it} ALL
     #  DEPENDS ${outfile}
     #)
-    if(WIN32)
+    if(WIN32 OR APPLE)
         ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
           COMMAND ${PYSIDE2RCCBINARY} ${infile} -o ${outfile}
           MAIN_DEPENDENCY ${infile}
         )
-    else(WIN32)
+    else()
         # Especially on Open Build Service we don't want changing date like
         # pyside-rcc generates in comments at beginning, which is why
         # we follow the tool command with in-place sed.
@@ -72,7 +72,7 @@ MACRO(PYSIDE_WRAP_RC outfiles)
           COMMAND sed -i "/^# /d" "${outfile}"
           MAIN_DEPENDENCY "${infile}"
         )
-    endif(WIN32)
+    endif()
     list(APPEND ${outfiles} ${outfile})
   ENDFOREACH(it)
 ENDMACRO (PYSIDE_WRAP_RC)

From b484ae84148bc5301d233f6ebc53f3789f7524f8 Mon Sep 17 00:00:00 2001
From: Eivind Kvedalen <eivind@kvedalen.name>
Date: Sun, 29 Jul 2018 19:37:23 +0200
Subject: [PATCH 32/33] Revert "fixes #0003361: Spreadsheet: Inserting Row
 Cause Crash - FC Daily v0.17"

This reverts commit f485a0786f238b1c555b2dc8a5d511d5cf8c3e24.
---
 src/Mod/Spreadsheet/App/PropertySheet.cpp | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/src/Mod/Spreadsheet/App/PropertySheet.cpp b/src/Mod/Spreadsheet/App/PropertySheet.cpp
index c277340d77c..051834d183b 100644
--- a/src/Mod/Spreadsheet/App/PropertySheet.cpp
+++ b/src/Mod/Spreadsheet/App/PropertySheet.cpp
@@ -358,9 +358,7 @@ Cell * PropertySheet::cellAt(CellAddress address)
     // address actually inside a merged cell
     if (j != mergedCells.end()) {
         std::map<CellAddress, Cell*>::const_iterator i = data.find(j->second);
-        //assert(i != data.end());
-        if (i == data.end())
-            return nullptr;
+        assert(i != data.end());
 
         return i->second;
     }
@@ -380,9 +378,7 @@ const Cell * PropertySheet::cellAt(CellAddress address) const
     // address actually inside a merged cell
     if (j != mergedCells.end()) {
         std::map<CellAddress, Cell*>::const_iterator i = data.find(j->second);
-        //assert(i != data.end());
-        if (i == data.end())
-            return nullptr;
+        assert(i != data.end());
 
         return i->second;
     }
@@ -889,9 +885,7 @@ void PropertySheet::getSpans(CellAddress address, int & rows, int & cols) const
     if (i != mergedCells.end()) {
         CellAddress anchor = i->second;
 
-        const Cell* cell = cellAt(anchor);
-        if (cell)
-            cell->getSpans(rows, cols);
+        cellAt(anchor)->getSpans(rows, cols);
     }
     else {
         rows = cols = 1;

From 549e8ec8070b6e3064d606010a26e8033d239a99 Mon Sep 17 00:00:00 2001
From: Eivind Kvedalen <eivind@kvedalen.name>
Date: Tue, 31 Jul 2018 00:57:23 +0200
Subject: [PATCH 33/33] Spreadsheet: Fixed issue #3361.

---
 src/Mod/Spreadsheet/App/Cell.cpp          |  4 ++--
 src/Mod/Spreadsheet/App/PropertySheet.cpp | 23 +++++++++++++++++++++--
 2 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/src/Mod/Spreadsheet/App/Cell.cpp b/src/Mod/Spreadsheet/App/Cell.cpp
index e99cb0086f5..d23d04cbd2c 100644
--- a/src/Mod/Spreadsheet/App/Cell.cpp
+++ b/src/Mod/Spreadsheet/App/Cell.cpp
@@ -461,8 +461,8 @@ void Cell::setSpans(int rows, int columns)
     if (rows != rowSpan || columns != colSpan) {
         PropertySheet::AtomicPropertyChange signaller(*owner);
 
-        rowSpan = rows;
-        colSpan = columns;
+        rowSpan = (rows == -1 ? 1 : rows);
+        colSpan = (columns == -1 ? 1 : columns);
         setUsed(SPANS_SET, (rowSpan != 1 || colSpan != 1) );
         setUsed(SPANS_UPDATED);
     }
diff --git a/src/Mod/Spreadsheet/App/PropertySheet.cpp b/src/Mod/Spreadsheet/App/PropertySheet.cpp
index 051834d183b..4e9c26dde5d 100644
--- a/src/Mod/Spreadsheet/App/PropertySheet.cpp
+++ b/src/Mod/Spreadsheet/App/PropertySheet.cpp
@@ -552,7 +552,14 @@ void PropertySheet::moveCell(CellAddress currPos, CellAddress newPos, std::map<A
 
     if (i != data.end()) {
         Cell * cell = i->second;
+        int rows, columns;
 
+        // Get merged cell data
+        cell->getSpans(rows, columns);
+
+        // Remove merged cell data
+        splitCell(currPos);
+        
         // Remove from old
         removeDependencies(currPos);
         data.erase(currPos);
@@ -561,6 +568,15 @@ void PropertySheet::moveCell(CellAddress currPos, CellAddress newPos, std::map<A
         // Insert into new spot
         cell->moveAbsolute(newPos);
         data[newPos] = cell;
+
+        if (rows > 1 || columns > 1) {
+            CellAddress toPos(newPos.row() + rows - 1, newPos.col() + columns - 1);
+
+            mergeCells(newPos, toPos);
+        }
+        else
+            cell->setSpans(-1, -1);
+
         addDependencies(newPos);
         setDirty(newPos);
 
@@ -875,7 +891,7 @@ void PropertySheet::splitCell(CellAddress address)
             mergedCells.erase(CellAddress(r, c));
         }
 
-    setSpans(anchor, 1, 1);
+    setSpans(anchor, -1, -1);
 }
 
 void PropertySheet::getSpans(CellAddress address, int & rows, int & cols) const
@@ -885,7 +901,10 @@ void PropertySheet::getSpans(CellAddress address, int & rows, int & cols) const
     if (i != mergedCells.end()) {
         CellAddress anchor = i->second;
 
-        cellAt(anchor)->getSpans(rows, cols);
+        if (anchor == address)
+            cellAt(anchor)->getSpans(rows, cols);
+        else
+            rows = cols = 1;
     }
     else {
         rows = cols = 1;