From bc585031a3f6934e8d13b7524603404a4eeca4eb Mon Sep 17 00:00:00 2001 From: luz paz Date: Mon, 13 Sep 2021 08:10:20 -0400 Subject: [PATCH 001/133] Crowdin: Fixes to Mesh WB translations Closes https://github.com/FreeCAD/FreeCAD-translations/issues/54 Exposes Mesh -> 'Cutting' sub-menu --- src/Mod/Mesh/Gui/Workbench.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mod/Mesh/Gui/Workbench.cpp b/src/Mod/Mesh/Gui/Workbench.cpp index 198a02fb73..822d6cdbfc 100644 --- a/src/Mod/Mesh/Gui/Workbench.cpp +++ b/src/Mod/Mesh/Gui/Workbench.cpp @@ -45,6 +45,7 @@ using namespace MeshGui; qApp->translate("Workbench", "Analyze"); qApp->translate("Workbench", "Boolean"); qApp->translate("Workbench", "&Meshes"); + qApp->translate("Workbench", "Cutting"); qApp->translate("Workbench", "Mesh tools"); #endif From 742f06a9831618af9ba3c3b928ab10fe24c05b82 Mon Sep 17 00:00:00 2001 From: luz paz Date: Mon, 13 Sep 2021 08:26:13 -0400 Subject: [PATCH 002/133] Mesh: remove superfluous whitespace + Improve readability of code --- src/Mod/MeshPart/Gui/MeshFlatteningCommand.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py b/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py index ed0d1aec6e..404278f1ad 100644 --- a/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py +++ b/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py @@ -19,7 +19,9 @@ class CreateFlatMesh(BaseCommand): """create flat wires from a meshed face""" def GetResources(self): - return {'Pixmap': 'MeshPart_CreateFlatMesh.svg', 'MenuText': 'Unwrap Mesh', 'ToolTip': 'find a flat representation of a mesh'} + return {'Pixmap': 'MeshPart_CreateFlatMesh.svg', + 'MenuText': 'Unwrap Mesh', + 'ToolTip': 'find a flat representation of a mesh'} def Activated(self): import numpy as np @@ -47,10 +49,12 @@ class CreateFlatMesh(BaseCommand): class CreateFlatFace(BaseCommand): """create a flat face from a single face only full faces are supported right now""" - + def GetResources(self): - return {'Pixmap': 'MeshPart_CreateFlatFace.svg', 'MenuText': 'Unwrap Face', 'ToolTip': 'find a flat representation of a mesh'} - + return {'Pixmap': 'MeshPart_CreateFlatFace.svg', + 'MenuText': 'Unwrap Face', + 'ToolTip': 'find a flat representation of a mesh'} + def Activated(self): import numpy as np import flatmesh @@ -74,12 +78,14 @@ class CreateFlatFace(BaseCommand): bs.setPole(u + 1, v + 1, App.Vector(poles[i])) i += 1 Part.show(bs.toShape()) - + def IsActive(self): assert(super(CreateFlatFace, self).IsActive()) assert(isinstance(Gui.Selection.getSelectionEx()[0].SubObjects[0], Part.Face)) return True + +# Test if pybind11 dependency is available try: import flatmesh Gui.addCommand('MeshPart_CreateFlatMesh', CreateFlatMesh()) From 6ff3dd2e575988da32ffc6273b9fd052baf24636 Mon Sep 17 00:00:00 2001 From: luz paz Date: Mon, 13 Sep 2021 08:22:02 -0400 Subject: [PATCH 003/133] Mesh: added license header to MeshFlatteningCommand.py --- src/Mod/MeshPart/Gui/MeshFlatteningCommand.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py b/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py index 404278f1ad..55ed1dbeaf 100644 --- a/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py +++ b/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py @@ -1,3 +1,26 @@ +#************************************************************************** +#* Copyright (c) * +#* * +#* This file is part of the FreeCAD CAx development system. * +#* * +#* This library is free software; you can redistribute it and/or * +#* modify it under the terms of the GNU Library General Public * +#* License as published by the Free Software Foundation; either * +#* version 2 of the License, or (at your option) any later version. * +#* * +#* This library is distributed in the hope that it will be useful, * +#* but WITHOUT ANY WARRANTY; without even the implied warranty of * +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +#* GNU Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * +#* License along with this library; see the file COPYING.LIB. If not, * +#* write to the Free Software Foundation, Inc., 59 Temple Place, * +#* Suite 330, Boston, MA 02111-1307, USA * +#* * +#**************************************************************************/ + + import Mesh import FreeCAD as App import FreeCADGui as Gui From 9f3a41887f426d4daa7fc549f96bdeee40d3aeb1 Mon Sep 17 00:00:00 2001 From: luz paz Date: Tue, 14 Sep 2021 17:32:47 -0400 Subject: [PATCH 004/133] Mesh: added attribution to @looooo in MeshFlatteningCommand.py --- src/Mod/MeshPart/Gui/MeshFlatteningCommand.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py b/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py index 55ed1dbeaf..36031f524b 100644 --- a/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py +++ b/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py @@ -1,5 +1,5 @@ #************************************************************************** -#* Copyright (c) * +#* Copyright (c) 2017 Lorenz Lechner * #* * #* This file is part of the FreeCAD CAx development system. * #* * From 94dda1621ac4000239a941f54cf0d1720b013df0 Mon Sep 17 00:00:00 2001 From: luz paz Date: Wed, 20 Oct 2021 08:53:45 -0400 Subject: [PATCH 005/133] Mesh: Apply the translation function appropriately --- src/Mod/MeshPart/Gui/MeshFlatteningCommand.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py b/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py index 36031f524b..ff442d2d90 100644 --- a/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py +++ b/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py @@ -20,13 +20,14 @@ #* * #**************************************************************************/ - import Mesh import FreeCAD as App import FreeCADGui as Gui import Part import MeshPartGui +from PySide.QtCore import QT_TRANSLATE_NOOP # for translations + class BaseCommand(object): def __init__(self): pass @@ -43,8 +44,8 @@ class CreateFlatMesh(BaseCommand): def GetResources(self): return {'Pixmap': 'MeshPart_CreateFlatMesh.svg', - 'MenuText': 'Unwrap Mesh', - 'ToolTip': 'find a flat representation of a mesh'} + 'MenuText': QT_TRANSLATE_NOOP("MeshPart_FlatteningCommand", "Unwrap Mesh"), + 'ToolTip': QT_TRANSLATE_NOOP("MeshPart_FlatteningCommand", "Find a flat representation of a mesh.")} def Activated(self): import numpy as np @@ -75,8 +76,8 @@ class CreateFlatFace(BaseCommand): def GetResources(self): return {'Pixmap': 'MeshPart_CreateFlatFace.svg', - 'MenuText': 'Unwrap Face', - 'ToolTip': 'find a flat representation of a mesh'} + 'MenuText': QT_TRANSLATE_NOOP("MeshPart_FlatteningCommand", "Unwrap Face"), + 'ToolTip': QT_TRANSLATE_NOOP("MeshPart_FlatteningCommand", "Find a flat representation of a mesh.")} def Activated(self): import numpy as np From 4c129c752610ad0f52bb20306e70c186bb63dd2d Mon Sep 17 00:00:00 2001 From: sliptonic Date: Mon, 15 Nov 2021 18:31:35 -0600 Subject: [PATCH 006/133] face outerwires aren't always the first wire in the Wires list. Added logic to compare hashCodes() https://forum.freecadweb.org/viewtopic.php?f=13&t=50567 --- src/Mod/Path/PathScripts/PathProfile.py | 92 ++++++++++++++----------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathProfile.py b/src/Mod/Path/PathScripts/PathProfile.py index d68066ca0b..2b786e1079 100644 --- a/src/Mod/Path/PathScripts/PathProfile.py +++ b/src/Mod/Path/PathScripts/PathProfile.py @@ -48,7 +48,11 @@ __doc__ = ( ) __contributors__ = "Schildkroet" -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) # Qt translation handling @@ -73,7 +77,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): def initAreaOpProperties(self, obj, warn=False): """initAreaOpProperties(obj) ... create operation specific properties""" - self.addNewProps = list() + self.addNewProps = [] for (prtyp, nm, grp, tt) in self.areaOpProperties(): if not hasattr(obj, nm): @@ -342,10 +346,9 @@ class ObjectProfile(PathAreaOp.ObjectOp): def areaOpShapes(self, obj): """areaOpShapes(obj) ... returns envelope for all base shapes or wires""" - PathLog.track() shapes = [] - remainingObjBaseFeatures = list() + remainingObjBaseFeatures = [] self.isDebug = True if PathLog.getLevel(PathLog.thisModule()) == 4 else False self.inaccessibleMsg = translate( "PathProfile", @@ -383,10 +386,12 @@ class ObjectProfile(PathAreaOp.ObjectOp): obj.Base and len(obj.Base) > 0 ): # The user has selected subobjects from the base. Process each. shapes.extend(self._processEdges(obj, remainingObjBaseFeatures)) + PathLog.track("returned {} shapes".format(len(shapes))) + PathLog.track(remainingObjBaseFeatures) if obj.Base and len(obj.Base) > 0 and not remainingObjBaseFeatures: # Edges were already processed, or whole model targeted. - PathLog.debug("remainingObjBaseFeatures is False") + PathLog.track("remainingObjBaseFeatures is False") elif ( remainingObjBaseFeatures and len(remainingObjBaseFeatures) > 0 ): # Process remaining features after edges processed above. @@ -403,12 +408,15 @@ class ObjectProfile(PathAreaOp.ObjectOp): if numpy.isclose( abs(shape.normalAt(0, 0).z), 1 ): # horizontal face - for wire in shape.Wires[1:]: + for wire in shape.Wires: + if wire.hashCode() == shape.OuterWire.hashCode(): + continue holes.append((base.Shape, wire)) # Add face depth to list faceDepths.append(shape.BoundBox.ZMin) else: + PathLog.track() ignoreSub = base.Name + "." + sub msg = translate( "PathProfile", @@ -475,6 +483,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): else: # Try to build targets from the job models # No base geometry selected, so treating operation like a exterior contour operation + PathLog.track() self.opUpdateDepths(obj) if 1 == len(self.model) and hasattr(self.model[0], "Proxy"): @@ -498,7 +507,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): # Method to handle each model as a whole, when no faces are selected def _processEachModel(self, obj): - shapeTups = list() + shapeTups = [] for base in self.model: if hasattr(base, "Shape"): env = PathUtils.getEnvelope( @@ -510,22 +519,22 @@ class ObjectProfile(PathAreaOp.ObjectOp): # Edges pre-processing def _processEdges(self, obj, remainingObjBaseFeatures): - shapes = list() - basewires = list() + PathLog.track("remainingObjBaseFeatures: {}".format(remainingObjBaseFeatures)) + shapes = [] + basewires = [] ezMin = None self.cutOut = self.tool.Diameter - for p in range(0, len(obj.Base)): - (base, subsList) = obj.Base[p] - keepFaces = list() - edgelist = list() + for base, subsList in obj.Base: + keepFaces = [] + edgelist = [] for sub in subsList: shape = getattr(base.Shape, sub) # extract and process edges if isinstance(shape, Part.Edge): edgelist.append(getattr(base.Shape, sub)) # save faces for regular processing - if isinstance(shape, Part.Face): + elif isinstance(shape, Part.Face): keepFaces.append(sub) if len(edgelist) > 0: basewires.append((base, DraftGeomUtils.findWires(edgelist))) @@ -535,6 +544,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): if len(keepFaces) > 0: # save faces for returning and processing remainingObjBaseFeatures.append((base, keepFaces)) + PathLog.track(basewires) for base, wires in basewires: for wire in wires: if wire.isClosed(): @@ -569,7 +579,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): zDiff = math.fabs(wire.BoundBox.ZMin - obj.FinalDepth.Value) if flattened and zDiff >= self.JOB.GeometryTolerance.Value: cutWireObjs = False - openEdges = list() + openEdges = [] passOffsets = [self.ofstRadius] (origWire, flatWire) = flattened @@ -708,8 +718,8 @@ class ObjectProfile(PathAreaOp.ObjectOp): self._addDebugObject("CutArea", cutArea) # Get top and bottom faces of cut area (CA), and combine faces when necessary - topFc = list() - botFc = list() + topFc = [] + botFc = [] bbZMax = cutArea.BoundBox.ZMax bbZMin = cutArea.BoundBox.ZMin for f in range(0, len(cutArea.Faces)): @@ -872,9 +882,9 @@ class ObjectProfile(PathAreaOp.ObjectOp): def _extractPathWire(self, obj, base, flatWire, cutShp): PathLog.debug("_extractPathWire()") - subLoops = list() - rtnWIRES = list() - osWrIdxs = list() + subLoops = [] + rtnWIRES = [] + osWrIdxs = [] subDistFactor = ( 1.0 # Raise to include sub wires at greater distance from original ) @@ -897,10 +907,10 @@ class ObjectProfile(PathAreaOp.ObjectOp): pass else: PathLog.error("No area to offset shape returned.") - return list() + return [] except Exception as ee: PathLog.error("No area to offset shape returned.\n{}".format(ee)) - return list() + return [] self._addDebugObject("OffsetShape", ofstShp) @@ -909,7 +919,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): osWrIdxs.append(w) # Identify two vertexes for dividing offset loop - NEAR0 = self._findNearestVertex(ofstShp, cent0) + NEAR0 = self._findNearestVertex(ofstShp, cent0) # min0i = 0 min0 = NEAR0[0][4] for n in range(0, len(NEAR0)): @@ -921,7 +931,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): near0Shp = Part.makeLine(cent0, pnt0) self._addDebugObject("Near0", near0Shp) - NEAR1 = self._findNearestVertex(ofstShp, cent1) + NEAR1 = self._findNearestVertex(ofstShp, cent1) # min1i = 0 min1 = NEAR1[0][4] for n in range(0, len(NEAR1)): @@ -941,7 +951,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): ) # Debugging - ''' + """ if self.isDebug: PathLog.debug('min0i is {}.'.format(min0i)) PathLog.debug('min1i is {}.'.format(min1i)) @@ -949,14 +959,14 @@ class ObjectProfile(PathAreaOp.ObjectOp): PathLog.debug('NEAR1[{}] is {}.'.format(w1, NEAR1[w1])) PathLog.debug('NEAR0 is {}.'.format(NEAR0)) PathLog.debug('NEAR1 is {}.'.format(NEAR1)) - ''' + """ mainWire = ofstShp.Wires[w0] # Check for additional closed loops in offset wire by checking distance to iTAG or eTAG elements if numOSWires > 1: # check all wires for proximity(children) to intersection tags - tagsComList = list() + tagsComList = [] for T in self.cutSideTags.Faces: tcom = T.CenterOfMass tv = FreeCAD.Vector(tcom.x, tcom.y, 0.0) @@ -987,8 +997,8 @@ class ObjectProfile(PathAreaOp.ObjectOp): except Exception as ee: PathLog.error("Failed to identify offset edge.\n{}".format(ee)) return False - edgs0 = list() - edgs1 = list() + edgs0 = [] + edgs1 = [] for e in edgeIdxs0: edgs0.append(mainWire.Edges[e]) for e in edgeIdxs1: @@ -1030,7 +1040,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): def sortDist(tup): return tup[4] - PNTS = list() + PNTS = [] for w in range(0, len(shape.Wires)): WR = shape.Wires[w] V = WR.Vertexes[0] @@ -1061,7 +1071,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): V2 = FreeCAD.Vector(VV2.X, VV2.Y, VV2.Z) lenE = len(wire.Edges) - FLGS = list() + FLGS = [] for e in range(0, lenE): FLGS.append(0) @@ -1098,11 +1108,11 @@ class ObjectProfile(PathAreaOp.ObjectOp): # PathLog.debug('_separateWireAtVertexes() FLGS: {}'.format(FLGS)) - PRE = list() - POST = list() - IDXS = list() - IDX1 = list() - IDX2 = list() + PRE = [] + POST = [] + IDXS = [] + IDX1 = [] + IDX2 = [] for e in range(0, lenE): f = FLGS[e] PRE.append(f) @@ -1174,7 +1184,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): # Eif # Debugging - ''' + """ if self.isDebug: PathLog.debug('grps[0]: {}'.format(grps[0])) PathLog.debug('grps[1]: {}'.format(grps[1])) @@ -1182,7 +1192,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): PathLog.debug('wireIdxs[1]: {}'.format(wireIdxs[1])) PathLog.debug('PRE: {}'.format(PRE)) PathLog.debug('IDXS: {}'.format(IDXS)) - ''' + """ return (wireIdxs[0], wireIdxs[1]) def _makeCrossSection(self, shape, sliceZ, zHghtTrgt=False): @@ -1191,7 +1201,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): Makes face shape from cross-section object. Returns face shape at zHghtTrgt.""" PathLog.debug("_makeCrossSection()") # Create cross-section of shape and translate - wires = list() + wires = [] slcs = shape.slice(FreeCAD.Vector(0, 0, 1), sliceZ) if len(slcs) > 0: for i in slcs: @@ -1220,8 +1230,8 @@ class ObjectProfile(PathAreaOp.ObjectOp): def _makeIntersectionTags(self, useWire, numOrigEdges, fdv): PathLog.debug("_makeIntersectionTags()") # Create circular probe tags around perimiter of wire - extTags = list() - intTags = list() + extTags = [] + intTags = [] tagRad = self.radius / 2 tagCnt = 0 begInt = False From a70d4a53cf6d164772731928f1b1512544e566bd Mon Sep 17 00:00:00 2001 From: Roy-043 <70520633+Roy-043@users.noreply.github.com> Date: Tue, 16 Nov 2021 16:35:34 +0100 Subject: [PATCH 007/133] Draft housekeeping: import is_group and get_windows in Draft.py --- src/Mod/Draft/Draft.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 992fb7c418..1307af47a8 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -120,9 +120,11 @@ from draftutils.gui_utils import (dim_symbol, dim_dash, dimDash) -from draftutils.groups import (get_group_names, +from draftutils.groups import (is_group + get_group_names, getGroupNames, ungroup, + get_windows get_group_contents, getGroupContents, get_movable_children, From 067f533928943c449c91b3c43266873026e3754c Mon Sep 17 00:00:00 2001 From: Roy-043 <70520633+Roy-043@users.noreply.github.com> Date: Tue, 16 Nov 2021 16:49:30 +0100 Subject: [PATCH 008/133] Draft housekeeping: SS-shortcut used twice --- src/Mod/Draft/draftguitools/gui_shapestrings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Mod/Draft/draftguitools/gui_shapestrings.py b/src/Mod/Draft/draftguitools/gui_shapestrings.py index c8ff4528be..5795b3f5ca 100644 --- a/src/Mod/Draft/draftguitools/gui_shapestrings.py +++ b/src/Mod/Draft/draftguitools/gui_shapestrings.py @@ -64,7 +64,6 @@ class ShapeString(gui_base_original.Creator): """Set icon, menu and tooltip.""" d = {'Pixmap': 'Draft_ShapeString', - 'Accel': "S, S", 'MenuText': QT_TRANSLATE_NOOP("Draft_ShapeString", "Shape from text"), 'ToolTip': QT_TRANSLATE_NOOP("Draft_ShapeString", "Creates a shape from a text string by choosing a specific font and a placement.\nThe closed shapes can be used for extrusions and boolean operations.")} return d From f548494e4a5f29e15227c0d11129e740688878ca Mon Sep 17 00:00:00 2001 From: Roy-043 <70520633+Roy-043@users.noreply.github.com> Date: Tue, 16 Nov 2021 17:00:54 +0100 Subject: [PATCH 009/133] Draft: fix array issue with Draft_Point and Part_Vertex --- src/Mod/Draft/draftobjects/draftlink.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Mod/Draft/draftobjects/draftlink.py b/src/Mod/Draft/draftobjects/draftlink.py index 5437a67dbf..d230977acd 100644 --- a/src/Mod/Draft/draftobjects/draftlink.py +++ b/src/Mod/Draft/draftobjects/draftlink.py @@ -187,8 +187,9 @@ class DraftLink(DraftObject): "from '{}'\n".format(obj.Label, obj.Base.Label)) raise RuntimeError(_err_msg) else: - shape = shape.copy() - shape.Placement = App.Placement() + # Resetting the Placement of the copied shape does not work for + # Part_Vertex and Draft_Point objects, we need to transform: + shape = shape.transformGeometry(shape.Placement.Matrix.inverse()) base = [] for i, pla in enumerate(pls): vis = getattr(obj, 'VisibilityList', []) From 9a467f39d19c59b05a7634422464dad7c9792c97 Mon Sep 17 00:00:00 2001 From: Roy-043 <70520633+Roy-043@users.noreply.github.com> Date: Wed, 17 Nov 2021 19:26:36 +0100 Subject: [PATCH 010/133] Draft: fix toggle grid issue. --- src/Mod/Draft/draftguitools/gui_snapper.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_snapper.py b/src/Mod/Draft/draftguitools/gui_snapper.py index b396e7fdb1..7e582bf3fa 100644 --- a/src/Mod/Draft/draftguitools/gui_snapper.py +++ b/src/Mod/Draft/draftguitools/gui_snapper.py @@ -265,10 +265,6 @@ class Snapper: # Setup trackers if needed self.setTrackers() - # Show the grid if it's off (new view, for ex) - if self.grid and Draft.getParam("grid", True): - self.grid.on() - # Get current snap radius self.radius = self.getScreenDist(Draft.getParam("snapRange", 8), screenpos) From 508df647326c4ae9f221a3839d688f3ba07f0743 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 19 Nov 2021 12:51:13 +0100 Subject: [PATCH 011/133] Gui: [skip ci] add sub-classes of the MDIView to the type system --- src/Gui/Application.cpp | 3 +++ src/Gui/EditorView.cpp | 4 ++++ src/Gui/EditorView.h | 4 ++++ src/Mod/Image/Gui/AppImageGui.cpp | 2 ++ src/Mod/Image/Gui/ImageView.cpp | 2 ++ src/Mod/Image/Gui/ImageView.h | 2 ++ src/Mod/Web/Gui/AppWebGui.cpp | 1 + src/Mod/Web/Gui/BrowserView.cpp | 2 ++ src/Mod/Web/Gui/BrowserView.h | 4 +++- 9 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 7e197b646c..94e2cb47e4 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -99,6 +99,7 @@ #include "ExpressionBindingPy.h" #include "ViewProviderLinkPy.h" +#include "EditorView.h" #include "TextDocumentEditorView.h" #include "SplitView3DInventor.h" #include "View3DInventor.h" @@ -1782,6 +1783,8 @@ void Application::initTypes(void) Gui::AbstractSplitView ::init(); Gui::SplitView3DInventor ::init(); Gui::TextDocumentEditorView ::init(); + Gui::EditorView ::init(); + Gui::PythonEditorView ::init(); // View Provider Gui::ViewProvider ::init(); Gui::ViewProviderExtension ::init(); diff --git a/src/Gui/EditorView.cpp b/src/Gui/EditorView.cpp index 196a077085..1ad2f0c972 100644 --- a/src/Gui/EditorView.cpp +++ b/src/Gui/EditorView.cpp @@ -83,6 +83,8 @@ public: /* TRANSLATOR Gui::EditorView */ +TYPESYSTEM_SOURCE_ABSTRACT(Gui::EditorView, Gui::MDIView) + /** * Constructs a EditorView which is a child of 'parent', with the * name 'name'. @@ -586,6 +588,8 @@ void EditorView::focusInEvent (QFocusEvent *) // --------------------------------------------------------- +TYPESYSTEM_SOURCE_ABSTRACT(Gui::PythonEditorView, Gui::EditorView) + PythonEditorView::PythonEditorView(PythonEditor* editor, QWidget* parent) : EditorView(editor, parent), _pye(editor) { diff --git a/src/Gui/EditorView.h b/src/Gui/EditorView.h index 80882adb41..cc249fe2aa 100644 --- a/src/Gui/EditorView.h +++ b/src/Gui/EditorView.h @@ -49,6 +49,8 @@ class GuiExport EditorView : public MDIView, public WindowParameter { Q_OBJECT + TYPESYSTEM_HEADER(); + public: enum DisplayName { FullName, @@ -118,6 +120,8 @@ class GuiExport PythonEditorView : public EditorView { Q_OBJECT + TYPESYSTEM_HEADER(); + public: PythonEditorView(PythonEditor* editor, QWidget* parent); ~PythonEditorView(); diff --git a/src/Mod/Image/Gui/AppImageGui.cpp b/src/Mod/Image/Gui/AppImageGui.cpp index 3c4050a813..5c1300a167 100644 --- a/src/Mod/Image/Gui/AppImageGui.cpp +++ b/src/Mod/Image/Gui/AppImageGui.cpp @@ -18,6 +18,7 @@ #include #include #include +#include "ImageView.h" #include "Workbench.h" #include "ViewProviderImagePlane.h" @@ -50,6 +51,7 @@ PyMOD_INIT_FUNC(ImageGui) // instantiating the commands CreateImageCommands(); + ImageGui::ImageView::init(); ImageGui::ViewProviderImagePlane::init(); ImageGui::Workbench::init(); diff --git a/src/Mod/Image/Gui/ImageView.cpp b/src/Mod/Image/Gui/ImageView.cpp index 36e7d5dc81..e1345c64df 100644 --- a/src/Mod/Image/Gui/ImageView.cpp +++ b/src/Mod/Image/Gui/ImageView.cpp @@ -36,6 +36,8 @@ using namespace ImageGui; /* TRANSLATOR ImageGui::ImageView */ +TYPESYSTEM_SOURCE_ABSTRACT(ImageGui::ImageView, Gui::MDIView) + ImageView::ImageView(QWidget* parent) : MDIView(0, parent), _ignoreCloseEvent(false) { diff --git a/src/Mod/Image/Gui/ImageView.h b/src/Mod/Image/Gui/ImageView.h index 7bc34f8e21..ef14bebd75 100644 --- a/src/Mod/Image/Gui/ImageView.h +++ b/src/Mod/Image/Gui/ImageView.h @@ -40,6 +40,8 @@ class ImageGuiExport ImageView : public Gui::MDIView { Q_OBJECT + TYPESYSTEM_HEADER(); + public: ImageView(QWidget* parent); virtual ~ImageView(); diff --git a/src/Mod/Web/Gui/AppWebGui.cpp b/src/Mod/Web/Gui/AppWebGui.cpp index a82508b93d..f48928d97a 100644 --- a/src/Mod/Web/Gui/AppWebGui.cpp +++ b/src/Mod/Web/Gui/AppWebGui.cpp @@ -170,6 +170,7 @@ PyMOD_INIT_FUNC(WebGui) // instantiating the commands CreateWebCommands(); + WebGui::BrowserView::init(); WebGui::Workbench::init(); // add resources and reloads the translators diff --git a/src/Mod/Web/Gui/BrowserView.cpp b/src/Mod/Web/Gui/BrowserView.cpp index 3914e06ffd..6e67d5b421 100644 --- a/src/Mod/Web/Gui/BrowserView.cpp +++ b/src/Mod/Web/Gui/BrowserView.cpp @@ -359,6 +359,8 @@ void WebView::triggerContextMenuAction(int id) /* TRANSLATOR Gui::BrowserView */ +TYPESYSTEM_SOURCE_ABSTRACT(WebGui::BrowserView, Gui::MDIView) + /** * Constructs a BrowserView which is a child of 'parent', with the * name 'name'. diff --git a/src/Mod/Web/Gui/BrowserView.h b/src/Mod/Web/Gui/BrowserView.h index 6123460479..9ce249eddf 100644 --- a/src/Mod/Web/Gui/BrowserView.h +++ b/src/Mod/Web/Gui/BrowserView.h @@ -33,7 +33,7 @@ #include namespace WebGui { class WebEngineUrlRequestInterceptor; -}; +} #elif defined(QTWEBKIT) #include #endif @@ -79,6 +79,8 @@ class WebGuiExport BrowserView : public Gui::MDIView, { Q_OBJECT + TYPESYSTEM_HEADER(); + public: BrowserView(QWidget* parent); ~BrowserView(); From 8eb099d4e15e78362788046a1b46b4a8c999d4e9 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 19 Nov 2021 15:44:23 +0100 Subject: [PATCH 012/133] Gui: add MDIViewPy.cast_to_base and implement in Python wrappers for sub-classes of MDIView --- src/Gui/MDIViewPy.cpp | 26 +++++++++++++++++++++ src/Gui/MDIViewPy.h | 7 +++++- src/Gui/View3DPy.cpp | 7 ++++++ src/Gui/View3DPy.h | 1 + src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp | 6 +++++ src/Mod/Spreadsheet/Gui/SpreadsheetView.h | 1 + 6 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/Gui/MDIViewPy.cpp b/src/Gui/MDIViewPy.cpp index 33ec535da1..b2005957bc 100644 --- a/src/Gui/MDIViewPy.cpp +++ b/src/Gui/MDIViewPy.cpp @@ -53,6 +53,7 @@ void MDIViewPy::init_type() behaviors().supportRepr(); behaviors().supportGetattr(); behaviors().supportSetattr(); + behaviors().set_tp_new(extension_object_new); add_varargs_method("message",&MDIViewPy::sendMessage,"deprecated: use sendMessage"); add_varargs_method("sendMessage",&MDIViewPy::sendMessage,"sendMessage(str)"); @@ -60,6 +61,26 @@ void MDIViewPy::init_type() add_varargs_method("fitAll",&MDIViewPy::fitAll,"fitAll()"); add_varargs_method("setActiveObject", &MDIViewPy::setActiveObject, "setActiveObject(name,object,subname=None)\nadd or set a new active object"); add_varargs_method("getActiveObject", &MDIViewPy::getActiveObject, "getActiveObject(name,resolve=True)\nreturns the active object for the given type"); + add_varargs_method("cast_to_base", &MDIViewPy::cast_to_base, "cast_to_base() cast to MDIView class"); +} + +PyObject *MDIViewPy::extension_object_new(struct _typeobject * /*type*/, PyObject * /*args*/, PyObject * /*kwds*/) +{ + return new MDIViewPy(nullptr); +} + +Py::Object MDIViewPy::type() +{ + return Py::Object( reinterpret_cast( behaviors().type_object() ) ); +} + +Py::ExtensionObject MDIViewPy::create(MDIView *mdi) +{ + Py::Callable class_type(type()); + Py::Tuple arg; + auto inst = Py::ExtensionObject(class_type.apply(arg, Py::Dict())); + inst.extensionObject()->_view = mdi; + return inst; } MDIViewPy::MDIViewPy(MDIView *mdi) @@ -198,3 +219,8 @@ Py::Object MDIViewPy::getActiveObject(const Py::Tuple& args) Py::asObject(parent->getPyObject()), Py::String(subname.c_str())); } + +Py::Object MDIViewPy::cast_to_base(const Py::Tuple&) +{ + return Py::Object(this); +} diff --git a/src/Gui/MDIViewPy.h b/src/Gui/MDIViewPy.h index 469bdca6f3..aee3897ff3 100644 --- a/src/Gui/MDIViewPy.h +++ b/src/Gui/MDIViewPy.h @@ -35,7 +35,11 @@ class MDIView; class GuiExport MDIViewPy : public Py::PythonExtension { public: - static void init_type(void); // announce properties and methods + static void init_type(); // announce properties and methods + static PyObject *extension_object_new( PyTypeObject *subtype, PyObject * /*args*/, PyObject * /*kwds*/ ); + + static Py::Object type(); + static Py::ExtensionObject create(MDIView *mdi); MDIViewPy(MDIView *mdi); ~MDIViewPy(); @@ -47,6 +51,7 @@ public: Py::Object fitAll(const Py::Tuple&); Py::Object setActiveObject(const Py::Tuple&); Py::Object getActiveObject(const Py::Tuple&); + Py::Object cast_to_base(const Py::Tuple&); MDIView* getMDIViewPtr() {return _view.data();} diff --git a/src/Gui/View3DPy.cpp b/src/Gui/View3DPy.cpp index 0576eae5da..469a365588 100644 --- a/src/Gui/View3DPy.cpp +++ b/src/Gui/View3DPy.cpp @@ -52,6 +52,7 @@ #include "View3DViewerPy.h" #include "ActiveObjectList.h" #include "PythonWrapper.h" +#include "MDIViewPy.h" #include @@ -208,6 +209,7 @@ void View3DInventorPy::init_type() "hasClippingPlane(): check whether this clipping plane is active"); add_varargs_method("graphicsView",&View3DInventorPy::graphicsView, "graphicsView(): Access this view as QGraphicsView"); + add_varargs_method("cast_to_base", &View3DInventorPy::cast_to_base, "cast_to_base() cast to MDIView class"); } View3DInventorPy::View3DInventorPy(View3DInventor *vi) @@ -2633,3 +2635,8 @@ Py::Object View3DInventorPy::graphicsView(const Py::Tuple& args) wrap.loadWidgetsModule(); return wrap.fromQWidget(_view->getViewer(), "QGraphicsView"); } + +Py::Object View3DInventorPy::cast_to_base(const Py::Tuple&) +{ + return Gui::MDIViewPy::create(_view); +} diff --git a/src/Gui/View3DPy.h b/src/Gui/View3DPy.h index d84c073c34..9bc057bfb4 100644 --- a/src/Gui/View3DPy.h +++ b/src/Gui/View3DPy.h @@ -135,6 +135,7 @@ public: Py::Object toggleClippingPlane(const Py::Tuple& args, const Py::Dict &); Py::Object hasClippingPlane(const Py::Tuple& args); Py::Object graphicsView(const Py::Tuple& args); + Py::Object cast_to_base(const Py::Tuple&); View3DInventor* getView3DIventorPtr() {return _view;} diff --git a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp index 3895df45ca..2f8fc28dcd 100644 --- a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp +++ b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp @@ -471,6 +471,7 @@ void SheetViewPy::init_type() behaviors().supportSetattr(); add_varargs_method("getSheet", &SheetViewPy::getSheet, "getSheet()"); + add_varargs_method("cast_to_base", &SheetViewPy::cast_to_base, "cast_to_base() cast to MDIView class"); behaviors().readyType(); } @@ -531,4 +532,9 @@ Py::Object SheetViewPy::getSheet(const Py::Tuple& args) return Py::asObject(new Spreadsheet::SheetPy(getSheetViewPtr()->getSheet())); } +Py::Object SheetViewPy::cast_to_base(const Py::Tuple&) +{ + return Gui::MDIViewPy::create(base.getMDIViewPtr()); +} + #include "moc_SpreadsheetView.cpp" diff --git a/src/Mod/Spreadsheet/Gui/SpreadsheetView.h b/src/Mod/Spreadsheet/Gui/SpreadsheetView.h index 03691eace0..803cb4060d 100644 --- a/src/Mod/Spreadsheet/Gui/SpreadsheetView.h +++ b/src/Mod/Spreadsheet/Gui/SpreadsheetView.h @@ -130,6 +130,7 @@ public: Py::Object repr(); Py::Object getattr(const char *); Py::Object getSheet(const Py::Tuple&); + Py::Object cast_to_base(const Py::Tuple&); SheetView* getSheetViewPtr(); From 6bf724cca9ef61b9faa38ce85c0bb6ae350cc3f4 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 19 Nov 2021 15:45:56 +0100 Subject: [PATCH 013/133] Gui: extend PySide2 wrapper of MainWindow with extra functions --- src/Gui/Application.cpp | 2 + src/Gui/ApplicationPy.cpp | 14 +--- src/Gui/CMakeLists.txt | 2 + src/Gui/MainWindowPy.cpp | 151 ++++++++++++++++++++++++++++++++++++++ src/Gui/MainWindowPy.h | 61 +++++++++++++++ 5 files changed, 220 insertions(+), 10 deletions(-) create mode 100644 src/Gui/MainWindowPy.cpp create mode 100644 src/Gui/MainWindowPy.h diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 94e2cb47e4..ca1b8d7967 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -87,6 +87,7 @@ #include "SoFCDB.h" #include "PythonConsolePy.h" #include "PythonDebugger.h" +#include "MainWindowPy.h" #include "MDIViewPy.h" #include "View3DPy.h" #include "DlgOnlineHelpImp.h" @@ -458,6 +459,7 @@ Application::Application(bool GUIenabled) OutputStdout ::init_type(); OutputStderr ::init_type(); PythonStdin ::init_type(); + MainWindowPy ::init_type(); MDIViewPy ::init_type(); View3DInventorPy ::init_type(); View3DInventorViewerPy ::init_type(); diff --git a/src/Gui/ApplicationPy.cpp b/src/Gui/ApplicationPy.cpp index 82a883cb1f..7f149f6960 100644 --- a/src/Gui/ApplicationPy.cpp +++ b/src/Gui/ApplicationPy.cpp @@ -44,6 +44,7 @@ #include "Command.h" #include "Document.h" #include "MainWindow.h" +#include "MainWindowPy.h" #include "Macro.h" #include "EditorView.h" #include "PythonEditor.h" @@ -705,20 +706,13 @@ PyObject* Application::sSendFocusView(PyObject * /*self*/, PyObject *args) PyObject* Application::sGetMainWindow(PyObject * /*self*/, PyObject *args) { if (!PyArg_ParseTuple(args, "")) - return NULL; + return nullptr; - PythonWrapper wrap; - if (!wrap.loadCoreModule() || - !wrap.loadGuiModule() || - !wrap.loadWidgetsModule()) { - PyErr_SetString(PyExc_RuntimeError, "Failed to load Python wrapper for Qt"); - return 0; - } try { - return Py::new_reference_to(wrap.fromQWidget(Gui::getMainWindow(), "QMainWindow")); + return Py::new_reference_to(MainWindowPy::createWrapper(Gui::getMainWindow())); } catch (const Py::Exception&) { - return 0; + return nullptr; } } diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 50a596949b..c492e461ec 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -1037,6 +1037,7 @@ SOURCE_GROUP("View3D\\Inventor" FILES ${Inventor_SRCS}) SET(Widget_CPP_SRCS FileDialog.cpp MainWindow.cpp + MainWindowPy.cpp PrefWidgets.cpp InputField.cpp ProgressBar.cpp @@ -1054,6 +1055,7 @@ SET(Widget_CPP_SRCS SET(Widget_HPP_SRCS FileDialog.h MainWindow.h + MainWindowPy.h PrefWidgets.h InputField.h ProgressBar.h diff --git a/src/Gui/MainWindowPy.cpp b/src/Gui/MainWindowPy.cpp new file mode 100644 index 0000000000..2b9576437c --- /dev/null +++ b/src/Gui/MainWindowPy.cpp @@ -0,0 +1,151 @@ +/*************************************************************************** + * Copyright (c) 2021 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +#endif + +#include "MainWindowPy.h" +#include "MainWindow.h" +#include "MDIView.h" +#include "MDIViewPy.h" +#include "PythonWrapper.h" + + +using namespace Gui; + + +void MainWindowPy::init_type() +{ + behaviors().name("MainWindowPy"); + behaviors().doc("Python binding class for the MainWindow class"); + // you must have overwritten the virtual functions + behaviors().supportRepr(); + behaviors().supportGetattr(); + behaviors().supportSetattr(); + behaviors().set_tp_new(extension_object_new); + + add_varargs_method("getWindows",&MainWindowPy::getWindows,"getWindows()"); + add_varargs_method("getWindowsOfType",&MainWindowPy::getWindowsOfType,"getWindowsOfType(typeid)"); + add_varargs_method("setActiveWindow", &MainWindowPy::setActiveWindow, "setActiveWindow(MDIView)"); + add_varargs_method("getActiveWindow", &MainWindowPy::getActiveWindow, "getActiveWindow()"); +} + +PyObject *MainWindowPy::extension_object_new(struct _typeobject * /*type*/, PyObject * /*args*/, PyObject * /*kwds*/) +{ + return new MainWindowPy(nullptr); +} + +Py::Object MainWindowPy::type() +{ + return Py::Object( reinterpret_cast( behaviors().type_object() ) ); +} + +Py::ExtensionObject MainWindowPy::create(MainWindow *mw) +{ + Py::Callable class_type(type()); + Py::Tuple arg; + auto inst = Py::ExtensionObject(class_type.apply(arg, Py::Dict())); + inst.extensionObject()->_mw = mw; + return inst; +} + +Py::Object MainWindowPy::createWrapper(MainWindow *mw) +{ + PythonWrapper wrap; + if (!wrap.loadCoreModule() || + !wrap.loadGuiModule() || + !wrap.loadWidgetsModule()) { + throw Py::RuntimeError("Failed to load Python wrapper for Qt"); + } + + // copy attributes + std::list attr = {"getWindows", "getWindowsOfType", "setActiveWindow", "getActiveWindow"}; + + Py::Object py = wrap.fromQWidget(mw, "QMainWindow"); + Py::ExtensionObject inst(create(mw)); + for (const auto& it : attr) { + py.setAttr(it, inst.getAttr(it)); + } + return py; +} + +MainWindowPy::MainWindowPy(MainWindow *mw) + : _mw(mw) +{ +} + +MainWindowPy::~MainWindowPy() +{ + // in case the class is instantiated on the stack + ob_refcnt = 0; +} + +Py::Object MainWindowPy::repr() +{ + std::string s; + std::ostringstream s_out; + if (!_mw) + throw Py::RuntimeError("Cannot print representation of deleted object"); + s_out << "MainWindow"; + return Py::String(s_out.str()); +} + +Py::Object MainWindowPy::getWindows(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + + return Py::None(); +} + +Py::Object MainWindowPy::getWindowsOfType(const Py::Tuple& args) +{ + return Py::None(); +} + +Py::Object MainWindowPy::setActiveWindow(const Py::Tuple& args) +{ + Py::ExtensionObject mdi(args[0].callMemberFunction("cast_to_base")); + if (_mw) { + _mw->setActiveWindow(mdi.extensionObject()->getMDIViewPtr()); + } + + return Py::None(); +} + +Py::Object MainWindowPy::getActiveWindow(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + + if (_mw) { + MDIView* mdi = _mw->activeWindow(); + if (mdi) { + return Py::asObject(mdi->getPyObject()); + } + } + return Py::None(); +} diff --git a/src/Gui/MainWindowPy.h b/src/Gui/MainWindowPy.h new file mode 100644 index 0000000000..abc03bb013 --- /dev/null +++ b/src/Gui/MainWindowPy.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (c) 2021 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_MAINWINDOWPY_H +#define GUI_MAINWINDOWPY_H + +#include +#include +#include +#include + +namespace Gui { +class MainWindow; + +class GuiExport MainWindowPy : public Py::PythonExtension +{ +public: + static void init_type(); + static PyObject *extension_object_new( PyTypeObject *subtype, PyObject * /*args*/, PyObject * /*kwds*/ ); + + static Py::Object createWrapper(MainWindow *mw); + static Py::Object type(); + static Py::ExtensionObject create(MainWindow *mw); + + MainWindowPy(MainWindow *mw); + ~MainWindowPy(); + + Py::Object repr(); + + Py::Object getWindows(const Py::Tuple&); + Py::Object getWindowsOfType(const Py::Tuple&); + Py::Object setActiveWindow(const Py::Tuple&); + Py::Object getActiveWindow(const Py::Tuple&); + +private: + QPointer _mw; +}; + +} // namespace Gui + +#endif //GUI_MAINWINDOWPY_H From 751227402db14aad83f5aa87d63e514109bd438f Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 19 Nov 2021 16:21:40 +0100 Subject: [PATCH 014/133] Gui: extend MainWindowPy * implement MainWindowPy::getWindows * implement MainWindowPy::getWindowsOfType --- src/Gui/MainWindowPy.cpp | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/Gui/MainWindowPy.cpp b/src/Gui/MainWindowPy.cpp index 2b9576437c..f5b1400a56 100644 --- a/src/Gui/MainWindowPy.cpp +++ b/src/Gui/MainWindowPy.cpp @@ -32,6 +32,7 @@ #include "MDIView.h" #include "MDIViewPy.h" #include "PythonWrapper.h" +#include using namespace Gui; @@ -118,12 +119,40 @@ Py::Object MainWindowPy::getWindows(const Py::Tuple& args) if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - return Py::None(); + Py::List mdis; + if (_mw) { + QList windows = _mw->windows(); + for (auto it : windows) { + MDIView* view = qobject_cast(it); + if (view) { + mdis.append(Py::asObject(view->getPyObject())); + } + } + } + + return mdis; } Py::Object MainWindowPy::getWindowsOfType(const Py::Tuple& args) { - return Py::None(); + PyObject* t; + if (!PyArg_ParseTuple(args.ptr(), "O!", &Base::TypePy::Type, &t)) + throw Py::Exception(); + + Base::Type typeId = *static_cast(t)->getBaseTypePtr(); + + Py::List mdis; + if (_mw) { + QList windows = _mw->windows(); + for (auto it : windows) { + MDIView* view = qobject_cast(it); + if (view && view->isDerivedFrom(typeId)) { + mdis.append(Py::asObject(view->getPyObject())); + } + } + } + + return mdis; } Py::Object MainWindowPy::setActiveWindow(const Py::Tuple& args) From 9ee60fd585d4a4b4161e1441cf62757dba0ba209 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 20 Nov 2021 10:34:01 +0100 Subject: [PATCH 015/133] PD: Add common base class for Pad/Pocket --- src/Mod/PartDesign/App/AppPartDesign.cpp | 1 + src/Mod/PartDesign/App/CMakeLists.txt | 2 + src/Mod/PartDesign/App/FeatureExtrude.cpp | 80 +++++++++++++++++++++++ src/Mod/PartDesign/App/FeatureExtrude.h | 61 +++++++++++++++++ src/Mod/PartDesign/App/FeaturePad.h | 6 +- src/Mod/PartDesign/App/FeaturePocket.h | 3 +- 6 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 src/Mod/PartDesign/App/FeatureExtrude.cpp create mode 100644 src/Mod/PartDesign/App/FeatureExtrude.h diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp b/src/Mod/PartDesign/App/AppPartDesign.cpp index ce39347034..f130609fc0 100644 --- a/src/Mod/PartDesign/App/AppPartDesign.cpp +++ b/src/Mod/PartDesign/App/AppPartDesign.cpp @@ -103,6 +103,7 @@ PyMOD_INIT_FUNC(_PartDesign) PartDesign::MultiTransform ::init(); PartDesign::Hole ::init(); PartDesign::Body ::init(); + PartDesign::FeatureExtrude ::init(); PartDesign::Pad ::init(); PartDesign::Pocket ::init(); PartDesign::Fillet ::init(); diff --git a/src/Mod/PartDesign/App/CMakeLists.txt b/src/Mod/PartDesign/App/CMakeLists.txt index a623563930..d74a77c1d5 100644 --- a/src/Mod/PartDesign/App/CMakeLists.txt +++ b/src/Mod/PartDesign/App/CMakeLists.txt @@ -87,6 +87,8 @@ SET(FeaturesDressUp_SRCS SOURCE_GROUP("DressUpFeatures" FILES ${FeaturesDressUp_SRCS}) SET(FeaturesSketchBased_SRCS + FeatureExtrude.cpp + FeatureExtrude.h FeatureSketchBased.cpp FeatureSketchBased.h FeaturePad.cpp diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp new file mode 100644 index 0000000000..4b281efbad --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include +#include +#include +#include + +#include "FeatureExtrude.h" + +using namespace PartDesign; + + +PROPERTY_SOURCE(PartDesign::FeatureExtrude, PartDesign::ProfileBased) + +FeatureExtrude::FeatureExtrude() +{ +} + +short FeatureExtrude::mustExecute() const +{ + if (Placement.isTouched() || + Type.isTouched() || + Length.isTouched() || + Length2.isTouched() || + UseCustomVector.isTouched() || + Direction.isTouched() || + ReferenceAxis.isTouched() || + AlongSketchNormal.isTouched() || + Offset.isTouched() || + UpToFace.isTouched()) + return 1; + return ProfileBased::mustExecute(); +} diff --git a/src/Mod/PartDesign/App/FeatureExtrude.h b/src/Mod/PartDesign/App/FeatureExtrude.h new file mode 100644 index 0000000000..a2fd9ea2e0 --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureExtrude.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef PARTDESIGN_FEATURE_EXTRUDE_H +#define PARTDESIGN_FEATURE_EXTRUDE_H + +#include +#include +#include + +#include "FeatureSketchBased.h" + +namespace PartDesign +{ + +class PartDesignExport FeatureExtrude : public ProfileBased +{ + PROPERTY_HEADER(PartDesign::FeatureExtrude); + +public: + FeatureExtrude(); + + App::PropertyEnumeration Type; + App::PropertyLength Length; + App::PropertyLength Length2; + App::PropertyBool UseCustomVector; + App::PropertyVector Direction; + App::PropertyBool AlongSketchNormal; + App::PropertyLength Offset; + App::PropertyLinkSub ReferenceAxis; + + /** @name methods override feature */ + //@{ + short mustExecute() const; + //@} +}; + +} //namespace PartDesign + + +#endif // PARTDESIGN_FEATURE_EXTRUDE_H diff --git a/src/Mod/PartDesign/App/FeaturePad.h b/src/Mod/PartDesign/App/FeaturePad.h index 775102f1b4..7723ec379a 100644 --- a/src/Mod/PartDesign/App/FeaturePad.h +++ b/src/Mod/PartDesign/App/FeaturePad.h @@ -24,11 +24,7 @@ #ifndef PARTDESIGN_Pad_H #define PARTDESIGN_Pad_H -#include -#include -#include - -#include "FeatureSketchBased.h" +#include "FeatureExtrude.h" namespace PartDesign { diff --git a/src/Mod/PartDesign/App/FeaturePocket.h b/src/Mod/PartDesign/App/FeaturePocket.h index 9fb580f4cf..01dba2f70c 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.h +++ b/src/Mod/PartDesign/App/FeaturePocket.h @@ -24,8 +24,7 @@ #ifndef PARTDESIGN_Pocket_H #define PARTDESIGN_Pocket_H -#include -#include "FeatureSketchBased.h" +#include "FeatureExtrude.h" namespace PartDesign { From ab480df74540b1b1433d44c24914187a3aa626a2 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 20 Nov 2021 11:45:13 +0100 Subject: [PATCH 016/133] PD: move duplicated code to common base class --- src/Mod/PartDesign/App/FeatureExtrude.cpp | 51 ++++++++++++++++ src/Mod/PartDesign/App/FeatureExtrude.h | 3 + src/Mod/PartDesign/App/FeaturePad.cpp | 71 +--------------------- src/Mod/PartDesign/App/FeaturePad.h | 17 +----- src/Mod/PartDesign/App/FeaturePocket.cpp | 72 ++--------------------- src/Mod/PartDesign/App/FeaturePocket.h | 15 +---- 6 files changed, 66 insertions(+), 163 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp index 4b281efbad..54a3599328 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.cpp +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -78,3 +78,54 @@ short FeatureExtrude::mustExecute() const return 1; return ProfileBased::mustExecute(); } + +Base::Vector3d FeatureExtrude::computeDirection(const Base::Vector3d& sketchVector) +{ + Base::Vector3d extrudeDirection; + + if (!UseCustomVector.getValue()) { + if (!ReferenceAxis.getValue()) { + // use sketch's normal vector for direction + extrudeDirection = sketchVector; + AlongSketchNormal.setReadOnly(true); + } + else { + // update Direction from ReferenceAxis + App::DocumentObject* pcReferenceAxis = ReferenceAxis.getValue(); + const std::vector& subReferenceAxis = ReferenceAxis.getSubValues(); + Base::Vector3d base; + Base::Vector3d dir; + getAxis(pcReferenceAxis, subReferenceAxis, base, dir, false); + switch (addSubType) { + case Type::Additive: + extrudeDirection = dir; + break; + case Type::Subtractive: + extrudeDirection = -dir; + break; + } + } + } + else { + // use the given vector + // if null vector, use sketchVector + if ((fabs(Direction.getValue().x) < Precision::Confusion()) + && (fabs(Direction.getValue().y) < Precision::Confusion()) + && (fabs(Direction.getValue().z) < Precision::Confusion())) { + Direction.setValue(sketchVector); + } + extrudeDirection = Direction.getValue(); + } + + // disable options of UseCustomVector + Direction.setReadOnly(!UseCustomVector.getValue()); + ReferenceAxis.setReadOnly(UseCustomVector.getValue()); + // UseCustomVector allows AlongSketchNormal but !UseCustomVector does not forbid it + if (UseCustomVector.getValue()) + AlongSketchNormal.setReadOnly(false); + + // explicitly set the Direction so that the dialog shows also the used direction + // if the sketch's normal vector was used + Direction.setValue(extrudeDirection); + return extrudeDirection; +} diff --git a/src/Mod/PartDesign/App/FeatureExtrude.h b/src/Mod/PartDesign/App/FeatureExtrude.h index a2fd9ea2e0..cfa1522de8 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.h +++ b/src/Mod/PartDesign/App/FeatureExtrude.h @@ -53,6 +53,9 @@ public: //@{ short mustExecute() const; //@} + +protected: + Base::Vector3d computeDirection(const Base::Vector3d& sketchVector); }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index e88fc4eebe..7b3a5f560e 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -58,7 +58,7 @@ using namespace PartDesign; const char* Pad::TypeEnums[]= {"Length", "UpToLast", "UpToFirst", "UpToFace", "TwoLengths", NULL}; -PROPERTY_SOURCE(PartDesign::Pad, PartDesign::ProfileBased) +PROPERTY_SOURCE(PartDesign::Pad, PartDesign::FeatureExtrude) Pad::Pad() { @@ -82,23 +82,7 @@ Pad::Pad() Length2.setConstraints(nullptr); } -short Pad::mustExecute() const -{ - if (Placement.isTouched() || - Type.isTouched() || - Length.isTouched() || - Length2.isTouched() || - UseCustomVector.isTouched() || - Direction.isTouched() || - ReferenceAxis.isTouched() || - AlongSketchNormal.isTouched() || - Offset.isTouched() || - UpToFace.isTouched()) - return 1; - return ProfileBased::mustExecute(); -} - -App::DocumentObjectExecReturn *Pad::execute(void) +App::DocumentObjectExecReturn *Pad::execute() { // Validate parameters double L = Length.getValue(); @@ -133,8 +117,6 @@ App::DocumentObjectExecReturn *Pad::execute(void) base = TopoDS_Shape(); } - // get the Sketch plane - Base::Placement SketchPos = obj->Placement.getValue(); // get the normal vector of the sketch Base::Vector3d SketchVector = getProfileNormal(); @@ -144,53 +126,11 @@ App::DocumentObjectExecReturn *Pad::execute(void) base.Move(invObjLoc); - Base::Vector3d paddingDirection; - - if (!UseCustomVector.getValue()) { - if (!ReferenceAxis.getValue()) { - // use sketch's normal vector for direction - paddingDirection = SketchVector; - AlongSketchNormal.setReadOnly(true); - } - else { - // update Direction from ReferenceAxis - try { - App::DocumentObject* pcReferenceAxis = ReferenceAxis.getValue(); - const std::vector& subReferenceAxis = ReferenceAxis.getSubValues(); - Base::Vector3d base; - Base::Vector3d dir; - getAxis(pcReferenceAxis, subReferenceAxis, base, dir, false); - paddingDirection = dir; - } - catch (const Base::Exception& e) { - return new App::DocumentObjectExecReturn(e.what()); - } - } - } - else { - // use the given vector - // if null vector, use SketchVector - if ( (fabs(Direction.getValue().x) < Precision::Confusion()) - && (fabs(Direction.getValue().y) < Precision::Confusion()) - && (fabs(Direction.getValue().z) < Precision::Confusion()) ) { - Direction.setValue(SketchVector); - } - paddingDirection = Direction.getValue(); - } - - // disable options of UseCustomVector - Direction.setReadOnly(!UseCustomVector.getValue()); - ReferenceAxis.setReadOnly(UseCustomVector.getValue()); - // UseCustomVector allows AlongSketchNormal but !UseCustomVector does not forbid it - if (UseCustomVector.getValue()) - AlongSketchNormal.setReadOnly(false); + Base::Vector3d paddingDirection = computeDirection(SketchVector); // create vector in padding direction with length 1 gp_Dir dir(paddingDirection.x, paddingDirection.y, paddingDirection.z); - // store the finally used direction to display it in the dialog - Direction.setValue(dir.X(), dir.Y(), dir.Z()); - // The length of a gp_Dir is 1 so the resulting pad would have // the length L in the direction of dir. But we want to have its height in the // direction of the normal vector. @@ -212,10 +152,6 @@ App::DocumentObjectExecReturn *Pad::execute(void) L2 = L2 / factor; } - // explicitly set the Direction so that the dialog shows also the used direction - // if the sketch's normal vector was used - Direction.setValue(paddingDirection); - dir.Transform(invObjLoc.Transformation()); if (sketchshape.IsNull()) @@ -394,7 +330,6 @@ App::DocumentObjectExecReturn *Pad::execute(void) return App::DocumentObject::StdReturn; } catch (Standard_Failure& e) { - if (std::string(e.GetMessageString()) == "TopoDS::Face") return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" "Intersecting sketch entities or multiple faces in a sketch are not allowed."); diff --git a/src/Mod/PartDesign/App/FeaturePad.h b/src/Mod/PartDesign/App/FeaturePad.h index 7723ec379a..381571e4f5 100644 --- a/src/Mod/PartDesign/App/FeaturePad.h +++ b/src/Mod/PartDesign/App/FeaturePad.h @@ -29,22 +29,13 @@ namespace PartDesign { -class PartDesignExport Pad : public ProfileBased +class PartDesignExport Pad : public FeatureExtrude { PROPERTY_HEADER(PartDesign::Pad); public: Pad(); - App::PropertyEnumeration Type; - App::PropertyLength Length; - App::PropertyLength Length2; - App::PropertyBool UseCustomVector; - App::PropertyVector Direction; - App::PropertyBool AlongSketchNormal; - App::PropertyLength Offset; - App::PropertyLinkSub ReferenceAxis; - /** @name methods override feature */ //@{ /** Recalculate the feature @@ -60,17 +51,15 @@ public: * If Reversed is true then the direction of revolution will be reversed. * The created material will be fused with the sketch support (if there is one) */ - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; + App::DocumentObjectExecReturn *execute(); /// returns the type name of the view provider - const char* getViewProviderName(void) const { + const char* getViewProviderName() const { return "PartDesignGui::ViewProviderPad"; } //@} private: static const char* TypeEnums[]; - //static const char* SideEnums[]; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index d77390069e..6d9a435c6e 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -57,7 +57,7 @@ using namespace PartDesign; const char* Pocket::TypeEnums[]= {"Length","ThroughAll","UpToFirst","UpToFace","TwoLengths",NULL}; -PROPERTY_SOURCE(PartDesign::Pocket, PartDesign::ProfileBased) +PROPERTY_SOURCE(PartDesign::Pocket, PartDesign::FeatureExtrude) Pocket::Pocket() { @@ -81,23 +81,7 @@ Pocket::Pocket() Length2.setConstraints(nullptr); } -short Pocket::mustExecute() const -{ - if (Placement.isTouched() || - Type.isTouched() || - Length.isTouched() || - Length2.isTouched() || - Offset.isTouched() || - UseCustomVector.isTouched() || - Direction.isTouched() || - ReferenceAxis.isTouched() || - AlongSketchNormal.isTouched() || - UpToFace.isTouched()) - return 1; - return ProfileBased::mustExecute(); -} - -App::DocumentObjectExecReturn *Pocket::execute(void) +App::DocumentObjectExecReturn *Pocket::execute() { // Handle legacy features, these typically have Type set to 3 (previously NULL, now UpToFace), // empty FaceName (because it didn't exist) and a value for Length @@ -136,10 +120,8 @@ App::DocumentObjectExecReturn *Pocket::execute(void) return new App::DocumentObjectExecReturn(text); } - // get the Sketch plane - Base::Placement SketchPos = obj->Placement.getValue(); // get the normal vector of the sketch - Base::Vector3d SketchVector = getProfileNormal(); + Base::Vector3d SketchVector = getProfileNormal(); // turn around for pockets SketchVector *= -1; @@ -150,53 +132,11 @@ App::DocumentObjectExecReturn *Pocket::execute(void) base.Move(invObjLoc); - Base::Vector3d pocketDirection; - - if (!UseCustomVector.getValue()) { - if (!ReferenceAxis.getValue()) { - // use sketch's normal vector for direction - pocketDirection = SketchVector; - AlongSketchNormal.setReadOnly(true); - } - else { - // update Direction from ReferenceAxis - try { - App::DocumentObject* pcReferenceAxis = ReferenceAxis.getValue(); - const std::vector& subReferenceAxis = ReferenceAxis.getSubValues(); - Base::Vector3d base; - Base::Vector3d dir; - getAxis(pcReferenceAxis, subReferenceAxis, base, dir, false); - pocketDirection = -dir; - } - catch (const Base::Exception& e) { - return new App::DocumentObjectExecReturn(e.what()); - } - } - } - else { - // use the given vector - // if null vector, use SketchVector - if ((fabs(Direction.getValue().x) < Precision::Confusion()) - && (fabs(Direction.getValue().y) < Precision::Confusion()) - && (fabs(Direction.getValue().z) < Precision::Confusion())) { - Direction.setValue(SketchVector); - } - pocketDirection = Direction.getValue(); - } - - // disable options of UseCustomVector - Direction.setReadOnly(!UseCustomVector.getValue()); - ReferenceAxis.setReadOnly(UseCustomVector.getValue()); - // UseCustomVector allows AlongSketchNormal but !UseCustomVector does not forbid it - if (UseCustomVector.getValue()) - AlongSketchNormal.setReadOnly(false); + Base::Vector3d pocketDirection = computeDirection(SketchVector); // create vector in pocketing direction with length 1 gp_Dir dir(pocketDirection.x, pocketDirection.y, pocketDirection.z); - // store the finally used direction to display it in the dialog - Direction.setValue(dir.X(), dir.Y(), dir.Z()); - // The length of a gp_Dir is 1 so the resulting pocket would have // the length L in the direction of dir. But we want to have its height in the // direction of the normal vector. @@ -218,10 +158,6 @@ App::DocumentObjectExecReturn *Pocket::execute(void) L2 = L2 / factor; } - // explicitly set the Direction so that the dialog shows also the used direction - // if the sketch's normal vector was used - Direction.setValue(pocketDirection); - dir.Transform(invObjLoc.Transformation()); if (profileshape.IsNull()) diff --git a/src/Mod/PartDesign/App/FeaturePocket.h b/src/Mod/PartDesign/App/FeaturePocket.h index 01dba2f70c..3c83e7becf 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.h +++ b/src/Mod/PartDesign/App/FeaturePocket.h @@ -29,22 +29,13 @@ namespace PartDesign { -class PartDesignExport Pocket : public ProfileBased +class PartDesignExport Pocket : public FeatureExtrude { PROPERTY_HEADER(PartDesign::Pocket); public: Pocket(); - App::PropertyEnumeration Type; - App::PropertyLength Length; - App::PropertyLength Length2; - App::PropertyLength Offset; - App::PropertyBool UseCustomVector; - App::PropertyVector Direction; - App::PropertyBool AlongSketchNormal; - App::PropertyLinkSub ReferenceAxis; - /** @name methods override feature */ //@{ /** Recalculate the feature @@ -57,8 +48,7 @@ public: * If Midplane is true, then the extrusion will extend for half of the length on both sides of the sketch plane * The created material will be cut out of the sketch support */ - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; + App::DocumentObjectExecReturn *execute(); /// returns the type name of the view provider const char* getViewProviderName(void) const { return "PartDesignGui::ViewProviderPocket"; @@ -66,7 +56,6 @@ public: //@} private: static const char* TypeEnums[]; - }; } //namespace PartDesign From 449797d7f50df65c08ba175d58fa1cd874ccd05c Mon Sep 17 00:00:00 2001 From: luz paz Date: Thu, 18 Nov 2021 06:42:55 -0500 Subject: [PATCH 017/133] Gui: Remove superfluous whitespace from string that is translated --- src/Gui/DlgUnitsCalculator.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gui/DlgUnitsCalculator.ui b/src/Gui/DlgUnitsCalculator.ui index c0e39feadc..b49c557b6a 100644 --- a/src/Gui/DlgUnitsCalculator.ui +++ b/src/Gui/DlgUnitsCalculator.ui @@ -80,7 +80,7 @@ - List of last used calculations + List of last used calculations. To add a calculation press Return in the value input field From 4fa4446f01248c080284f4fa06c4ac852276e4e1 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 20 Nov 2021 12:01:55 +0100 Subject: [PATCH 018/133] PD: [skip ci] code clean-up in pad and pocket feature --- src/Mod/PartDesign/App/FeaturePad.cpp | 90 ++---------------------- src/Mod/PartDesign/App/FeaturePocket.cpp | 14 +--- 2 files changed, 8 insertions(+), 96 deletions(-) diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index 7b3a5f560e..8b58918fa0 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -179,65 +179,6 @@ App::DocumentObjectExecReturn *Pad::execute() // TODO: Write our own PrismMaker which does not depend on a solid base shape if (base.IsNull()) { - // This implementation suffers from some problems: - // * it explicitly checks for planes only but e.g. a B-spline may work too - // * The extracted surface passed to GeomAPI_ProjectPointOnSurf may lack of - // its placement and thus computes a wrong result - // * the direction computed by base and projection point must not be transformed -#if 0 - // Workaround because BRepFeat_MakePrism requires the base face located on a solid to be able to extrude up to a face - // Handle special case of extruding up to a face or plane parallel to the base face - BRepAdaptor_Surface adapt(upToFace); - if (adapt.GetType() != GeomAbs_Plane) - return new App::DocumentObjectExecReturn("Pad: Extruding up to a face or plane is only possible if the sketch is located on a face"); - - double angle = dir.Angle(adapt.Plane().Axis().Direction()); - if (angle > Precision::Confusion()) - return new App::DocumentObjectExecReturn("Pad: Extruding up to a face is only possible if the sketch plane is parallel to it"); - - // Project basepoint of sketch onto the UpToFace to determine distance and direction - gp_Pnt basePoint(SketchPos.getPosition().x, SketchPos.getPosition().y, SketchPos.getPosition().z); - GeomAPI_ProjectPointOnSurf prj(basePoint, adapt.Surface().Surface()); - if (prj.NbPoints() != 1) - return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed to find extrusion direction"); - // Distance - double length = prj.Distance(1) + Offset.getValue(); - if (length < Precision::Confusion()) - return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed because of zero height"); - - // Direction (the distance is always positive) - gp_Pnt prjP = prj.NearestPoint(); - dir = gp_Dir(gp_Vec(basePoint, prjP)); - dir.Transform(invObjLoc.Transformation()); -#else - /*TopLoc_Location upToFaceLoc; - Handle(Geom_Surface) surf = BRep_Tool::Surface(upToFace, upToFaceLoc); - GeomLib_IsPlanarSurface checkSurface(surf); - if (surf.IsNull() || !checkSurface.IsPlanar()) - return new App::DocumentObjectExecReturn("Pad: Extruding up to a face or plane is only possible if the sketch is located on a face"); - - gp_Pln upToPlane = checkSurface.Plan().Transformed(upToFaceLoc); - gp_Dir planeNorm = upToPlane.Axis().Direction(); - gp_Pnt planeBase = upToPlane.Location(); - double angle = dir.Angle(planeNorm); - if (angle > Precision::Confusion()) - return new App::DocumentObjectExecReturn("Pad: Extruding up to a face is only possible if the sketch plane is parallel to it"); - - // Project basepoint of sketch onto the UpToFace to determine distance and direction - gp_Pnt basePoint(SketchPos.getPosition().x, SketchPos.getPosition().y, SketchPos.getPosition().z); - Standard_Real pn = planeBase.XYZ().Dot(planeNorm.XYZ()); - Standard_Real qn = basePoint.XYZ().Dot(planeNorm.XYZ()); - gp_Pnt projPoint = basePoint.Translated(planeNorm.XYZ().Multiplied(pn-qn)); - - // Distance - double length = projPoint.Distance(basePoint) + Offset.getValue(); - if (length < Precision::Confusion()) - return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed because of zero height"); - - // Direction (the distance is always positive) - dir = gp_Dir(gp_Vec(basePoint, projPoint));*/ -#endif - //generatePrism(prism, sketchshape, "Length", dir, length, 0.0, false, false); base = sketchshape; supportface = TopoDS::Face(sketchshape); @@ -245,20 +186,11 @@ App::DocumentObjectExecReturn *Pad::execute() if (!Ex.More()) supportface = TopoDS_Face(); -#if 0 - BRepFeat_MakePrism PrismMaker; - PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1); - PrismMaker.Perform(upToFace); - - if (!PrismMaker.IsDone()) - return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!"); - prism = PrismMaker.Shape(); -#else PrismMode mode = PrismMode::None; generatePrism(prism, method, base, sketchshape, supportface, upToFace, dir, mode, Standard_True); -#endif base.Nullify(); - } else { + } + else { // A support object is always required and we need to use BRepFeat_MakePrism // Problem: For Pocket/UpToFirst (or an equivalent Pocket/UpToFace) the resulting shape is invalid // because the feature does not add any material. This only happens with the "2" option, though @@ -271,20 +203,11 @@ App::DocumentObjectExecReturn *Pad::execute() TopExp_Explorer Ex(supportface,TopAbs_WIRE); if (!Ex.More()) supportface = TopoDS_Face(); -#if 0 - BRepFeat_MakePrism PrismMaker; - PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1); - PrismMaker.Perform(upToFace); - - if (!PrismMaker.IsDone()) - return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!"); - prism = PrismMaker.Shape(); -#else PrismMode mode = PrismMode::None; generatePrism(prism, method, base, sketchshape, supportface, upToFace, dir, mode, Standard_True); -#endif } - } else { + } + else { generatePrism(prism, sketchshape, method, dir, L, L2, hasMidplane, hasReversed); } @@ -297,8 +220,6 @@ App::DocumentObjectExecReturn *Pad::execute() this->AddSubShape.setValue(prism); if (!base.IsNull()) { -// auto obj = getDocument()->addObject("Part::Feature", "prism"); -// static_cast(obj)->Shape.setValue(getSolid(prism)); // Let's call algorithm computing a fuse operation: BRepAlgoAPI_Fuse mkFuse(base, prism); // Let's check if the fusion has been successful @@ -318,7 +239,8 @@ App::DocumentObjectExecReturn *Pad::execute() solRes = refineShapeIfActive(solRes); this->Shape.setValue(getSolid(solRes)); - } else { + } + else { int solidCount = countSolids(prism); if (solidCount > 1) { return new App::DocumentObjectExecReturn("Pad: Result has multiple solids. This is not supported at this time."); diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index 6d9a435c6e..2263a0613a 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -195,19 +195,9 @@ App::DocumentObjectExecReturn *Pocket::execute() TopExp_Explorer Ex(supportface,TopAbs_WIRE); if (!Ex.More()) supportface = TopoDS_Face(); -#if 0 - BRepFeat_MakePrism PrismMaker; - PrismMaker.Init(base, profileshape, supportface, dir, 0, 1); - PrismMaker.Perform(upToFace); - - if (!PrismMaker.IsDone()) - return new App::DocumentObjectExecReturn("Pocket: Up to face: Could not extrude the sketch!"); - TopoDS_Shape prism = PrismMaker.Shape(); -#else TopoDS_Shape prism; PrismMode mode = PrismMode::CutFromBase; generatePrism(prism, method, base, profileshape, supportface, upToFace, dir, mode, Standard_True); -#endif // And the really expensive way to get the SubShape... BRepAlgoAPI_Cut mkCut(base, prism); @@ -223,7 +213,8 @@ App::DocumentObjectExecReturn *Pocket::execute() } this->Shape.setValue(getSolid(prism)); - } else { + } + else { TopoDS_Shape prism; generatePrism(prism, profileshape, method, dir, L, L2, Midplane.getValue(), Reversed.getValue()); @@ -258,7 +249,6 @@ App::DocumentObjectExecReturn *Pocket::execute() return App::DocumentObject::StdReturn; } catch (Standard_Failure& e) { - if (std::string(e.GetMessageString()) == "TopoDS::Face" && (std::string(Type.getValueAsString()) == "UpToFirst" || std::string(Type.getValueAsString()) == "UpToFace")) return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" From 0db37e77c3ee207fe6021b26f4554f669eadf911 Mon Sep 17 00:00:00 2001 From: luz paz Date: Tue, 16 Nov 2021 15:44:05 -0500 Subject: [PATCH 019/133] App: fix doc typo in ObjectIdentifier.h --- src/App/ObjectIdentifier.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App/ObjectIdentifier.h b/src/App/ObjectIdentifier.h index 5c09f1035b..0504d0c136 100644 --- a/src/App/ObjectIdentifier.h +++ b/src/App/ObjectIdentifier.h @@ -368,7 +368,7 @@ public: /** Get dependencies of this object identifier * - * @param deps: returns the depdenencies. + * @param deps: returns the dependencies. * @param needProps: whether need property dependencies. * @param labels: optional return of any label references. * From 5b7fb78b103412c493d0018b7f71495cafc6d415 Mon Sep 17 00:00:00 2001 From: luz paz Date: Tue, 16 Nov 2021 15:45:27 -0500 Subject: [PATCH 020/133] App: remove superfluous whitespace in ObjectIdentifier.h --- src/App/ObjectIdentifier.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App/ObjectIdentifier.h b/src/App/ObjectIdentifier.h index 0504d0c136..16a16400bc 100644 --- a/src/App/ObjectIdentifier.h +++ b/src/App/ObjectIdentifier.h @@ -346,7 +346,7 @@ public: * * The dependency is a map from document object to a set of property names. * An object identifier may references multiple objects using syntax like - * 'Part.Group[0].Width'. + * 'Part.Group[0].Width'. * * Also, we use set of string instead of set of Property pointer, because * the property may not exist at the time this ObjectIdentifier is @@ -378,7 +378,7 @@ public: * dependencies will be returned. */ void getDep(Dependencies &deps, bool needProps, std::vector *labels=0) const; - + /// Returns all label references void getDepLabels(std::vector &labels) const; From 79a0c6b54c572b2e956cefc53617a52102b24b49 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Sun, 14 Nov 2021 23:24:55 -0600 Subject: [PATCH 021/133] Spreadsheet: Implement Python SheetView functions Add the following functions to the Python interface of SheetView: * selectedRanges() * selectedCells() * select(cell, flags) * select(upperLeft, lowerRight, flags) * currentIndex() * setCurrentIndex(cell) --- src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp | 87 ++++++++++++++++++++- src/Mod/Spreadsheet/Gui/SpreadsheetView.h | 6 ++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp index 2f8fc28dcd..007d534e82 100644 --- a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp +++ b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp @@ -53,7 +53,6 @@ #include "qtcolorpicker.h" #include "SpreadsheetView.h" -#include "SpreadsheetViewPy.h" #include "SpreadsheetDelegate.h" #include "ui_Sheet.h" @@ -469,7 +468,13 @@ void SheetViewPy::init_type() behaviors().supportRepr(); behaviors().supportGetattr(); behaviors().supportSetattr(); - + + add_varargs_method("selectedRanges", &SheetViewPy::selectedRanges, "selectedRanges(): Get a list of all selected ranges"); + add_varargs_method("selectedCells", &SheetViewPy::selectedCells, "selectedCells(): Get a list of all selected cells"); + add_varargs_method("select", &SheetViewPy::select, "select(cell,flags): Select (or deselect) the given cell, applying QItemSelectionModel.SelectionFlags\nselect(topLeft,bottomRight,flags): Select (or deselect) the given range, applying QItemSelectionModel.SelectionFlags"); + add_varargs_method("currentIndex", &SheetViewPy::currentIndex, "currentIndex(): Get the current index"); + add_varargs_method("setCurrentIndex", &SheetViewPy::setCurrentIndex, "setCurrentIndex(cell): Set the current index to the named cell (e.g. 'A1')"); + add_varargs_method("getSheet", &SheetViewPy::getSheet, "getSheet()"); add_varargs_method("cast_to_base", &SheetViewPy::cast_to_base, "cast_to_base() cast to MDIView class"); behaviors().readyType(); @@ -537,4 +542,82 @@ Py::Object SheetViewPy::cast_to_base(const Py::Tuple&) return Gui::MDIViewPy::create(base.getMDIViewPtr()); } +Py::Object SheetViewPy::selectedRanges(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + SheetView* sheetView = getSheetViewPtr(); + std::vector ranges = sheetView->selectedRanges(); + Py::List list; + for (const auto& range : ranges) + { + list.append(Py::String(range.rangeString())); + } + + return list; +} + +Py::Object SheetViewPy::selectedCells(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + SheetView* sheetView = getSheetViewPtr(); + QModelIndexList cells = sheetView->selectedIndexes(); + Py::List list; + for (const auto& cell : cells) { + list.append(Py::String(App::CellAddress(cell.row(), cell.column()).toString())); + } + + return list; +} + +Py::Object SheetViewPy::select(const Py::Tuple& _args) +{ + SheetView* sheetView = getSheetViewPtr(); + + Py::Sequence args(_args.ptr()); + + const char* cell; + const char* topLeft; + const char* bottomRight; + int flags = 0; + if (args.size() == 2 && PyArg_ParseTuple(_args.ptr(), "si", &cell, &flags)) { + sheetView->select(App::CellAddress(cell), static_cast(flags)); + } + else if (args.size() == 3 && PyArg_ParseTuple(_args.ptr(), "ssi", &topLeft, &bottomRight, &flags)) { + sheetView->select(App::CellAddress(topLeft), App::CellAddress(bottomRight), static_cast(flags)); + } + else { + if (args.size() == 2) + throw Base::TypeError("Expects the arguments to be a cell name (e.g. 'A1') and QItemSelectionModel.SelectionFlags"); + else if (args.size() == 3) + throw Base::TypeError("Expects the arguments to be a cell name (e.g. 'A1'), a second cell name (e.g. 'B5'), and QItemSelectionModel.SelectionFlags"); + else + throw Base::TypeError("Wrong arguments to select: specify either a cell, or two cells (for a range), and QItemSelectionModel.SelectionFlags"); + } + return Py::Object(); +} + +Py::Object SheetViewPy::currentIndex(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + SheetView* sheetView = getSheetViewPtr(); + auto index = sheetView->currentIndex(); + Py::String str(App::CellAddress(index.row(), index.column()).toString()); + return str; +} + +Py::Object SheetViewPy::setCurrentIndex(const Py::Tuple& args) +{ + SheetView* sheetView = getSheetViewPtr(); + + const char* cell; + if (PyArg_ParseTuple(args.ptr(), "s", &cell)) { + sheetView->setCurrentIndex(App::CellAddress(cell)); + } + return Py::Object(); +} + + #include "moc_SpreadsheetView.cpp" diff --git a/src/Mod/Spreadsheet/Gui/SpreadsheetView.h b/src/Mod/Spreadsheet/Gui/SpreadsheetView.h index 803cb4060d..ec96b81d06 100644 --- a/src/Mod/Spreadsheet/Gui/SpreadsheetView.h +++ b/src/Mod/Spreadsheet/Gui/SpreadsheetView.h @@ -131,6 +131,12 @@ public: Py::Object getattr(const char *); Py::Object getSheet(const Py::Tuple&); Py::Object cast_to_base(const Py::Tuple&); + + Py::Object selectedRanges(const Py::Tuple&); + Py::Object selectedCells(const Py::Tuple&); + Py::Object select(const Py::Tuple&); + Py::Object currentIndex(const Py::Tuple&); + Py::Object setCurrentIndex(const Py::Tuple&); SheetView* getSheetViewPtr(); From d60a0fb760a6927974b91f97b9f0f59928158b9e Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Sun, 14 Nov 2021 23:41:13 -0600 Subject: [PATCH 022/133] Spreadsheet: Remove unnecessary functions & files Remove functions from they Python code for ViewProviderSpreadsheet that are now in SheetView, and eliminate the unneded files for SheetView now that it's being generated by hand to facilitate pseudo-inheritance. --- src/Mod/Spreadsheet/Gui/CMakeLists.txt | 3 - src/Mod/Spreadsheet/Gui/SpreadsheetViewPy.xml | 23 ------ .../Spreadsheet/Gui/SpreadsheetViewPyImp.cpp | 32 -------- .../Gui/ViewProviderSpreadsheetPy.xml | 26 ------- .../Gui/ViewProviderSpreadsheetPyImp.cpp | 77 ------------------- 5 files changed, 161 deletions(-) delete mode 100644 src/Mod/Spreadsheet/Gui/SpreadsheetViewPy.xml delete mode 100644 src/Mod/Spreadsheet/Gui/SpreadsheetViewPyImp.cpp diff --git a/src/Mod/Spreadsheet/Gui/CMakeLists.txt b/src/Mod/Spreadsheet/Gui/CMakeLists.txt index 61ff766fa2..cbffc4e9b3 100644 --- a/src/Mod/Spreadsheet/Gui/CMakeLists.txt +++ b/src/Mod/Spreadsheet/Gui/CMakeLists.txt @@ -8,12 +8,10 @@ include_directories( ${XercesC_INCLUDE_DIRS} ) -generate_from_xml(SpreadsheetViewPy) generate_from_xml(ViewProviderSpreadsheetPy) # The XML files set(SpreadsheetGui_XML_SRCS - SpreadsheetViewPy.xml ViewProviderSpreadsheetPy.xml ) @@ -77,7 +75,6 @@ SET(SpreadsheetGui_SRCS Resources/Spreadsheet.qrc SpreadsheetView.cpp SpreadsheetView.h - SpreadsheetViewPyImp.cpp SpreadsheetDelegate.h SpreadsheetDelegate.cpp SheetTableView.cpp diff --git a/src/Mod/Spreadsheet/Gui/SpreadsheetViewPy.xml b/src/Mod/Spreadsheet/Gui/SpreadsheetViewPy.xml deleted file mode 100644 index 618ddfa7b4..0000000000 --- a/src/Mod/Spreadsheet/Gui/SpreadsheetViewPy.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - SpreadsheetView object - - - - returns the sheet being displayed - - - - - diff --git a/src/Mod/Spreadsheet/Gui/SpreadsheetViewPyImp.cpp b/src/Mod/Spreadsheet/Gui/SpreadsheetViewPyImp.cpp deleted file mode 100644 index 08b47d8e5d..0000000000 --- a/src/Mod/Spreadsheet/Gui/SpreadsheetViewPyImp.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "PreCompiled.h" - -#include "SpreadsheetViewPy.h" -#include "SpreadsheetViewPy.cpp" -#include "ui_Sheet.h" - -#include - -using namespace SpreadsheetGui; - -PyObject* SpreadsheetViewPy::getSheet(PyObject *args) -{ - if (!PyArg_ParseTuple(args, "")) - return nullptr; - return new Spreadsheet::SheetPy(getSheetViewPtr()->getSheet()); -} - -// returns a string which represents the object e.g. when printed in python -std::string SpreadsheetViewPy::representation(void) const -{ - return std::string(""); -} - -PyObject *SpreadsheetViewPy::getCustomAttributes(const char* /*attr*/) const -{ - return 0; -} - -int SpreadsheetViewPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) -{ - return 0; -} diff --git a/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheetPy.xml b/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheetPy.xml index d14f891c03..2434e12d36 100644 --- a/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheetPy.xml +++ b/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheetPy.xml @@ -15,32 +15,6 @@ ViewProviderSheet class - - - returns a list with the selected ranges of cells - - - - - returns a list with the selected cells - - - - - select(index, flags): Select the specified cell using the given QItemSelectionModel.SelectionFlag set -select(topLeft, bottomRight, flags): Select the specified range using the given QItemSelectionModel.SelectionFlag set - - - - - Get the current active cell - - - - - Set the current active cell - - Get access to the sheet view diff --git a/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheetPyImp.cpp b/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheetPyImp.cpp index bea7958ee6..12ba9d5684 100644 --- a/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheetPyImp.cpp +++ b/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheetPyImp.cpp @@ -14,83 +14,6 @@ std::string ViewProviderSpreadsheetPy::representation(void) const return std::string(""); } - -PyObject* ViewProviderSpreadsheetPy::selectedRanges(PyObject* /*obj*/) -{ - ViewProviderSheet* vp = this->getViewProviderSheetPtr(); - SheetView *sheetView = vp->getView(); - std::vector ranges = sheetView->selectedRanges(); - Py::List list; - for (const auto &range : ranges) - { - list.append(Py::String(range.rangeString())); - } - - return Py::new_reference_to(list); -} - -PyObject* ViewProviderSpreadsheetPy::selectedCells(PyObject* /*obj*/) -{ - ViewProviderSheet* vp = this->getViewProviderSheetPtr(); - SheetView *sheetView = vp->getView(); - QModelIndexList cells = sheetView->selectedIndexes(); - Py::List list; - for (const auto &cell : cells) { - list.append(Py::String(App::CellAddress(cell.row(), cell.column()).toString())); - } - - return Py::new_reference_to(list); -} - -PyObject* ViewProviderSpreadsheetPy::select(PyObject* _args) -{ - ViewProviderSheet* vp = this->getViewProviderSheetPtr(); - SheetView* sheetView = vp->getView(); - - Py::Sequence args(_args); - - const char* cell; - const char* topLeft; - const char* bottomRight; - int flags = 0; - if (args.size() == 2 && PyArg_ParseTuple(_args, "si", &cell, &flags)) { - sheetView->select(App::CellAddress(cell), static_cast(flags)); - } - else if (args.size() == 3 && PyArg_ParseTuple(_args, "ssi", &topLeft, &bottomRight, &flags)) { - sheetView->select(App::CellAddress(topLeft), App::CellAddress(bottomRight), static_cast(flags)); - } - else { - if (args.size() == 2) - throw Base::TypeError("Expects the arguments to be a cell name (e.g. 'A1') and QItemSelectionModel.SelectionFlags"); - else if (args.size() == 3) - throw Base::TypeError("Expects the arguments to be a cell name (e.g. 'A1'), a second cell name (e.g. 'B5'), and QItemSelectionModel.SelectionFlags"); - else - throw Base::TypeError("Wrong arguments to select: specify either a cell, or two cells (for a range), and QItemSelectionModel.SelectionFlags"); - } - Py_RETURN_NONE; -} - -PyObject* ViewProviderSpreadsheetPy::currentIndex(PyObject* /*_args*/) -{ - ViewProviderSheet* vp = this->getViewProviderSheetPtr(); - SheetView* sheetView = vp->getView(); - auto index = sheetView->currentIndex(); - Py::String str(App::CellAddress(index.row(), index.column()).toString()); - return Py::new_reference_to(str); -} - -PyObject* ViewProviderSpreadsheetPy::setCurrentIndex(PyObject* args) -{ - ViewProviderSheet* vp = this->getViewProviderSheetPtr(); - SheetView* sheetView = vp->getView(); - - const char* cell; - if (PyArg_ParseTuple(args, "s", &cell)) { - sheetView->setCurrentIndex(App::CellAddress(cell)); - } - Py_RETURN_NONE; -} - PyObject* ViewProviderSpreadsheetPy::getView(PyObject* args) { if (!PyArg_ParseTuple(args, "")) From 2c701c09857189dd49b46363e03e8ad341baeda4 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 20 Nov 2021 14:39:06 +0100 Subject: [PATCH 023/133] Spreadsheet: [skip ci] return Py::None() instead of Py::Object() --- src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp index 007d534e82..a37ad89b37 100644 --- a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp +++ b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp @@ -595,7 +595,7 @@ Py::Object SheetViewPy::select(const Py::Tuple& _args) else throw Base::TypeError("Wrong arguments to select: specify either a cell, or two cells (for a range), and QItemSelectionModel.SelectionFlags"); } - return Py::Object(); + return Py::None(); } Py::Object SheetViewPy::currentIndex(const Py::Tuple& args) @@ -616,7 +616,7 @@ Py::Object SheetViewPy::setCurrentIndex(const Py::Tuple& args) if (PyArg_ParseTuple(args.ptr(), "s", &cell)) { sheetView->setCurrentIndex(App::CellAddress(cell)); } - return Py::Object(); + return Py::None(); } From 71e70c876b2c22105ac828c3da721e6ff3e41e0b Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Mon, 15 Nov 2021 16:02:37 -0500 Subject: [PATCH 024/133] [PD] Use `PropertyLinkSubList` for loft and sweep sections This change is necessary since we restrict part-design features to only use other features from the same body. --- src/Mod/PartDesign/App/FeatureLoft.h | 2 +- src/Mod/PartDesign/App/FeaturePipe.h | 2 +- src/Mod/PartDesign/Gui/TaskLoftParameters.cpp | 22 ++++++------ src/Mod/PartDesign/Gui/TaskPipeParameters.cpp | 34 ++++++++++++------- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureLoft.h b/src/Mod/PartDesign/App/FeatureLoft.h index 270cdfbda7..ad4658e566 100644 --- a/src/Mod/PartDesign/App/FeatureLoft.h +++ b/src/Mod/PartDesign/App/FeatureLoft.h @@ -40,7 +40,7 @@ class PartDesignExport Loft : public ProfileBased public: Loft(); - App::PropertyXLinkSubList Sections; + App::PropertyLinkSubList Sections; App::PropertyBool Ruled; App::PropertyBool Closed; diff --git a/src/Mod/PartDesign/App/FeaturePipe.h b/src/Mod/PartDesign/App/FeaturePipe.h index e173cc3830..7e8a7802c7 100644 --- a/src/Mod/PartDesign/App/FeaturePipe.h +++ b/src/Mod/PartDesign/App/FeaturePipe.h @@ -47,7 +47,7 @@ public: App::PropertyVector Binormal; App::PropertyEnumeration Transition; App::PropertyEnumeration Transformation; - App::PropertyXLinkSubList Sections; + App::PropertyLinkSubList Sections; App::DocumentObjectExecReturn *execute(void); short mustExecute() const; diff --git a/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp b/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp index 4b69d9313d..db0d0d65fe 100644 --- a/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp @@ -50,6 +50,8 @@ #include "TaskSketchBasedParameters.h" #include "ReferenceSelection.h" +Q_DECLARE_METATYPE(App::PropertyLinkSubList::SubSet); + using namespace PartDesignGui; using namespace Gui; @@ -107,13 +109,13 @@ TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView, bool /*newObj ui->profileBaseEdit->setText(label); } - for (auto obj : loft->Sections.getValues()) { - Gui::Application::Instance->showViewProvider(obj); + for (auto &subSet : loft->Sections.getSubListValues()) { + Gui::Application::Instance->showViewProvider(subSet.first); - QString label = make2DLabel(obj, loft->Sections.getSubValues(obj)); + QString label = make2DLabel(subSet.first, subSet.second); QListWidgetItem* item = new QListWidgetItem(); item->setText(label); - item->setData(Qt::UserRole, QByteArray(obj->getNameInDocument())); + item->setData(Qt::UserRole, QVariant::fromValue(subSet)); ui->listWidgetReferences->addItem(item); } @@ -157,7 +159,8 @@ void TaskLoftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) else if (selectionMode == refAdd) { QListWidgetItem* item = new QListWidgetItem(); item->setText(label); - item->setData(Qt::UserRole, QByteArray(msg.pObjectName)); + item->setData(Qt::UserRole, + QVariant::fromValue(std::make_pair(object, std::vector(1, msg.pSubName)))); ui->listWidgetReferences->addItem(item); } else if (selectionMode == refRemove) { @@ -243,7 +246,7 @@ void TaskLoftParameters::onDeleteSection() int row = ui->listWidgetReferences->currentRow(); QListWidgetItem* item = ui->listWidgetReferences->takeItem(row); if (item) { - QByteArray data = item->data(Qt::UserRole).toByteArray(); + QByteArray data(item->data(Qt::UserRole).value().first->getNameInDocument()); delete item; // search inside the list of sections @@ -270,17 +273,16 @@ void TaskLoftParameters::indexesMoved() return; PartDesign::Loft* loft = static_cast(vp->getObject()); - std::vector originals = loft->Sections.getValues(); + auto originals = loft->Sections.getSubListValues(); QByteArray name; int rows = model->rowCount(); for (int i = 0; i < rows; i++) { QModelIndex index = model->index(i, 0); - name = index.data(Qt::UserRole).toByteArray().constData(); - originals[i] = loft->getDocument()->getObject(name.constData()); + originals[i] = index.data(Qt::UserRole).value(); } - loft->Sections.setValues(originals); + loft->Sections.setSubListValues(originals); recomputeFeature(); updateUI(); } diff --git a/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp b/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp index a2d9cd765d..d7d1796ce0 100644 --- a/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp @@ -60,6 +60,8 @@ #include "Utils.h" #include "TaskFeaturePick.h" +Q_DECLARE_METATYPE(App::PropertyLinkSubList::SubSet); + using namespace PartDesignGui; using namespace Gui; @@ -540,21 +542,26 @@ bool TaskPipeParameters::accept() copies.push_back(pcPipe->AuxillerySpine.getValue()); } - std::vector objs; + std::vector subSets; int index = 0; - for (App::DocumentObject* obj : pcPipe->Sections.getValues()) { - if (!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) { - objs.push_back(PartDesignGui::TaskFeaturePick::makeCopy(obj, "", dlg.radioIndependent->isChecked())); - copies.push_back(objs.back()); + for (auto &subSet : pcPipe->Sections.getSubListValues()) { + if (!pcActiveBody->hasObject(subSet.first) && + !pcActiveBody->getOrigin()->hasObject(subSet.first)) { + subSets.push_back( + std::make_pair( + PartDesignGui::TaskFeaturePick::makeCopy( + subSet.first, "", dlg.radioIndependent->isChecked()), + subSet.second)); + copies.push_back(subSets.back().first); } else { - objs.push_back(obj); + subSets.push_back(subSet); } index++; } - pcPipe->Sections.setValues(objs); + pcPipe->Sections.setSubListValues(subSets); } } @@ -934,12 +941,12 @@ TaskPipeScaling::TaskPipeScaling(ViewProviderPipe* PipeView, bool /*newObj*/, QW this->groupLayout()->addWidget(proxy); PartDesign::Pipe* pipe = static_cast(PipeView->getObject()); - for (auto obj : pipe->Sections.getValues()) { - Gui::Application::Instance->showViewProvider(obj); - QString label = make2DLabel(obj, pipe->Sections.getSubValues(obj)); + for (auto &subSet : pipe->Sections.getSubListValues()) { + Gui::Application::Instance->showViewProvider(subSet.first); + QString label = make2DLabel(subSet.first, subSet.second); QListWidgetItem* item = new QListWidgetItem(); item->setText(label); - item->setData(Qt::UserRole, QByteArray(obj->getNameInDocument())); + item->setData(Qt::UserRole, QVariant::fromValue(subSet)); ui->listWidgetReferences->addItem(item); } @@ -1022,7 +1029,8 @@ void TaskPipeScaling::onSelectionChanged(const SelectionChanges& msg) if (selectionMode == refAdd) { QListWidgetItem* item = new QListWidgetItem(); item->setText(label); - item->setData(Qt::UserRole, QByteArray(msg.pObjectName)); + item->setData(Qt::UserRole, + QVariant::fromValue(std::make_pair(object, std::vector(1, msg.pSubName)))); ui->listWidgetReferences->addItem(item); } else if (selectionMode == refRemove) { @@ -1098,7 +1106,7 @@ void TaskPipeScaling::onDeleteSection() int row = ui->listWidgetReferences->currentRow(); QListWidgetItem* item = ui->listWidgetReferences->takeItem(row); if (item) { - QByteArray data = item->data(Qt::UserRole).toByteArray(); + QByteArray data(item->data(Qt::UserRole).value().first->getNameInDocument()); delete item; // search inside the list of sections From 195144fdc37ea498fce785d146b0abbb57df134f Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 20 Nov 2021 22:49:51 +0100 Subject: [PATCH 025/133] Gui: make sure the calltips show the added methods of MainWindowPy --- src/Gui/CallTips.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Gui/CallTips.cpp b/src/Gui/CallTips.cpp index 2a1a5e63b9..9927de2f10 100644 --- a/src/Gui/CallTips.cpp +++ b/src/Gui/CallTips.cpp @@ -277,9 +277,13 @@ QMap CallTipsList::extractTips(const QString& context) const // Make sure it's not a type object union PyType_Object typetype = {&PyType_Type}; if (PyObject_IsInstance(obj.ptr(), typetype.o) != 1) { + // For wrapped objects with PySide2 use the object, not its type + // as otherwise attributes added at runtime won't be listed (e.g. MainWindowPy) + QString typestr(QLatin1String(Py_TYPE(obj.ptr())->tp_name)); + // this should be now a user-defined Python class // http://stackoverflow.com/questions/12233103/in-python-at-runtime-determine-if-an-object-is-a-class-old-and-new-type-instan - if (Py_TYPE(obj.ptr())->tp_flags & Py_TPFLAGS_HEAPTYPE) { + if (!typestr.startsWith(QLatin1String("PySide")) && Py_TYPE(obj.ptr())->tp_flags & Py_TPFLAGS_HEAPTYPE) { obj = type; } } From c93031da393ed69a80dc07cca762d0879f33b23a Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 21 Nov 2021 14:32:36 +0100 Subject: [PATCH 026/133] Gui: expose some more methods of MDIView to Python --- src/Gui/MDIViewPy.cpp | 70 +++++++++++++++++++++++++++++++++++++++++++ src/Gui/MDIViewPy.h | 13 ++++++++ 2 files changed, 83 insertions(+) diff --git a/src/Gui/MDIViewPy.cpp b/src/Gui/MDIViewPy.cpp index b2005957bc..23b7a255d3 100644 --- a/src/Gui/MDIViewPy.cpp +++ b/src/Gui/MDIViewPy.cpp @@ -55,6 +55,13 @@ void MDIViewPy::init_type() behaviors().supportSetattr(); behaviors().set_tp_new(extension_object_new); + add_varargs_method("printView",&MDIViewPy::printView,"printView()"); + add_varargs_method("printPdf",&MDIViewPy::printPdf,"printPdf()"); + add_varargs_method("printPreview",&MDIViewPy::printPreview,"printPreview()"); + + add_varargs_method("undoActions",&MDIViewPy::undoActions,"undoActions()"); + add_varargs_method("redoActions",&MDIViewPy::redoActions,"redoActions()"); + add_varargs_method("message",&MDIViewPy::sendMessage,"deprecated: use sendMessage"); add_varargs_method("sendMessage",&MDIViewPy::sendMessage,"sendMessage(str)"); add_varargs_method("supportMessage",&MDIViewPy::supportMessage,"supportMessage(str)"); @@ -104,6 +111,69 @@ Py::Object MDIViewPy::repr() return Py::String(s_out.str()); } +Py::Object MDIViewPy::printView(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + + if (_view) + _view->print(); + + return Py::None(); +} + +Py::Object MDIViewPy::printPdf(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + + if (_view) + _view->printPdf(); + + return Py::None(); +} + +Py::Object MDIViewPy::printPreview(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + + if (_view) + _view->printPreview(); + + return Py::None(); +} + +Py::Object MDIViewPy::undoActions(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + + Py::List list; + if (_view) { + QStringList undo = _view->undoActions(); + for (const auto& it : undo) + list.append(Py::String(it.toStdString())); + } + + return list; +} + +Py::Object MDIViewPy::redoActions(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + + Py::List list; + if (_view) { + QStringList redo = _view->redoActions(); + for (const auto& it : redo) + list.append(Py::String(it.toStdString())); + } + + return list; +} + Py::Object MDIViewPy::sendMessage(const Py::Tuple& args) { const char **ppReturn = 0; diff --git a/src/Gui/MDIViewPy.h b/src/Gui/MDIViewPy.h index aee3897ff3..86ced43a8b 100644 --- a/src/Gui/MDIViewPy.h +++ b/src/Gui/MDIViewPy.h @@ -46,6 +46,19 @@ public: Py::Object repr(); + /** @name Printing */ + //@{ + Py::Object printView(const Py::Tuple&); + Py::Object printPdf(const Py::Tuple&); + Py::Object printPreview(const Py::Tuple&); + //@} + + /** @name Undo/Redo actions */ + //@{ + Py::Object undoActions(const Py::Tuple&); + Py::Object redoActions(const Py::Tuple&); + //@} + Py::Object sendMessage(const Py::Tuple&); Py::Object supportMessage(const Py::Tuple&); Py::Object fitAll(const Py::Tuple&); From 8de5d37fbac39541be9ad7fe8e44aba1c4dd5078 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 21 Nov 2021 15:34:33 +0100 Subject: [PATCH 027/133] Web: make BrowserViwePy acting as sub-class of MDIViewPy --- src/Mod/Web/Gui/BrowserView.cpp | 88 +++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 5 deletions(-) diff --git a/src/Mod/Web/Gui/BrowserView.cpp b/src/Mod/Web/Gui/BrowserView.cpp index 6e67d5b421..3c202a30bc 100644 --- a/src/Mod/Web/Gui/BrowserView.cpp +++ b/src/Mod/Web/Gui/BrowserView.cpp @@ -77,6 +77,7 @@ using QWebEnginePage = QWebPage; #include "CookieJar.h" #include #include +#include #include #include #include @@ -170,17 +171,25 @@ void UrlWidget::display() class BrowserViewPy : public Py::PythonExtension { public: - static void init_type(void); // announce properties and methods + using BaseType = Py::PythonExtension; + static void init_type(); // announce properties and methods BrowserViewPy(BrowserView* view); ~BrowserViewPy(); Py::Object repr(); + Py::Object getattr(const char *); + Py::Object cast_to_base(const Py::Tuple&); Py::Object setHtml(const Py::Tuple&); + Py::Object load(const Py::Tuple&); + Py::Object stop(const Py::Tuple&); + Py::Object url(const Py::Tuple&); + + BrowserView* getBrowserViewPtr(); private: - QPointer myWebView; + Gui::MDIViewPy base; }; void BrowserViewPy::init_type() @@ -194,9 +203,13 @@ void BrowserViewPy::init_type() behaviors().readyType(); add_varargs_method("setHtml",&BrowserViewPy::setHtml,"setHtml(str)"); + add_varargs_method("load",&BrowserViewPy::load,"load(url)"); + add_varargs_method("stop",&BrowserViewPy::stop,"stop()"); + add_varargs_method("url",&BrowserViewPy::url,"url()"); + add_varargs_method("cast_to_base", &BrowserViewPy::cast_to_base, "cast_to_base() cast to MDIView class"); } -BrowserViewPy::BrowserViewPy(BrowserView* view) : myWebView(view) +BrowserViewPy::BrowserViewPy(BrowserView* view) : base(view) { } @@ -204,6 +217,16 @@ BrowserViewPy::~BrowserViewPy() { } +BrowserView* BrowserViewPy::getBrowserViewPtr() +{ + return qobject_cast(base.getMDIViewPtr()); +} + +Py::Object BrowserViewPy::cast_to_base(const Py::Tuple&) +{ + return Gui::MDIViewPy::create(base.getMDIViewPtr()); +} + Py::Object BrowserViewPy::repr() { std::stringstream s; @@ -211,6 +234,33 @@ Py::Object BrowserViewPy::repr() return Py::String(s.str()); } +// Since with PyCXX it's not possible to make a sub-class of MDIViewPy +// a trick is to use MDIViewPy as class member and override getattr() to +// join the attributes of both classes. This way all methods of MDIViewPy +// appear for SheetViewPy, too. +Py::Object BrowserViewPy::getattr(const char * attr) +{ + if (!getBrowserViewPtr()) + throw Py::RuntimeError("Cannot print representation of deleted object"); + std::string name( attr ); + if (name == "__dict__" || name == "__class__") { + Py::Dict dict_self(BaseType::getattr("__dict__")); + Py::Dict dict_base(base.getattr("__dict__")); + for (auto it : dict_base) { + dict_self.setItem(it.first, it.second); + } + return dict_self; + } + + try { + return BaseType::getattr(attr); + } + catch (Py::AttributeError& e) { + e.clear(); + return base.getattr(attr); + } +} + Py::Object BrowserViewPy::setHtml(const Py::Tuple& args) { char* HtmlCode; @@ -221,10 +271,38 @@ Py::Object BrowserViewPy::setHtml(const Py::Tuple& args) std::string EncodedHtml = std::string(HtmlCode); PyMem_Free(HtmlCode); - if (myWebView) - myWebView->setHtml(QString::fromUtf8(EncodedHtml.c_str()), QUrl(QString::fromUtf8(BaseUrl))); + getBrowserViewPtr()->setHtml(QString::fromUtf8(EncodedHtml.c_str()), QUrl(QString::fromUtf8(BaseUrl))); return Py::None(); } + +Py::Object BrowserViewPy::load(const Py::Tuple& args) +{ + char* BaseUrl; + if (!PyArg_ParseTuple(args.ptr(), "s", &BaseUrl)) + throw Py::Exception(); + + getBrowserViewPtr()->load(BaseUrl); + return Py::None(); +} + +Py::Object BrowserViewPy::stop(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + + getBrowserViewPtr()->stop(); + return Py::None(); +} + +Py::Object BrowserViewPy::url(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + + QUrl url = getBrowserViewPtr()->url(); + return Py::String(url.toString().toStdString()); +} + } /** From cf337394a16c42a4e65740b7dffa450e76bb5b6a Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 21 Nov 2021 15:44:06 +0100 Subject: [PATCH 028/133] Gui: in repr() of MDIViewPy write the typeid name --- src/Gui/MDIViewPy.cpp | 2 +- src/Mod/Drawing/Gui/DrawingView.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Gui/MDIViewPy.cpp b/src/Gui/MDIViewPy.cpp index 23b7a255d3..a196101b45 100644 --- a/src/Gui/MDIViewPy.cpp +++ b/src/Gui/MDIViewPy.cpp @@ -107,7 +107,7 @@ Py::Object MDIViewPy::repr() std::ostringstream s_out; if (!_view) throw Py::RuntimeError("Cannot print representation of deleted object"); - s_out << "MDIView"; + s_out << _view->getTypeId().getName(); return Py::String(s_out.str()); } diff --git a/src/Mod/Drawing/Gui/DrawingView.cpp b/src/Mod/Drawing/Gui/DrawingView.cpp index bca5828799..69bcded867 100644 --- a/src/Mod/Drawing/Gui/DrawingView.cpp +++ b/src/Mod/Drawing/Gui/DrawingView.cpp @@ -681,7 +681,7 @@ void DrawingView::viewAll() PyObject* DrawingView::getPyObject() { - Py_Return; + return Gui::MDIView::getPyObject(); } #include "moc_DrawingView.cpp" From d64b698d0559deb6cf533de2b2082a24a2fcf4b7 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 21 Nov 2021 17:33:19 +0100 Subject: [PATCH 029/133] TD: make MDIViewPagePy acting as sub-class of MDIViewPy --- src/Mod/TechDraw/Gui/AppTechDrawGui.cpp | 1 + src/Mod/TechDraw/Gui/CMakeLists.txt | 4 -- src/Mod/TechDraw/Gui/MDIViewPage.cpp | 80 ++++++++++++++++++++++- src/Mod/TechDraw/Gui/MDIViewPage.h | 23 ++++++- src/Mod/TechDraw/Gui/MDIViewPagePy.xml | 23 ------- src/Mod/TechDraw/Gui/MDIViewPagePyImp.cpp | 43 ------------ 6 files changed, 102 insertions(+), 72 deletions(-) delete mode 100644 src/Mod/TechDraw/Gui/MDIViewPagePy.xml delete mode 100644 src/Mod/TechDraw/Gui/MDIViewPagePyImp.cpp diff --git a/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp b/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp index 5f2978d8bb..4e84646f4e 100644 --- a/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp +++ b/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp @@ -125,6 +125,7 @@ PyMOD_INIT_FUNC(TechDrawGui) TechDrawGui::Workbench::init(); TechDrawGui::MDIViewPage::init(); + TechDrawGui::MDIViewPagePy::init_type(); TechDrawGui::ViewProviderPage::init(); TechDrawGui::ViewProviderDrawingView::init(); diff --git a/src/Mod/TechDraw/Gui/CMakeLists.txt b/src/Mod/TechDraw/Gui/CMakeLists.txt index a8cfc77149..1cffb31d8f 100644 --- a/src/Mod/TechDraw/Gui/CMakeLists.txt +++ b/src/Mod/TechDraw/Gui/CMakeLists.txt @@ -36,11 +36,8 @@ else(BUILD_QT5) ) endif(BUILD_QT5) -generate_from_xml(MDIViewPagePy) - # The XML files set(TechDrawGui_XML_SRCS - MDIViewPagePy.xml ) link_directories(${OCC_LIBRARY_DIR}) @@ -206,7 +203,6 @@ SET(TechDrawGui_SRCS SET(TechDrawGuiView_SRCS MDIViewPage.cpp MDIViewPage.h - MDIViewPagePyImp.cpp QGVPage.cpp QGVPage.h QGCustomText.cpp diff --git a/src/Mod/TechDraw/Gui/MDIViewPage.cpp b/src/Mod/TechDraw/Gui/MDIViewPage.cpp index d5404a5cb8..5ff113d1ea 100644 --- a/src/Mod/TechDraw/Gui/MDIViewPage.cpp +++ b/src/Mod/TechDraw/Gui/MDIViewPage.cpp @@ -47,7 +47,6 @@ #include #include "MDIViewPage.h" -#include "MDIViewPagePy.h" #include #include @@ -71,6 +70,7 @@ #include #include +#include #include #include #include @@ -1375,4 +1375,82 @@ MDIViewPage *MDIViewPage::getFromScene(const QGraphicsScene *scene) return nullptr; } +// ---------------------------------------------------------------------------- + +void MDIViewPagePy::init_type() +{ + behaviors().name("MDIViewPagePy"); + behaviors().doc("Python binding class for the MDI view page class"); + // you must have overwritten the virtual functions + behaviors().supportRepr(); + behaviors().supportGetattr(); + behaviors().supportSetattr(); + + add_varargs_method("getPage", &MDIViewPagePy::getPage, "getPage() returns the page being displayed"); + add_varargs_method("cast_to_base", &MDIViewPagePy::cast_to_base, "cast_to_base() cast to MDIView class"); + behaviors().readyType(); +} + +MDIViewPagePy::MDIViewPagePy(MDIViewPage *mdi) + : base(mdi) +{ +} + +MDIViewPagePy::~MDIViewPagePy() +{ +} + +Py::Object MDIViewPagePy::repr() +{ + std::ostringstream s_out; + if (!getMDIViewPagePtr()) + throw Py::RuntimeError("Cannot print representation of deleted object"); + s_out << "MDI view page"; + return Py::String(s_out.str()); +} + +// Since with PyCXX it's not possible to make a sub-class of MDIViewPy +// a trick is to use MDIViewPy as class member and override getattr() to +// join the attributes of both classes. This way all methods of MDIViewPy +// appear for SheetViewPy, too. +Py::Object MDIViewPagePy::getattr(const char * attr) +{ + if (!getMDIViewPagePtr()) + throw Py::RuntimeError("Cannot print representation of deleted object"); + std::string name( attr ); + if (name == "__dict__" || name == "__class__") { + Py::Dict dict_self(BaseType::getattr("__dict__")); + Py::Dict dict_base(base.getattr("__dict__")); + for (auto it : dict_base) { + dict_self.setItem(it.first, it.second); + } + return dict_self; + } + + try { + return BaseType::getattr(attr); + } + catch (Py::AttributeError& e) { + e.clear(); + return base.getattr(attr); + } +} + +MDIViewPage* MDIViewPagePy::getMDIViewPagePtr() +{ + return qobject_cast(base.getMDIViewPtr()); +} + +Py::Object MDIViewPagePy::getPage(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + return Py::asObject(new TechDraw::DrawPagePy(getMDIViewPagePtr()->getPage())); +} + +Py::Object MDIViewPagePy::cast_to_base(const Py::Tuple&) +{ + return Gui::MDIViewPy::create(base.getMDIViewPtr()); +} + #include diff --git a/src/Mod/TechDraw/Gui/MDIViewPage.h b/src/Mod/TechDraw/Gui/MDIViewPage.h index ba5c85b4cd..e2f2655ce8 100644 --- a/src/Mod/TechDraw/Gui/MDIViewPage.h +++ b/src/Mod/TechDraw/Gui/MDIViewPage.h @@ -27,6 +27,7 @@ #include "ViewProviderPage.h" #include +#include #include #include @@ -96,7 +97,7 @@ public: PyObject* getPyObject(); TechDraw::DrawPage * getPage() { return m_vpPage->getDrawPage(); } - QGVPage* getQGVPage(void) {return m_view;}; + QGVPage* getQGVPage(void) {return m_view;} QGraphicsScene* m_scene; @@ -173,6 +174,26 @@ private: QList deleteItems; }; +class MDIViewPagePy : public Py::PythonExtension +{ +public: + using BaseType = Py::PythonExtension; + static void init_type(); + + MDIViewPagePy(MDIViewPage *mdi); + ~MDIViewPagePy(); + + Py::Object repr(); + Py::Object getattr(const char *); + Py::Object getPage(const Py::Tuple&); + Py::Object cast_to_base(const Py::Tuple&); + + MDIViewPage* getMDIViewPagePtr(); + +protected: + Gui::MDIViewPy base; +}; + } // namespace MDIViewPageGui diff --git a/src/Mod/TechDraw/Gui/MDIViewPagePy.xml b/src/Mod/TechDraw/Gui/MDIViewPagePy.xml deleted file mode 100644 index 25292969f8..0000000000 --- a/src/Mod/TechDraw/Gui/MDIViewPagePy.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - MDIViewPage object - - - - returns the page being displayed - - - - - diff --git a/src/Mod/TechDraw/Gui/MDIViewPagePyImp.cpp b/src/Mod/TechDraw/Gui/MDIViewPagePyImp.cpp deleted file mode 100644 index e59dc8c326..0000000000 --- a/src/Mod/TechDraw/Gui/MDIViewPagePyImp.cpp +++ /dev/null @@ -1,43 +0,0 @@ - -#include "PreCompiled.h" - -#include "Mod/TechDraw/Gui/MDIViewPage.h" - -// inclusion of the generated files (generated out of MDIViewPagePy.xml) -#include "MDIViewPagePy.h" -#include "MDIViewPagePy.cpp" - -#include - -using namespace TechDrawGui; - -// returns a string which represents the object e.g. when printed in python -std::string MDIViewPagePy::representation() const -{ - return std::string(""); -} - - - -PyObject* MDIViewPagePy::getPage(PyObject * args) -{ - if (!PyArg_ParseTuple(args, "")) - return nullptr; - return new TechDraw::DrawPagePy(getMDIViewPagePtr()->getPage()); -} - - - - - -PyObject *MDIViewPagePy::getCustomAttributes(const char* /*attr*/) const -{ - return nullptr; -} - -int MDIViewPagePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) -{ - return 0; -} - - From 292f6dcaa755d6e3cfced8666e22ae67c437d053 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 21 Nov 2021 18:59:28 +0100 Subject: [PATCH 030/133] Gui: make AbstractSplitViewPy acting as sub-class of MDIViewPy --- src/Gui/SplitView3DInventor.cpp | 114 +++++++++++++++++++++----------- src/Gui/SplitView3DInventor.h | 14 ++-- 2 files changed, 86 insertions(+), 42 deletions(-) diff --git a/src/Gui/SplitView3DInventor.cpp b/src/Gui/SplitView3DInventor.cpp index 7db754c7dd..78a7102da5 100644 --- a/src/Gui/SplitView3DInventor.cpp +++ b/src/Gui/SplitView3DInventor.cpp @@ -38,6 +38,7 @@ #include "Application.h" #include "NavigationStyle.h" #include "View3DPy.h" +#include using namespace Gui; @@ -47,7 +48,7 @@ TYPESYSTEM_SOURCE_ABSTRACT(Gui::AbstractSplitView,Gui::MDIView) AbstractSplitView::AbstractSplitView(Gui::Document* pcDocument, QWidget* parent, Qt::WindowFlags wflags) : MDIView(pcDocument,parent, wflags) { - _viewerPy = 0; + _viewerPy = nullptr; // important for highlighting setMouseTracking(true); } @@ -59,7 +60,7 @@ AbstractSplitView::~AbstractSplitView() delete *it; } if (_viewerPy) { - static_cast(_viewerPy)->_view = 0; + Base::PyGILStateLocker lock; Py_DECREF(_viewerPy); } } @@ -72,6 +73,12 @@ void AbstractSplitView::deleteSelf() MDIView::deleteSelf(); } +void AbstractSplitView::viewAll() +{ + for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) + (*it)->viewAll(); +} + bool AbstractSplitView::containsViewProvider(const ViewProvider* vp) const { for (auto it = _viewer.begin(); it != _viewer.end(); ++it) { @@ -307,8 +314,7 @@ const char *AbstractSplitView::getName(void) const bool AbstractSplitView::onMsg(const char* pMsg, const char**) { if (strcmp("ViewFit",pMsg) == 0 ) { - for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) - (*it)->viewAll(); + viewAll(); return true; } else if (strcmp("ViewBottom",pMsg) == 0) { @@ -439,6 +445,8 @@ void AbstractSplitViewPy::init_type() behaviors().doc("Python binding class for the Inventor viewer class"); // you must have overwritten the virtual functions behaviors().supportRepr(); + behaviors().supportGetattr(); + behaviors().supportSetattr(); behaviors().supportSequenceType(); add_varargs_method("fitAll",&AbstractSplitViewPy::fitAll,"fitAll()"); @@ -452,10 +460,12 @@ void AbstractSplitViewPy::init_type() add_varargs_method("viewIsometric",&AbstractSplitViewPy::viewIsometric,"viewIsometric()"); add_varargs_method("getViewer",&AbstractSplitViewPy::getViewer,"getViewer(index)"); add_varargs_method("close",&AbstractSplitViewPy::close,"close()"); + add_varargs_method("cast_to_base", &AbstractSplitViewPy::cast_to_base, "cast_to_base() cast to MDIView class"); + behaviors().readyType(); } AbstractSplitViewPy::AbstractSplitViewPy(AbstractSplitView *vi) - : _view(vi) + : base(vi) { } @@ -463,30 +473,61 @@ AbstractSplitViewPy::~AbstractSplitViewPy() { } -void AbstractSplitViewPy::testExistence() +Py::Object AbstractSplitViewPy::cast_to_base(const Py::Tuple&) { - if (!(_view && _view->getViewer(0))) - throw Py::RuntimeError("Object already deleted"); + return Gui::MDIViewPy::create(base.getMDIViewPtr()); } Py::Object AbstractSplitViewPy::repr() { - std::string s; std::ostringstream s_out; - if (!_view) + if (!getSplitViewPtr()) throw Py::RuntimeError("Cannot print representation of deleted object"); s_out << "AbstractSplitView"; return Py::String(s_out.str()); } +// Since with PyCXX it's not possible to make a sub-class of MDIViewPy +// a trick is to use MDIViewPy as class member and override getattr() to +// join the attributes of both classes. This way all methods of MDIViewPy +// appear for SheetViewPy, too. +Py::Object AbstractSplitViewPy::getattr(const char * attr) +{ + getSplitViewPtr(); + std::string name( attr ); + if (name == "__dict__" || name == "__class__") { + Py::Dict dict_self(BaseType::getattr("__dict__")); + Py::Dict dict_base(base.getattr("__dict__")); + for (auto it : dict_base) { + dict_self.setItem(it.first, it.second); + } + return dict_self; + } + + try { + return BaseType::getattr(attr); + } + catch (Py::AttributeError& e) { + e.clear(); + return base.getattr(attr); + } +} + +AbstractSplitView* AbstractSplitViewPy::getSplitViewPtr() +{ + AbstractSplitView* view = qobject_cast(base.getMDIViewPtr()); + if (!(view && view->getViewer(0))) + throw Py::RuntimeError("Object already deleted"); + return view; +} + Py::Object AbstractSplitViewPy::fitAll(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewFit", 0); + getSplitViewPtr()->onMsg("ViewFit", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -504,10 +545,9 @@ Py::Object AbstractSplitViewPy::viewBottom(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewBottom", 0); + getSplitViewPtr()->onMsg("ViewBottom", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -526,10 +566,9 @@ Py::Object AbstractSplitViewPy::viewFront(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewFront", 0); + getSplitViewPtr()->onMsg("ViewFront", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -548,10 +587,9 @@ Py::Object AbstractSplitViewPy::viewLeft(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewLeft", 0); + getSplitViewPtr()->onMsg("ViewLeft", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -570,10 +608,9 @@ Py::Object AbstractSplitViewPy::viewRear(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewRear", 0); + getSplitViewPtr()->onMsg("ViewRear", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -592,10 +629,9 @@ Py::Object AbstractSplitViewPy::viewRight(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewRight", 0); + getSplitViewPtr()->onMsg("ViewRight", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -614,10 +650,9 @@ Py::Object AbstractSplitViewPy::viewTop(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewTop", 0); + getSplitViewPtr()->onMsg("ViewTop", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -636,10 +671,9 @@ Py::Object AbstractSplitViewPy::viewIsometric(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewAxo", 0); + getSplitViewPtr()->onMsg("ViewAxo", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -659,10 +693,9 @@ Py::Object AbstractSplitViewPy::getViewer(const Py::Tuple& args) int viewIndex; if (!PyArg_ParseTuple(args.ptr(), "i", &viewIndex)) throw Py::Exception(); - testExistence(); try { - Gui::View3DInventorViewer* view = _view->getViewer(viewIndex); + Gui::View3DInventorViewer* view = getSplitViewPtr()->getViewer(viewIndex); if (!view) throw Py::IndexError("Index out of range"); return Py::asObject(view->getPyObject()); @@ -673,6 +706,10 @@ Py::Object AbstractSplitViewPy::getViewer(const Py::Tuple& args) catch (const std::exception& e) { throw Py::RuntimeError(e.what()); } + catch (const Py::Exception&) { + // re-throw + throw; + } catch(...) { throw Py::RuntimeError("Unknown C++ exception"); } @@ -680,29 +717,28 @@ Py::Object AbstractSplitViewPy::getViewer(const Py::Tuple& args) Py::Object AbstractSplitViewPy::sequence_item(ssize_t viewIndex) { - testExistence(); - if (viewIndex >= _view->getSize() || viewIndex < 0) + AbstractSplitView* view = getSplitViewPtr(); + if (viewIndex >= view->getSize() || viewIndex < 0) throw Py::IndexError("Index out of range"); - PyObject* viewer = _view->getViewer(viewIndex)->getPyObject(); + PyObject* viewer = view->getViewer(viewIndex)->getPyObject(); return Py::asObject(viewer); } int AbstractSplitViewPy::sequence_length() { - testExistence(); - return _view->getSize(); + AbstractSplitView* view = getSplitViewPtr(); + return view->getSize(); } Py::Object AbstractSplitViewPy::close(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); - _view->close(); - if (_view->parentWidget()) - _view->parentWidget()->deleteLater(); - _view = 0; + AbstractSplitView* view = getSplitViewPtr(); + view->close(); + if (view->parentWidget()) + view->parentWidget()->deleteLater(); return Py::None(); } @@ -791,3 +827,5 @@ SplitView3DInventor::SplitView3DInventor(int views, Gui::Document* pcDocument, Q SplitView3DInventor::~SplitView3DInventor() { } + +#include "moc_SplitView3DInventor.cpp" diff --git a/src/Gui/SplitView3DInventor.h b/src/Gui/SplitView3DInventor.h index bbbdd6d3fd..da0bfb56a6 100644 --- a/src/Gui/SplitView3DInventor.h +++ b/src/Gui/SplitView3DInventor.h @@ -25,6 +25,7 @@ #define GUI_SPLITVIEW3DINVENTOR_H #include "MDIView.h" +#include "MDIViewPy.h" #include #include @@ -39,6 +40,8 @@ class AbstractSplitViewPy; */ class GuiExport AbstractSplitView : public MDIView, public ParameterGrp::ObserverType { + Q_OBJECT + TYPESYSTEM_HEADER(); public: @@ -53,6 +56,7 @@ public: virtual void OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::MessageType Reason); virtual void onUpdate(void); virtual void deleteSelf(); + virtual void viewAll(); View3DInventorViewer *getViewer(unsigned int) const; void setOverrideCursor(const QCursor&); @@ -75,12 +79,16 @@ protected: class AbstractSplitViewPy : public Py::PythonExtension { public: - static void init_type(void); // announce properties and methods + using BaseType = Py::PythonExtension; + static void init_type(); // announce properties and methods AbstractSplitViewPy(AbstractSplitView *vi); ~AbstractSplitViewPy(); + AbstractSplitView* getSplitViewPtr(); Py::Object repr(); + Py::Object getattr(const char *); + Py::Object cast_to_base(const Py::Tuple&); Py::Object fitAll(const Py::Tuple&); Py::Object viewBottom(const Py::Tuple&); @@ -96,9 +104,7 @@ public: int sequence_length(); private: - AbstractSplitView* _view; - friend class AbstractSplitView; - void testExistence(); + Gui::MDIViewPy base; }; /** The SplitView3DInventor class allows to create a window with two or more Inventor views. From fad2fd9568b796e51704f22b967b6b1ce00f8a8a Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 21 Nov 2021 19:44:38 +0100 Subject: [PATCH 031/133] Gui: make View3DInventorPy acting as sub-class of MDIViewPy --- src/Gui/View3DInventor.cpp | 2 +- src/Gui/View3DPy.cpp | 236 +++++++++++++++++++------------------ src/Gui/View3DPy.h | 15 +-- 3 files changed, 132 insertions(+), 121 deletions(-) diff --git a/src/Gui/View3DInventor.cpp b/src/Gui/View3DInventor.cpp index 2b378dfb2f..c03281cfab 100644 --- a/src/Gui/View3DInventor.cpp +++ b/src/Gui/View3DInventor.cpp @@ -224,7 +224,7 @@ View3DInventor::~View3DInventor() } if (_viewerPy) { - static_cast(_viewerPy)->_view = 0; + Base::PyGILStateLocker lock; Py_DECREF(_viewerPy); } diff --git a/src/Gui/View3DPy.cpp b/src/Gui/View3DPy.cpp index 469a365588..23a0a68da6 100644 --- a/src/Gui/View3DPy.cpp +++ b/src/Gui/View3DPy.cpp @@ -52,7 +52,6 @@ #include "View3DViewerPy.h" #include "ActiveObjectList.h" #include "PythonWrapper.h" -#include "MDIViewPy.h" #include @@ -82,7 +81,6 @@ void View3DInventorPy::init_type() behaviors().supportGetattr(); behaviors().supportSetattr(); - add_varargs_method("message",&View3DInventorPy::message,"message()"); add_varargs_method("fitAll",&View3DInventorPy::fitAll,"fitAll()"); add_keyword_method("boxZoom",&View3DInventorPy::boxZoom,"boxZoom()"); @@ -213,7 +211,7 @@ void View3DInventorPy::init_type() } View3DInventorPy::View3DInventorPy(View3DInventor *vi) - : _view(vi) + : base(vi) { } @@ -224,11 +222,16 @@ View3DInventorPy::~View3DInventorPy() Py_DECREF(*it); } +View3DInventor* View3DInventorPy::getView3DIventorPtr() +{ + return qobject_cast(base.getMDIViewPtr()); +} + Py::Object View3DInventorPy::repr() { std::string s; std::ostringstream s_out; - if (!_view) + if (!getView3DIventorPtr()) throw Py::RuntimeError("Cannot print representation of deleted object"); s_out << "View3DInventor"; return Py::String(s_out.str()); @@ -247,28 +250,57 @@ PyObject *View3DInventorPy::method_varargs_ext_handler(PyObject *_self_and_name_ catch (const std::exception& e) { throw Py::RuntimeError(e.what()); } + catch (const Py::Exception&) { + throw; + } catch (...) { throw Py::RuntimeError("Unknown C++ exception"); } } +// Since with PyCXX it's not possible to make a sub-class of MDIViewPy +// a trick is to use MDIViewPy as class member and override getattr() to +// join the attributes of both classes. This way all methods of MDIViewPy +// appear for SheetViewPy, too. +Py::Object View3DInventorPy::getattribute(const char * attr) +{ + if (!getView3DIventorPtr()) + throw Py::RuntimeError("Cannot print representation of deleted object"); + std::string name( attr ); + if (name == "__dict__" || name == "__class__") { + Py::Dict dict_self(BaseType::getattr("__dict__")); + Py::Dict dict_base(base.getattr("__dict__")); + for (auto it : dict_base) { + dict_self.setItem(it.first, it.second); + } + return dict_self; + } + + try { + return BaseType::getattr(attr); + } + catch (Py::AttributeError& e) { + e.clear(); + return base.getattr(attr); + } +} + Py::Object View3DInventorPy::getattr(const char * attr) { - if (!_view) { - std::string s; + if (!getView3DIventorPtr()) { std::ostringstream s_out; s_out << "Cannot access attribute '" << attr << "' of deleted object"; throw Py::RuntimeError(s_out.str()); } else { // see if an active object has the same name - App::DocumentObject *docObj = _view->getActiveObject(attr); + App::DocumentObject *docObj = getView3DIventorPtr()->getActiveObject(attr); if (docObj) { return Py::Object(docObj->getPyObject(),true); } else { // else looking for a method with the name and call it - Py::Object obj = Py::PythonExtension::getattr(attr); + Py::Object obj = getattribute(attr); if (PyCFunction_Check(obj.ptr())) { PyCFunctionObject* op = reinterpret_cast(obj.ptr()); if (op->m_ml->ml_flags == METH_VARARGS) { @@ -284,39 +316,17 @@ Py::Object View3DInventorPy::getattr(const char * attr) int View3DInventorPy::setattr(const char * attr, const Py::Object & value) { - if (!_view) { + if (!getView3DIventorPtr()) { std::string s; std::ostringstream s_out; s_out << "Cannot access attribute '" << attr << "' of deleted object"; throw Py::RuntimeError(s_out.str()); } else { - return Py::PythonExtension::setattr(attr, value); + return BaseType::setattr(attr, value); } } -Py::Object View3DInventorPy::message(const Py::Tuple& args) -{ - const char **ppReturn = 0; - char *psMsgStr; - if (!PyArg_ParseTuple(args.ptr(), "s;Message string needed (string)",&psMsgStr)) // convert args: Python->C - throw Py::Exception(); - - try { - _view->onMsg(psMsgStr,ppReturn); - } - catch (const Base::Exception& e) { - throw Py::RuntimeError(e.what()); - } - catch (const std::exception& e) { - throw Py::RuntimeError(e.what()); - } - catch (...) { - throw Py::RuntimeError("Unknown C++ exception"); - } - return Py::None(); -} - Py::Object View3DInventorPy::fitAll(const Py::Tuple& args) { double factor = 1.0; @@ -324,7 +334,7 @@ Py::Object View3DInventorPy::fitAll(const Py::Tuple& args) throw Py::Exception(); try { - _view->getViewer()->viewAll((float)factor); + getView3DIventorPtr()->getViewer()->viewAll((float)factor); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -347,7 +357,7 @@ Py::Object View3DInventorPy::boxZoom(const Py::Tuple& args, const Py::Dict& kwds throw Py::Exception(); SbBox2s box(xmin, ymin, xmax, ymax); - _view->getViewer()->boxZoom(box); + getView3DIventorPtr()->getViewer()->boxZoom(box); return Py::None(); } @@ -470,7 +480,7 @@ Py::Object View3DInventorPy::viewBottom(const Py::Tuple& args) throw Py::Exception(); try { - _view->getViewer()->setCameraOrientation(Camera::rotation(Camera::Bottom)); + getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Bottom)); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -491,7 +501,7 @@ Py::Object View3DInventorPy::viewFront(const Py::Tuple& args) throw Py::Exception(); try { - _view->getViewer()->setCameraOrientation(Camera::rotation(Camera::Front)); + getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Front)); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -512,7 +522,7 @@ Py::Object View3DInventorPy::viewLeft(const Py::Tuple& args) throw Py::Exception(); try { - _view->getViewer()->setCameraOrientation(Camera::rotation(Camera::Left)); + getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Left)); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -533,7 +543,7 @@ Py::Object View3DInventorPy::viewRear(const Py::Tuple& args) throw Py::Exception(); try { - _view->getViewer()->setCameraOrientation(Camera::rotation(Camera::Rear)); + getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Rear)); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -554,7 +564,7 @@ Py::Object View3DInventorPy::viewRight(const Py::Tuple& args) throw Py::Exception(); try { - _view->getViewer()->setCameraOrientation(Camera::rotation(Camera::Right)); + getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Right)); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -575,7 +585,7 @@ Py::Object View3DInventorPy::viewTop(const Py::Tuple& args) throw Py::Exception(); try { - _view->getViewer()->setCameraOrientation(Camera::rotation(Camera::Top)); + getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Top)); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -596,7 +606,7 @@ Py::Object View3DInventorPy::viewIsometric(const Py::Tuple& args) throw Py::Exception(); try { - _view->getViewer()->setCameraOrientation(Camera::rotation(Camera::Isometric)); + getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Isometric)); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -617,7 +627,7 @@ Py::Object View3DInventorPy::viewDimetric(const Py::Tuple& args) throw Py::Exception(); try { - _view->getViewer()->setCameraOrientation(Camera::rotation(Camera::Dimetric)); + getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Dimetric)); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -638,7 +648,7 @@ Py::Object View3DInventorPy::viewTrimetric(const Py::Tuple& args) throw Py::Exception(); try { - _view->getViewer()->setCameraOrientation(Camera::rotation(Camera::Trimetric)); + getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Trimetric)); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -707,7 +717,7 @@ Py::Object View3DInventorPy::viewDefaultOrientation(const Py::Tuple& args) rot.setValue(q0, q1, q2, q3); } - SoCamera* cam = _view->getViewer()->getCamera(); + SoCamera* cam = getView3DIventorPtr()->getViewer()->getCamera(); cam->orientation = rot; if (scale < 0.0){ @@ -750,7 +760,7 @@ Py::Object View3DInventorPy::viewRotateLeft(const Py::Tuple& args) throw Py::Exception(); try { - SoCamera* cam = _view->getViewer()->getSoRenderManager()->getCamera(); + SoCamera* cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera(); SbRotation rot = cam->orientation.getValue(); SbVec3f vdir(0, 0, -1); rot.multVec(vdir, vdir); @@ -776,7 +786,7 @@ Py::Object View3DInventorPy::viewRotateRight(const Py::Tuple& args) throw Py::Exception(); try { - SoCamera* cam = _view->getViewer()->getSoRenderManager()->getCamera(); + SoCamera* cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera(); SbRotation rot = cam->orientation.getValue(); SbVec3f vdir(0, 0, -1); rot.multVec(vdir, vdir); @@ -802,7 +812,7 @@ Py::Object View3DInventorPy::zoomIn(const Py::Tuple& args) throw Py::Exception(); try { - _view->getViewer()->navigationStyle()->zoomIn(); + getView3DIventorPtr()->getViewer()->navigationStyle()->zoomIn(); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -823,7 +833,7 @@ Py::Object View3DInventorPy::zoomOut(const Py::Tuple& args) throw Py::Exception(); try { - _view->getViewer()->navigationStyle()->zoomOut(); + getView3DIventorPtr()->getViewer()->navigationStyle()->zoomOut(); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -852,13 +862,13 @@ Py::Object View3DInventorPy::setCameraOrientation(const Py::Tuple& args) float q1 = (float)Py::Float(tuple[1]); float q2 = (float)Py::Float(tuple[2]); float q3 = (float)Py::Float(tuple[3]); - _view->getViewer()->setCameraOrientation(SbRotation(q0, q1, q2, q3), PyObject_IsTrue(m)); + getView3DIventorPtr()->getViewer()->setCameraOrientation(SbRotation(q0, q1, q2, q3), PyObject_IsTrue(m)); } else if (PyObject_TypeCheck(o, &Base::RotationPy::Type)) { Base::Rotation r = (Base::Rotation)Py::Rotation(o,false); double q0, q1, q2, q3; r.getValue(q0, q1, q2, q3); - _view->getViewer()->setCameraOrientation(SbRotation((float)q0, (float)q1, (float)q2, (float)q3), PyObject_IsTrue(m)); + getView3DIventorPtr()->getViewer()->setCameraOrientation(SbRotation((float)q0, (float)q1, (float)q2, (float)q3), PyObject_IsTrue(m)); } else { throw Py::ValueError("Neither tuple nor rotation object"); @@ -884,7 +894,7 @@ Py::Object View3DInventorPy::getCameraOrientation(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - SbRotation rot = _view->getViewer()->getCameraOrientation(); + SbRotation rot = getView3DIventorPtr()->getViewer()->getCameraOrientation(); float q0,q1,q2,q3; rot.getValue(q0,q1,q2,q3); return Py::Rotation(Base::Rotation(q0,q1,q2,q3)); @@ -904,12 +914,12 @@ Py::Object View3DInventorPy::viewPosition(const Py::Tuple& args) Base::Vector3d pos = plm->getPosition(); double q0,q1,q2,q3; rot.getValue(q0,q1,q2,q3); - _view->getViewer()->moveCameraTo( + getView3DIventorPtr()->getViewer()->moveCameraTo( SbRotation((float)q0, (float)q1, (float)q2, (float)q3), SbVec3f((float)pos.x, (float)pos.y, (float)pos.z), steps, ms); } - SoCamera* cam = _view->getViewer()->getSoRenderManager()->getCamera(); + SoCamera* cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera(); if (!cam) return Py::None(); SbRotation rot = cam->orientation.getValue(); @@ -928,7 +938,7 @@ Py::Object View3DInventorPy::startAnimating(const Py::Tuple& args) float velocity; if (!PyArg_ParseTuple(args.ptr(), "ffff", &x,&y,&z,&velocity)) throw Py::Exception(); - _view->getViewer()->startAnimating(SbVec3f(x,y,z),velocity); + getView3DIventorPtr()->getViewer()->startAnimating(SbVec3f(x,y,z),velocity); return Py::None(); } @@ -936,7 +946,7 @@ Py::Object View3DInventorPy::stopAnimating(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - _view->getViewer()->stopAnimating(); + getView3DIventorPtr()->getViewer()->stopAnimating(); return Py::None(); } @@ -945,7 +955,7 @@ Py::Object View3DInventorPy::setAnimationEnabled(const Py::Tuple& args) int ok; if (!PyArg_ParseTuple(args.ptr(), "i", &ok)) throw Py::Exception(); - _view->getViewer()->setAnimationEnabled(ok!=0); + getView3DIventorPtr()->getViewer()->setAnimationEnabled(ok!=0); return Py::None(); } @@ -953,7 +963,7 @@ Py::Object View3DInventorPy::isAnimationEnabled(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - SbBool ok = _view->getViewer()->isAnimationEnabled(); + SbBool ok = getView3DIventorPtr()->getViewer()->isAnimationEnabled(); return Py::Boolean(ok ? true : false); } @@ -962,7 +972,7 @@ Py::Object View3DInventorPy::setPopupMenuEnabled(const Py::Tuple& args) int ok; if (!PyArg_ParseTuple(args.ptr(), "i", &ok)) throw Py::Exception(); - _view->getViewer()->setPopupMenuEnabled(ok!=0); + getView3DIventorPtr()->getViewer()->setPopupMenuEnabled(ok!=0); return Py::None(); } @@ -970,7 +980,7 @@ Py::Object View3DInventorPy::isPopupMenuEnabled(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - SbBool ok = _view->getViewer()->isPopupMenuEnabled(); + SbBool ok = getView3DIventorPtr()->getViewer()->isPopupMenuEnabled(); return Py::Boolean(ok ? true : false); } @@ -998,10 +1008,10 @@ Py::Object View3DInventorPy::saveImage(const Py::Tuple& args) bg.setNamedColor(colname); QImage img; - _view->getViewer()->savePicture(w, h, s, bg, img); + getView3DIventorPtr()->getViewer()->savePicture(w, h, s, bg, img); SoFCOffscreenRenderer& renderer = SoFCOffscreenRenderer::instance(); - SoCamera* cam = _view->getViewer()->getSoRenderManager()->getCamera(); + SoCamera* cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera(); renderer.writeToImageFile(encodedName.c_str(), cComment, cam->getViewVolume().getMatrix(), img); return Py::None(); @@ -1042,11 +1052,11 @@ Py::Object View3DInventorPy::saveVectorGraphic(const Py::Tuple& args) QColor bg; QString colname = QString::fromLatin1(name); if (colname.compare(QLatin1String("Current"), Qt::CaseInsensitive) == 0) - bg = _view->getViewer()->backgroundColor(); + bg = getView3DIventorPtr()->getViewer()->backgroundColor(); else bg.setNamedColor(colname); - _view->getViewer()->saveGraphic(ps,bg,vo.get()); + getView3DIventorPtr()->getViewer()->saveGraphic(ps,bg,vo.get()); out->closeFile(); return Py::None(); } @@ -1057,7 +1067,7 @@ Py::Object View3DInventorPy::getCameraNode(const Py::Tuple& args) throw Py::Exception(); try { - SoNode* camera = _view->getViewer()->getSoRenderManager()->getCamera(); + SoNode* camera = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera(); PyObject* proxy = 0; std::string type; type = "So"; // seems that So prefix is missing in camera node @@ -1083,7 +1093,7 @@ Py::Object View3DInventorPy::getCamera(const Py::Tuple& args) try { SoWriteAction wa(&out); - SoCamera * cam = _view->getViewer()->getSoRenderManager()->getCamera(); + SoCamera * cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera(); if (cam) wa.apply(cam); else buffer[0] = '\0'; return Py::String(buffer); @@ -1104,7 +1114,7 @@ Py::Object View3DInventorPy::getViewDirection(const Py::Tuple& args) if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); try { - SbVec3f dvec = _view->getViewer()->getViewDirection(); + SbVec3f dvec = getView3DIventorPtr()->getViewer()->getViewDirection(); return Py::Vector(Base::Vector3f(dvec[0], dvec[1], dvec[2])); } catch (const Base::Exception& e) { @@ -1134,7 +1144,7 @@ Py::Object View3DInventorPy::setViewDirection(const Py::Tuple& args) dir.setValue((float)x, (float)y, (float)z); if (dir.length() < 0.001f) throw Py::ValueError("Null vector cannot be used to set direction"); - _view->getViewer()->setViewDirection(dir); + getView3DIventorPtr()->getViewer()->setViewDirection(dir); return Py::None(); } } @@ -1163,7 +1173,7 @@ Py::Object View3DInventorPy::setCamera(const Py::Tuple& args) throw Py::Exception(); try { - _view->setCamera(buffer); + getView3DIventorPtr()->setCamera(buffer); return Py::None(); } catch (const Base::Exception& e) { @@ -1185,7 +1195,7 @@ Py::Object View3DInventorPy::getCameraType(const Py::Tuple& args) if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - SoCamera* cam = _view->getViewer()->getSoRenderManager()->getCamera(); + SoCamera* cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera(); if (!cam) { throw Py::RuntimeError("No camera set!"); } @@ -1226,9 +1236,9 @@ Py::Object View3DInventorPy::setCameraType(const Py::Tuple& args) if (cameratype < 0 || cameratype > 1) throw Py::IndexError("Out of range"); if (cameratype==0) - _view->getViewer()->setCameraType(SoOrthographicCamera::getClassTypeId()); + getView3DIventorPtr()->getViewer()->setCameraType(SoOrthographicCamera::getClassTypeId()); else - _view->getViewer()->setCameraType(SoPerspectiveCamera::getClassTypeId()); + getView3DIventorPtr()->getViewer()->setCameraType(SoPerspectiveCamera::getClassTypeId()); return Py::None(); } @@ -1263,7 +1273,7 @@ Py::Object View3DInventorPy::dump(const Py::Tuple& args) throw Py::Exception(); try { - _view->dump(filename, PyObject_IsTrue(onlyVisible)); + getView3DIventorPtr()->dump(filename, PyObject_IsTrue(onlyVisible)); return Py::None(); } catch (const Base::Exception& e) { @@ -1324,7 +1334,7 @@ Py::Object View3DInventorPy::setStereoType(const Py::Tuple& args) if (stereomode < 0 || stereomode > 4) throw Py::IndexError("Out of range"); Quarter::SoQTQuarterAdaptor::StereoMode mode = Quarter::SoQTQuarterAdaptor::StereoMode(stereomode); - _view->getViewer()->setStereoMode(mode); + getView3DIventorPtr()->getViewer()->setStereoMode(mode); return Py::None(); } catch (const Base::Exception& e) { @@ -1344,7 +1354,7 @@ Py::Object View3DInventorPy::getStereoType(const Py::Tuple& args) throw Py::Exception(); try { - int mode = (int)(_view->getViewer()->stereoMode()); + int mode = (int)(getView3DIventorPtr()->getViewer()->stereoMode()); return Py::String(StereoTypeEnums[mode]); } catch (const Base::Exception& e) { @@ -1387,10 +1397,10 @@ Py::Object View3DInventorPy::getCursorPos(const Py::Tuple& args) if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); try { - QPoint pos = _view->mapFromGlobal(QCursor::pos()); + QPoint pos = getView3DIventorPtr()->mapFromGlobal(QCursor::pos()); Py::Tuple tuple(2); tuple.setItem(0, Py::Int(pos.x())); - tuple.setItem(1, Py::Int(_view->height()-pos.y()-1)); + tuple.setItem(1, Py::Int(getView3DIventorPtr()->height()-pos.y()-1)); return tuple; } catch (const Py::Exception&) { @@ -1401,7 +1411,7 @@ Py::Object View3DInventorPy::getCursorPos(const Py::Tuple& args) Py::Object View3DInventorPy::getObjectInfo(const Py::Tuple& args) { PyObject* object; - float r = _view->getViewer()->getPickRadius(); + float r = getView3DIventorPtr()->getViewer()->getPickRadius(); if (!PyArg_ParseTuple(args.ptr(), "O|f", &object, &r)) throw Py::Exception(); @@ -1419,10 +1429,10 @@ Py::Object View3DInventorPy::getObjectInfo(const Py::Tuple& args) // graph traversal we must not use a second SoHandleEventAction as // we will get Coin warnings because of multiple scene graph traversals // which is regarded as error-prone. - SoRayPickAction action(_view->getViewer()->getSoRenderManager()->getViewportRegion()); + SoRayPickAction action(getView3DIventorPtr()->getViewer()->getSoRenderManager()->getViewportRegion()); action.setPoint(SbVec2s((long)x,(long)y)); action.setRadius(r); - action.apply(_view->getViewer()->getSoRenderManager()->getSceneGraph()); + action.apply(getView3DIventorPtr()->getViewer()->getSoRenderManager()->getSceneGraph()); SoPickedPoint *Point = action.getPickedPoint(); Py::Object ret = Py::None(); @@ -1433,9 +1443,9 @@ Py::Object View3DInventorPy::getObjectInfo(const Py::Tuple& args) dict.setItem("y", Py::Float(pt[1])); dict.setItem("z", Py::Float(pt[2])); - Gui::Document* doc = _view->getViewer()->getDocument(); + Gui::Document* doc = getView3DIventorPtr()->getViewer()->getDocument(); ViewProvider *vp = doc ? doc->getViewProviderByPathFromHead(Point->getPath()) - : _view->getViewer()->getViewProviderByPath(Point->getPath()); + : getView3DIventorPtr()->getViewer()->getViewProviderByPath(Point->getPath()); if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) { if (!vp->isSelectable()) return ret; @@ -1509,7 +1519,7 @@ Py::Object View3DInventorPy::getObjectInfo(const Py::Tuple& args) Py::Object View3DInventorPy::getObjectsInfo(const Py::Tuple& args) { PyObject* object; - float r = _view->getViewer()->getPickRadius(); + float r = getView3DIventorPtr()->getViewer()->getPickRadius(); if (!PyArg_ParseTuple(args.ptr(), "O|f", &object, &r)) throw Py::Exception(); @@ -1527,14 +1537,14 @@ Py::Object View3DInventorPy::getObjectsInfo(const Py::Tuple& args) // graph traversal we must not use a second SoHandleEventAction as // we will get Coin warnings because of multiple scene graph traversals // which is regarded as error-prone. - SoRayPickAction action(_view->getViewer()->getSoRenderManager()->getViewportRegion()); + SoRayPickAction action(getView3DIventorPtr()->getViewer()->getSoRenderManager()->getViewportRegion()); action.setPickAll(true); action.setRadius(r); action.setPoint(SbVec2s((long)x,(long)y)); - action.apply(_view->getViewer()->getSoRenderManager()->getSceneGraph()); + action.apply(getView3DIventorPtr()->getViewer()->getSoRenderManager()->getSceneGraph()); const SoPickedPointList& pp = action.getPickedPointList(); - Gui::Document* doc = _view->getViewer()->getDocument(); + Gui::Document* doc = getView3DIventorPtr()->getViewer()->getDocument(); Py::Object ret = Py::None(); if (pp.getLength() > 0) { Py::List list; @@ -1547,7 +1557,7 @@ Py::Object View3DInventorPy::getObjectsInfo(const Py::Tuple& args) dict.setItem("z", Py::Float(pt[2])); ViewProvider *vp = doc ? doc->getViewProviderByPathFromHead(point->getPath()) - : _view->getViewer()->getViewProviderByPath(point->getPath()); + : getView3DIventorPtr()->getViewer()->getViewProviderByPath(point->getPath()); if(vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) { if(!vp->isSelectable()) continue; @@ -1625,7 +1635,7 @@ Py::Object View3DInventorPy::getSize(const Py::Tuple& args) if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); try { - SbVec2s size = _view->getViewer()->getSoRenderManager()->getSize(); + SbVec2s size = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getSize(); Py::Tuple tuple(2); tuple.setItem(0, Py::Int(size[0])); tuple.setItem(1, Py::Int(size[1])); @@ -1646,7 +1656,7 @@ Py::Object View3DInventorPy::getPoint(const Py::Tuple& args) y = (int)Py::Int(t[1]); } try { - SbVec3f pt = _view->getViewer()->getPointOnScreen(SbVec2s(x,y)); + SbVec3f pt = getView3DIventorPtr()->getViewer()->getPointOnScreen(SbVec2s(x,y)); return Py::Vector(Base::Vector3f(pt[0], pt[1], pt[2])); } catch (const Base::Exception& e) { @@ -1675,11 +1685,11 @@ Py::Object View3DInventorPy::getPointOnScreen(const Py::Tuple& args) } try { - const SbViewportRegion& vp = _view->getViewer()->getSoRenderManager()->getViewportRegion(); + const SbViewportRegion& vp = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getViewportRegion(); float fRatio = vp.getViewportAspectRatio(); const SbVec2s& sp = vp.getViewportSizePixels(); //float dX, dY; vp.getViewportSize().getValue(dX, dY); - SbViewVolume vv = _view->getViewer()->getSoRenderManager()->getCamera()->getViewVolume(fRatio); + SbViewVolume vv = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera()->getViewVolume(fRatio); SbVec3f pt(vx,vy,vz); vv.projectToScreen(pt, pt); @@ -1720,7 +1730,7 @@ Py::Object View3DInventorPy::listNavigationTypes(const Py::Tuple&) Py::Object View3DInventorPy::getNavigationType(const Py::Tuple&) { - std::string name = _view->getViewer()->navigationStyle()->getTypeId().getName(); + std::string name = getView3DIventorPtr()->getViewer()->navigationStyle()->getTypeId().getName(); return Py::String(name); } @@ -1730,7 +1740,7 @@ Py::Object View3DInventorPy::setNavigationType(const Py::Tuple& args) if (!PyArg_ParseTuple(args.ptr(), "s", &style)) throw Py::Exception(); Base::Type type = Base::Type::fromName(style); - _view->getViewer()->setNavigationType(type); + getView3DIventorPtr()->getViewer()->setNavigationType(type); return Py::None(); } @@ -2111,7 +2121,7 @@ Py::Object View3DInventorPy::addEventCallback(const Py::Tuple& args) throw Py::TypeError(s_out.str()); } - _view->getViewer()->addEventCallback(eventId, View3DInventorPy::eventCallback, method); + getView3DIventorPtr()->getViewer()->addEventCallback(eventId, View3DInventorPy::eventCallback, method); callbacks.push_back(method); Py_INCREF(method); return Py::Callable(method, false); @@ -2139,7 +2149,7 @@ Py::Object View3DInventorPy::removeEventCallback(const Py::Tuple& args) throw Py::TypeError(s_out.str()); } - _view->getViewer()->removeEventCallback(eventId, View3DInventorPy::eventCallback, method); + getView3DIventorPtr()->getViewer()->removeEventCallback(eventId, View3DInventorPy::eventCallback, method); callbacks.remove(method); Py_DECREF(method); return Py::None(); @@ -2164,7 +2174,7 @@ Py::Object View3DInventorPy::setAnnotation(const Py::Tuple& args) throw Py::RuntimeError(e.what()); } - _view->getGuiDocument()->setAnnotationViewProvider(psAnnoName, view); + getView3DIventorPtr()->getGuiDocument()->setAnnotationViewProvider(psAnnoName, view); return Py::None(); } @@ -2174,9 +2184,9 @@ Py::Object View3DInventorPy::removeAnnotation(const Py::Tuple& args) if (!PyArg_ParseTuple(args.ptr(), "s", &psAnnoName)) throw Py::Exception(); ViewProvider* view = 0; - view = _view->getGuiDocument()->getAnnotationViewProvider(psAnnoName); + view = getView3DIventorPtr()->getGuiDocument()->getAnnotationViewProvider(psAnnoName); if (view) { - _view->getGuiDocument()->removeAnnotationViewProvider(psAnnoName); + getView3DIventorPtr()->getGuiDocument()->removeAnnotationViewProvider(psAnnoName); return Py::None(); } else { @@ -2193,7 +2203,7 @@ Py::Object View3DInventorPy::getSceneGraph(const Py::Tuple& args) throw Py::Exception(); try { - SoNode* scene = _view->getViewer()->getSceneGraph(); + SoNode* scene = getView3DIventorPtr()->getViewer()->getSceneGraph(); PyObject* proxy = 0; proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", "SoSeparator *", (void*)scene, 1); scene->ref(); @@ -2209,7 +2219,7 @@ Py::Object View3DInventorPy::getViewer(const Py::Tuple& args) if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - View3DInventorViewer* viewer = _view->getViewer(); + View3DInventorViewer* viewer = getView3DIventorPtr()->getViewer(); return Py::Object(viewer->getPyObject(), true); } @@ -2313,7 +2323,7 @@ Py::Object View3DInventorPy::addEventCallbackPivy(const Py::Tuple& args) SoEventCallbackCB* callback = (ex == 1 ? View3DInventorPy::eventCallbackPivyEx : View3DInventorPy::eventCallbackPivy); - _view->getViewer()->addEventCallback(*eventId, callback, method); + getView3DIventorPtr()->getViewer()->addEventCallback(*eventId, callback, method); callbacks.push_back(method); Py_INCREF(method); return Py::Callable(method, false); @@ -2355,7 +2365,7 @@ Py::Object View3DInventorPy::removeEventCallbackPivy(const Py::Tuple& args) SoEventCallbackCB* callback = (ex == 1 ? View3DInventorPy::eventCallbackPivyEx : View3DInventorPy::eventCallbackPivy); - _view->getViewer()->removeEventCallback(*eventId, callback, method); + getView3DIventorPtr()->getViewer()->removeEventCallback(*eventId, callback, method); callbacks.remove(method); Py_DECREF(method); return Py::Callable(method, false); @@ -2370,7 +2380,7 @@ Py::Object View3DInventorPy::setAxisCross(const Py::Tuple& args) int ok; if (!PyArg_ParseTuple(args.ptr(), "i", &ok)) throw Py::Exception(); - _view->getViewer()->setAxisCross(ok!=0); + getView3DIventorPtr()->getViewer()->setAxisCross(ok!=0); return Py::None(); } @@ -2378,7 +2388,7 @@ Py::Object View3DInventorPy::hasAxisCross(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - SbBool ok = _view->getViewer()->hasAxisCross(); + SbBool ok = getView3DIventorPtr()->getViewer()->hasAxisCross(); return Py::Boolean(ok ? true : false); } @@ -2522,13 +2532,13 @@ Py::Object View3DInventorPy::setActiveObject(const Py::Tuple& args) throw Py::Exception(); if (docObject == Py_None) { - _view->setActiveObject(0, name); + getView3DIventorPtr()->setActiveObject(0, name); } else { if (!PyObject_TypeCheck(docObject, &App::DocumentObjectPy::Type)) throw Py::TypeError("Expect the second argument to be a document object or None"); App::DocumentObject* obj = static_cast(docObject)->getDocumentObjectPtr(); - _view->setActiveObject(obj, name, subname); + getView3DIventorPtr()->setActiveObject(obj, name, subname); } return Py::None(); @@ -2543,7 +2553,7 @@ Py::Object View3DInventorPy::getActiveObject(const Py::Tuple& args) App::DocumentObject *parent = 0; std::string subname; - App::DocumentObject* obj = _view->getActiveObject(name,&parent,&subname); + App::DocumentObject* obj = getView3DIventorPtr()->getActiveObject(name,&parent,&subname); if (!obj) return Py::None(); @@ -2562,7 +2572,7 @@ Py::Object View3DInventorPy::getViewProvidersOfType(const Py::Tuple& args) if (!PyArg_ParseTuple(args.ptr(), "s", &name)) throw Py::Exception(); - std::vector vps = _view->getViewer()->getViewProvidersOfType(Base::Type::fromName(name)); + std::vector vps = getView3DIventorPtr()->getViewer()->getViewProvidersOfType(Base::Type::fromName(name)); Py::List list; for (std::vector::iterator it = vps.begin(); it != vps.end(); ++it) { list.append(Py::asObject((*it)->getPyObject())); @@ -2575,7 +2585,7 @@ Py::Object View3DInventorPy::redraw(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - _view->getViewer()->redraw(); + getView3DIventorPtr()->getViewer()->redraw(); return Py::None(); } @@ -2586,7 +2596,7 @@ Py::Object View3DInventorPy::setName(const Py::Tuple& args) throw Py::Exception(); try { - _view->setWindowTitle(QString::fromUtf8(buffer)); + getView3DIventorPtr()->setWindowTitle(QString::fromUtf8(buffer)); return Py::None(); } catch (const Base::Exception& e) { @@ -2614,7 +2624,7 @@ Py::Object View3DInventorPy::toggleClippingPlane(const Py::Tuple& args, const Py Base::Placement pla; if(pyPla!=Py_None) pla = *static_cast(pyPla)->getPlacementPtr(); - _view->getViewer()->toggleClippingPlane(toggle,PyObject_IsTrue(beforeEditing), + getView3DIventorPtr()->getViewer()->toggleClippingPlane(toggle,PyObject_IsTrue(beforeEditing), PyObject_IsTrue(noManip),pla); return Py::None(); } @@ -2623,7 +2633,7 @@ Py::Object View3DInventorPy::hasClippingPlane(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - return Py::Boolean(_view->getViewer()->hasClippingPlane()); + return Py::Boolean(getView3DIventorPtr()->getViewer()->hasClippingPlane()); } Py::Object View3DInventorPy::graphicsView(const Py::Tuple& args) @@ -2633,10 +2643,10 @@ Py::Object View3DInventorPy::graphicsView(const Py::Tuple& args) PythonWrapper wrap; wrap.loadWidgetsModule(); - return wrap.fromQWidget(_view->getViewer(), "QGraphicsView"); + return wrap.fromQWidget(getView3DIventorPtr()->getViewer(), "QGraphicsView"); } Py::Object View3DInventorPy::cast_to_base(const Py::Tuple&) { - return Gui::MDIViewPy::create(_view); + return Gui::MDIViewPy::create(getView3DIventorPtr()); } diff --git a/src/Gui/View3DPy.h b/src/Gui/View3DPy.h index 9bc057bfb4..9a7bf17148 100644 --- a/src/Gui/View3DPy.h +++ b/src/Gui/View3DPy.h @@ -26,6 +26,8 @@ #include #include +#include +#include class SoEventCallback; class SoDragger; @@ -56,16 +58,18 @@ public: class View3DInventorPy : public Py::PythonExtension { public: - static void init_type(void); // announce properties and methods + using BaseType = Py::PythonExtension; + static void init_type(); // announce properties and methods View3DInventorPy(View3DInventor *vi); ~View3DInventorPy(); + View3DInventor* getView3DIventorPtr(); Py::Object repr(); Py::Object getattr(const char *); int setattr(const char *, const Py::Object &); + Py::Object cast_to_base(const Py::Tuple&); - Py::Object message(const Py::Tuple&); Py::Object fitAll(const Py::Tuple&); Py::Object boxZoom(const Py::Tuple&, const Py::Dict&); Py::Object viewBottom(const Py::Tuple&); @@ -135,9 +139,6 @@ public: Py::Object toggleClippingPlane(const Py::Tuple& args, const Py::Dict &); Py::Object hasClippingPlane(const Py::Tuple& args); Py::Object graphicsView(const Py::Tuple& args); - Py::Object cast_to_base(const Py::Tuple&); - - View3DInventor* getView3DIventorPtr() {return _view;} private: static void eventCallback(void * ud, SoEventCallback * n); @@ -149,11 +150,11 @@ private: typedef PyObject* (*method_varargs_handler)(PyObject *_self, PyObject *_args); static method_varargs_handler pycxx_handler; static PyObject *method_varargs_ext_handler(PyObject *_self, PyObject *_args); + Py::Object getattribute(const char *); private: + Gui::MDIViewPy base; std::list callbacks; - View3DInventor* _view; - friend class View3DInventor; }; } // namespace Gui From 9bfab4262f2cd67174017725e0a7d8717057aae9 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 21 Nov 2021 19:57:21 +0100 Subject: [PATCH 032/133] Mod: change error text of Python wrapper when trying to access deleted view --- src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp | 7 +++++-- src/Mod/TechDraw/Gui/MDIViewPage.cpp | 7 +++++-- src/Mod/Web/Gui/BrowserView.cpp | 7 +++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp index a37ad89b37..3595268f2d 100644 --- a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp +++ b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp @@ -504,8 +504,11 @@ Py::Object SheetViewPy::repr() // appear for SheetViewPy, too. Py::Object SheetViewPy::getattr(const char * attr) { - if (!getSheetViewPtr()) - throw Py::RuntimeError("Cannot print representation of deleted object"); + if (!getSheetViewPtr()) { + std::ostringstream s_out; + s_out << "Cannot access attribute '" << attr << "' of deleted object"; + throw Py::RuntimeError(s_out.str()); + } std::string name( attr ); if (name == "__dict__" || name == "__class__") { Py::Dict dict_self(BaseType::getattr("__dict__")); diff --git a/src/Mod/TechDraw/Gui/MDIViewPage.cpp b/src/Mod/TechDraw/Gui/MDIViewPage.cpp index 5ff113d1ea..8b305bf0bd 100644 --- a/src/Mod/TechDraw/Gui/MDIViewPage.cpp +++ b/src/Mod/TechDraw/Gui/MDIViewPage.cpp @@ -1415,8 +1415,11 @@ Py::Object MDIViewPagePy::repr() // appear for SheetViewPy, too. Py::Object MDIViewPagePy::getattr(const char * attr) { - if (!getMDIViewPagePtr()) - throw Py::RuntimeError("Cannot print representation of deleted object"); + if (!getMDIViewPagePtr()) { + std::ostringstream s_out; + s_out << "Cannot access attribute '" << attr << "' of deleted object"; + throw Py::RuntimeError(s_out.str()); + } std::string name( attr ); if (name == "__dict__" || name == "__class__") { Py::Dict dict_self(BaseType::getattr("__dict__")); diff --git a/src/Mod/Web/Gui/BrowserView.cpp b/src/Mod/Web/Gui/BrowserView.cpp index 3c202a30bc..2c60b5f760 100644 --- a/src/Mod/Web/Gui/BrowserView.cpp +++ b/src/Mod/Web/Gui/BrowserView.cpp @@ -240,8 +240,11 @@ Py::Object BrowserViewPy::repr() // appear for SheetViewPy, too. Py::Object BrowserViewPy::getattr(const char * attr) { - if (!getBrowserViewPtr()) - throw Py::RuntimeError("Cannot print representation of deleted object"); + if (!getBrowserViewPtr()) { + std::ostringstream s_out; + s_out << "Cannot access attribute '" << attr << "' of deleted object"; + throw Py::RuntimeError(s_out.str()); + } std::string name( attr ); if (name == "__dict__" || name == "__class__") { Py::Dict dict_self(BaseType::getattr("__dict__")); From 66038006d79d51b37b5d3d2b95048a27332fe819 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Fri, 4 Oct 2019 11:53:34 +0800 Subject: [PATCH 033/133] App: do not auto rename new dynamic property Instead, throw exception in case of duplicate name. Use boolean parameter 'Preferences/Document/AutoNameDynamicProperty' to get back the old behavior. --- src/App/DynamicProperty.cpp | 42 ++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/App/DynamicProperty.cpp b/src/App/DynamicProperty.cpp index 5851814b34..16b88739f9 100644 --- a/src/App/DynamicProperty.cpp +++ b/src/App/DynamicProperty.cpp @@ -37,7 +37,7 @@ #include #include -FC_LOG_LEVEL_INIT("DynamicProperty",true,true) +FC_LOG_LEVEL_INIT("Property",true,true) using namespace App; @@ -149,23 +149,45 @@ const char* DynamicProperty::getPropertyDocumentation(const char *name) const Property* DynamicProperty::addDynamicProperty(PropertyContainer &pc, const char* type, const char* name, const char* group, const char* doc, short attr, bool ro, bool hidden) { + if(!type) + type = ""; + + std::string _name; + + static ParameterGrp::handle hGrp = GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Document"); + if(hGrp->GetBool("AutoNameDynamicProperty",false)) { + if(!name || !name[0]) + name = type; + _name = getUniquePropertyName(pc,name); + if(_name != name) { + FC_WARN(pc.getFullName() << " rename dynamic property from '" + << name << "' to '" << _name << "'"); + } + name = _name.c_str(); + } else if(!name) + name = ""; // setting a bad name to trigger exception + + auto prop = pc.getPropertyByName(name); + if(prop && prop->getContainer()==&pc) + FC_THROWM(Base::NameError, "Property " << pc.getFullName() << '.' << name << " already exists"); + + if(Base::Tools::getIdentifier(name) != name) + FC_THROWM(Base::NameError, "Invalid property name '" << name << "'"); + Base::BaseClass* base = static_cast(Base::Type::createInstanceByName(type,true)); - if (!base) - return 0; + if (!base) + FC_THROWM(Base::RuntimeError, "Failed to create property " + << pc.getFullName() << '.' << name << " of type " << type); if (!base->getTypeId().isDerivedFrom(Property::getClassTypeId())) { delete base; - std::stringstream str; - str << "'" << type << "' is not a property type"; - throw Base::ValueError(str.str()); + FC_THROWM(Base::ValueError, "Invalid type " << type << " for property " << pc.getFullName() << '.' << name); } // get unique name Property* pcProperty = static_cast(base); - if (!name || !name[0]) - name = type; - auto res = props.get<0>().emplace(pcProperty, - getUniquePropertyName(pc,name), nullptr, group, doc, attr, ro, hidden); + auto res = props.get<0>().emplace(pcProperty,name, nullptr, group, doc, attr, ro, hidden); pcProperty->setContainer(&pc); pcProperty->myName = res.first->name.c_str(); From 789d32f87bf75ade033bd7292f26722642531fb7 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Wed, 20 Nov 2019 08:54:15 +0800 Subject: [PATCH 034/133] Test: fix test case Adding dynamic property with an invalid name or existing name is now an error, because there is no easy way for Python code to find out the name of a property if it is auto renamed. --- src/Mod/Path/PathTests/TestPathStock.py | 1 - src/Mod/Test/Document.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mod/Path/PathTests/TestPathStock.py b/src/Mod/Path/PathTests/TestPathStock.py index 8f9d22e412..af2471d611 100644 --- a/src/Mod/Path/PathTests/TestPathStock.py +++ b/src/Mod/Path/PathTests/TestPathStock.py @@ -45,7 +45,6 @@ class TestPathStock(PathTestBase): model = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", "Model") model.addObject(self.base) self.job.Model = model - self.job.addProperty('App::PropertyLink', 'Proxy') self.job.Proxy = FakeJobProxy() def tearDown(self): diff --git a/src/Mod/Test/Document.py b/src/Mod/Test/Document.py index fd5eb15af4..663b1a662e 100644 --- a/src/Mod/Test/Document.py +++ b/src/Mod/Test/Document.py @@ -1325,7 +1325,7 @@ class DocumentPropertyCases(unittest.TestCase): # testing the up and downstream stuff props=self.Obj.supportedProperties() for i in props: - self.Obj.addProperty(i,i) + self.Obj.addProperty(i,i.replace(':','_')) tempPath = tempfile.gettempdir() tempFile = tempPath + os.sep + "PropertyTests.FCStd" self.Doc.saveAs(tempFile) From e3cbc9fcfc4ac8a4620c465e77c12188cf933e07 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Wed, 5 Feb 2020 20:01:32 +0800 Subject: [PATCH 035/133] App: change PropertyContainer::Restore() Changes the way PropertyContainer handles existing property while restoring. Previously it will first ask DynamicProperty to restore if possible, then fallback to static property if else. This patch looks up existing property first, and only fallback to DynamicProperty if not found. This handles situation when an object changes an originally dynamic property into a static one. With the original code, it will add an auto renamed dynamic property that no one knows its existence. --- src/App/PropertyContainer.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/App/PropertyContainer.cpp b/src/App/PropertyContainer.cpp index 5fda5ce279..a7438cea2f 100644 --- a/src/App/PropertyContainer.cpp +++ b/src/App/PropertyContainer.cpp @@ -332,21 +332,21 @@ void PropertyContainer::Restore(Base::XMLReader &reader) reader.readElement("Property"); std::string PropName = reader.getAttribute("name"); std::string TypeName = reader.getAttribute("type"); - auto prop = dynamicProps.restore(*this,PropName.c_str(),TypeName.c_str(),reader); - if(!prop) - prop = getPropertyByName(PropName.c_str()); - - decltype(Property::StatusBits) status; - if(reader.hasAttribute("status")) { - status = decltype(status)(reader.getAttributeAsUnsigned("status")); - if(prop) - prop->setStatusValue(status.to_ulong()); - } // NOTE: We must also check the type of the current property because a // subclass of PropertyContainer might change the type of a property but // not its name. In this case we would force to read-in a wrong property // type and the behaviour would be undefined. try { + auto prop = getPropertyByName(PropName.c_str()); + if(!prop) + prop = dynamicProps.restore(*this,PropName.c_str(),TypeName.c_str(),reader); + + decltype(Property::StatusBits) status; + if(reader.hasAttribute("status")) { + status = decltype(status)(reader.getAttributeAsUnsigned("status")); + if(prop) + prop->setStatusValue(status.to_ulong()); + } // name and type match if (prop && strcmp(prop->getTypeId().getName(), TypeName.c_str()) == 0) { if (!prop->testStatus(Property::Transient) From 7349eb519809e106d9e68b5c2ad473d0a0ee93d8 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Fri, 19 Nov 2021 16:24:55 +0100 Subject: [PATCH 036/133] [Sheet] Prevent duplicate call to 'nonNullCellAt' --- src/Mod/Spreadsheet/App/PropertySheet.cpp | 36 +++++++++++++---------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/Mod/Spreadsheet/App/PropertySheet.cpp b/src/Mod/Spreadsheet/App/PropertySheet.cpp index 571453c1a1..8ad988995b 100644 --- a/src/Mod/Spreadsheet/App/PropertySheet.cpp +++ b/src/Mod/Spreadsheet/App/PropertySheet.cpp @@ -477,39 +477,43 @@ Cell * PropertySheet::nonNullCellAt(CellAddress address) void PropertySheet::setContent(CellAddress address, const char *value) { Cell * cell = nonNullCellAt(address); - assert(cell != 0); - cell->setContent(value); } void PropertySheet::setAlignment(CellAddress address, int _alignment) { - nonNullCellAt(address)->setAlignment(_alignment); + Cell * cell = nonNullCellAt(address); + assert(cell != 0); + cell->setAlignment(_alignment); } void PropertySheet::setStyle(CellAddress address, const std::set &_style) { - assert(nonNullCellAt(address) != 0); - nonNullCellAt(address)->setStyle(_style); + Cell * cell = nonNullCellAt(address); + assert(cell != 0); + cell->setStyle(_style); } void PropertySheet::setForeground(CellAddress address, const App::Color &color) { - assert(nonNullCellAt(address) != 0); - nonNullCellAt(address)->setForeground(color); + Cell * cell = nonNullCellAt(address); + assert(cell != 0); + cell->setForeground(color); } void PropertySheet::setBackground(CellAddress address, const App::Color &color) { - assert(nonNullCellAt(address) != 0); - nonNullCellAt(address)->setBackground(color); + Cell * cell = nonNullCellAt(address); + assert(cell != 0); + cell->setBackground(color); } void PropertySheet::setDisplayUnit(CellAddress address, const std::string &unit) { - assert(nonNullCellAt(address) != 0); - nonNullCellAt(address)->setDisplayUnit(unit); + Cell * cell = nonNullCellAt(address); + assert(cell != 0); + cell->setDisplayUnit(unit); } @@ -561,14 +565,16 @@ void PropertySheet::setAlias(CellAddress address, const std::string &alias) void PropertySheet::setComputedUnit(CellAddress address, const Base::Unit &unit) { - assert(nonNullCellAt(address) != 0); - nonNullCellAt(address)->setComputedUnit(unit); + Cell * cell = nonNullCellAt(address); + assert(cell != 0); + cell->setComputedUnit(unit); } void PropertySheet::setSpans(CellAddress address, int rows, int columns) { - assert(nonNullCellAt(address) != 0); - nonNullCellAt(address)->setSpans(rows, columns); + Cell * cell = nonNullCellAt(address); + assert(cell != 0); + cell->setSpans(rows, columns); } void PropertySheet::clearAlias(CellAddress address) From dc8f20a9e4c67e778a21119a56fb0f0fd28dac68 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Fri, 19 Nov 2021 16:25:36 +0100 Subject: [PATCH 037/133] [Sheet] Assert non-null pointer before using it --- src/Mod/Spreadsheet/App/PropertySheet.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mod/Spreadsheet/App/PropertySheet.cpp b/src/Mod/Spreadsheet/App/PropertySheet.cpp index 8ad988995b..faf93456f9 100644 --- a/src/Mod/Spreadsheet/App/PropertySheet.cpp +++ b/src/Mod/Spreadsheet/App/PropertySheet.cpp @@ -524,12 +524,11 @@ void PropertySheet::setAlias(CellAddress address, const std::string &alias) const Cell * aliasedCell = getValueFromAlias(alias); Cell * cell = nonNullCellAt(address); + assert(cell != 0); if (aliasedCell != 0 && cell != aliasedCell) throw Base::ValueError("Alias already defined."); - assert(cell != 0); - /* Mark cells depending on this cell dirty; they need to be resolved when an alias changes or disappears */ std::string fullName = owner->getFullName() + "." + address.toString(); From d5e750d26212a6071ad0d4b680097b528c333eef Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Fri, 19 Nov 2021 16:44:08 +0100 Subject: [PATCH 038/133] [Sheet][Bugfix] Reject alignment change for merged cell except top-left one --- src/Mod/Spreadsheet/App/PropertySheet.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mod/Spreadsheet/App/PropertySheet.cpp b/src/Mod/Spreadsheet/App/PropertySheet.cpp index faf93456f9..7f73663540 100644 --- a/src/Mod/Spreadsheet/App/PropertySheet.cpp +++ b/src/Mod/Spreadsheet/App/PropertySheet.cpp @@ -485,6 +485,7 @@ void PropertySheet::setAlignment(CellAddress address, int _alignment) { Cell * cell = nonNullCellAt(address); assert(cell != 0); + if (cell->address != address) return; //Reject alignment change for merged cell except top-left one cell->setAlignment(_alignment); } From 4483c7afd1f07a0056ff796ee76266a1e18d89ca Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Thu, 11 Nov 2021 21:22:58 -0500 Subject: [PATCH 039/133] [PD] Refactor `Loft::execute()` and support points for sections This is a combination of 4 commits. Original commit messages follow. [PD] Initial support for point sections in loft This commit allows the last section in a loft to be a single vertex of a solid. Currently single vertices of sketches or datum points are NOT supported. [PD] Allow loft "profiles" to be points Most reliably done in dialog-based workflow. [PD] Allow loft last section to be sketch point [PD] Refactor `Loft::execute` Makes it easier to support adding a single-vertex sketch in profile or sections field when selecting the sketch in tree (i.e. without selecting subelements). [PD] Refactoring after PR #5176 is merged --- src/Mod/PartDesign/App/FeatureLoft.cpp | 164 +++++++++++++++++-------- 1 file changed, 112 insertions(+), 52 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureLoft.cpp b/src/Mod/PartDesign/App/FeatureLoft.cpp index 811fd972eb..11622296ea 100644 --- a/src/Mod/PartDesign/App/FeatureLoft.cpp +++ b/src/Mod/PartDesign/App/FeatureLoft.cpp @@ -74,17 +74,48 @@ short Loft::mustExecute() const App::DocumentObjectExecReturn *Loft::execute(void) { + auto getSectionShape = + [](App::DocumentObject* feature, const std::vector &subs) -> TopoDS_Shape { + if (!feature || + !feature->isDerivedFrom(Part::Feature::getClassTypeId())) + throw Base::TypeError("Loft: Invalid profile/section"); + + auto subName = subs.empty() ? "" : subs.front(); + + // only take the entire shape when we have a sketch selected, but + // not a point of the sketch + if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) && + !(subName.size() > 6 && subName.substr(0,6) == "Vertex")) + return static_cast(feature)->Shape.getValue(); + else { + if(subName.empty()) + throw Base::ValueError("No valid subelement linked in Part::Feature"); + return static_cast(feature)->Shape.getShape().getSubShape(subName.c_str()); + } + }; + + auto addWiresToWireSections = + [](TopoDS_Shape& section, + std::vector>& wiresections) -> size_t { + TopExp_Explorer ex; + size_t i=0; + bool initialWireSectionsEmpty = wiresections.empty(); + for (ex.Init(section, TopAbs_WIRE); ex.More(); ex.Next(), ++i) { + // if profile was just a point then this is where we can first set our list + if (i>=wiresections.size()) { + if (initialWireSectionsEmpty) + wiresections.emplace_back(1, ex.Current()); + else + throw Base::ValueError("Loft: Sections need to have the same amount of inner wires (except profile and last section, which can be points)"); + } + else + wiresections[i].push_back(TopoDS::Wire(ex.Current())); + } + return i; + }; std::vector wires; - try { - wires = getProfileWires(); - } catch (const Base::Exception& e) { - return new App::DocumentObjectExecReturn(e.what()); - } - - TopoDS_Shape sketchshape = getVerifiedFace(); - if (sketchshape.IsNull()) - return new App::DocumentObjectExecReturn("Loft: Creating a face from sketch failed"); + TopoDS_Shape profilePoint; // if the Base property has a valid shape, fuse the pipe into it TopoDS_Shape base; @@ -102,80 +133,109 @@ App::DocumentObjectExecReturn *Loft::execute(void) base.Move(invObjLoc); // build up multisections - auto multisections = Sections.getValues(); + auto multisections = Sections.getSubListValues(); if (multisections.empty()) return new App::DocumentObjectExecReturn("Loft: At least one section is needed"); - std::vector> wiresections; - for (TopoDS_Wire& wire : wires) - wiresections.emplace_back(1, wire); + TopoDS_Shape profileShape = getSectionShape(Profile.getValue(), + Profile.getSubValues()); + if (profileShape.IsNull()) + return new App::DocumentObjectExecReturn("Loft: Could not obtain profile shape"); - for (auto obj : multisections) { - if (!obj->isDerivedFrom(Part::Feature::getClassTypeId())) - return new App::DocumentObjectExecReturn("Loft: All sections need to be part features"); - - // if the section is an object's face then take just the face - TopoDS_Shape shape; - if (obj->isDerivedFrom(Part::Part2DObject::getClassTypeId())) - shape = static_cast(obj)->Shape.getValue(); - else { - auto subValues = Sections.getSubValues(obj); - if (subValues.empty()) - throw Base::ValueError("Loft: No valid subelement linked in Part::Feature"); - - shape = static_cast(obj)->Shape.getShape().getSubShape(subValues[0].c_str()); - } + std::vector> wiresections; + size_t numWires = addWiresToWireSections(profileShape, wiresections); + if (numWires == 0) { + // profileShape had no wires so only other valid option is point section TopExp_Explorer ex; - size_t i=0; - for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next(), ++i) { - if (i>=wiresections.size()) - return new App::DocumentObjectExecReturn("Loft: Sections need to have the same amount of inner wires as the base section"); - wiresections[i].push_back(TopoDS::Wire(ex.Current())); + size_t i = 0; + for (ex.Init(profileShape, TopAbs_VERTEX); ex.More(); ex.Next(), ++i) { + profilePoint = ex.Current(); } - if (i 1) + return new App::DocumentObjectExecReturn("Loft: Only one isolated point is needed if using a sketch with isolated points for section"); + } + bool isLastSectionVertex = false; + + for (auto &subSet : multisections) { + if (!subSet.first->isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("Loft: All sections need to be part features"); + + // if the selected subvalue is a point, pick that even if we have a sketch + TopoDS_Shape shape = getSectionShape(subSet.first, subSet.second); + if (shape.IsNull()) + return new App::DocumentObjectExecReturn("Loft: Could not obtain section shape"); + + size_t numWiresAdded = addWiresToWireSections(shape, wiresections); + if (numWiresAdded == 0) { + TopExp_Explorer ex; + size_t j = 0; + for (ex.Init(shape, TopAbs_VERTEX); ex.More(); ex.Next(), ++j) { + if (isLastSectionVertex) + return new App::DocumentObjectExecReturn("Loft: Only the profile and last section can be vertices"); + isLastSectionVertex = true; + for (auto &wires : wiresections) + wires.push_back(ex.Current()); + } + if (j > 1) + return new App::DocumentObjectExecReturn("Loft: Only one isolated point is needed if using a sketch with isolated points for section"); + } + if (!isLastSectionVertex && numWiresAdded < wiresections.size()) + return new App::DocumentObjectExecReturn("Loft: Sections need to have the same amount of inner wires as the base section"); } // build all shells std::vector shells; - for (std::vector& wires : wiresections) { + TopoDS_Shape copyProfilePoint(profilePoint); + if (!profilePoint.IsNull()) + copyProfilePoint.Move(invObjLoc); + + for (auto& wires : wiresections) { BRepOffsetAPI_ThruSections mkTS(false, Ruled.getValue(), Precision::Confusion()); - for (TopoDS_Wire& wire : wires) { - wire.Move(invObjLoc); - mkTS.AddWire(wire); + if (!profilePoint.IsNull()) + mkTS.AddVertex(TopoDS::Vertex(copyProfilePoint)); + + for (auto& shape : wires) { + shape.Move(invObjLoc); + if (shape.ShapeType() == TopAbs_VERTEX) + mkTS.AddVertex(TopoDS::Vertex(shape)); + else + mkTS.AddWire(TopoDS::Wire(shape)); } mkTS.Build(); if (!mkTS.IsDone()) return new App::DocumentObjectExecReturn("Loft could not be built"); - //build the shell use simulate to get the top and bottom wires in an easy way + // build the shell use simulate to get the top and bottom wires in an easy way shells.push_back(mkTS.Shape()); } - //build the top and bottom face, sew the shell and build the final solid - TopoDS_Shape front = getVerifiedFace(); - front.Move(invObjLoc); - std::vector backwires; - for (std::vector& wires : wiresections) - backwires.push_back(wires.back()); - - TopoDS_Shape back = Part::FaceMakerCheese::makeFace(backwires); - + // build the top and bottom faces (where possible), sew the shell, + // and build the final solid BRepBuilderAPI_Sewing sewer; sewer.SetTolerance(Precision::Confusion()); - sewer.Add(front); - sewer.Add(back); + if (profilePoint.IsNull()) { + TopoDS_Shape front = getVerifiedFace(); + front.Move(invObjLoc); + sewer.Add(front); + } + if (!isLastSectionVertex) { + std::vector backwires; + for (auto& wires : wiresections) + backwires.push_back(TopoDS::Wire(wires.back())); + TopoDS_Shape back = Part::FaceMakerCheese::makeFace(backwires); + sewer.Add(back); + } for (TopoDS_Shape& s : shells) sewer.Add(s); sewer.Perform(); - //build the solid + // build the solid BRepBuilderAPI_MakeSolid mkSolid; mkSolid.Add(TopoDS::Shell(sewer.SewedShape())); if (!mkSolid.IsDone()) From ea10dfd85dcff2c3e286ecbf1ab7700cb0d0f3e9 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Sat, 13 Nov 2021 15:15:37 -0500 Subject: [PATCH 040/133] [PD] Allow sketch point profile in selection-based loft workflow --- src/Mod/PartDesign/Gui/Command.cpp | 40 ++++++++++++++----- src/Mod/PartDesign/Gui/TaskLoftParameters.cpp | 3 ++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 144e9a0494..ec5d49db68 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -1004,18 +1004,32 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons auto Feat = pcActiveBody->getDocument()->getObject(FeatName.c_str()); auto objCmd = Gui::Command::getObjectCmd(feature); - if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) || subs.empty()) { - FCMD_OBJ_CMD(Feat,"Profile = " << objCmd); - } - else { - std::ostringstream ss; - for (auto &s : subs) - ss << "'" << s << "',"; - FCMD_OBJ_CMD(Feat,"Profile = (" << objCmd << ", [" << ss.str() << "])"); - } - //for additive and subtractive lofts allow the user to preselect the sections + auto runProfileCmd = + [=]() { + FCMD_OBJ_CMD(Feat,"Profile = " << objCmd); + }; + + auto runProfileCmdWithSubs = + [=]() { + std::ostringstream ss; + for (auto &s : subs) + ss << "'" << s << "',"; + FCMD_OBJ_CMD(Feat,"Profile = (" << objCmd << ", [" << ss.str() << "])"); + }; + if (which.compare("AdditiveLoft") == 0 || which.compare("SubtractiveLoft") == 0) { + // for additive and subtractive lofts set subvalues even for sketches + // when a vertex is first selected + auto subName = subs.empty() ? "" : subs.front(); + + if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) && + !(subName.size() > 6 && subName.substr(0,6) == "Vertex")) + runProfileCmd(); + else + runProfileCmdWithSubs(); + + // for additive and subtractive lofts allow the user to preselect the sections std::vector selection = cmd->getSelection().getSelectionEx(); if (selection.size() > 1) { //treat additional selected objects as sections for (std::vector::size_type ii = 1; ii < selection.size(); ii++) { @@ -1028,6 +1042,12 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons } } } + else { + if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) || subs.empty()) + runProfileCmd(); + else + runProfileCmdWithSubs(); + } // for additive and subtractive pipes allow the user to preselect the spines if (which.compare("AdditivePipe") == 0 || which.compare("SubtractivePipe") == 0) { diff --git a/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp b/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp index db0d0d65fe..9511e0fb20 100644 --- a/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLoftParameters.cpp @@ -105,6 +105,7 @@ TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView, bool /*newObj if (profile) { Gui::Application::Instance->showViewProvider(profile); + // TODO: if it is a single vertex of a sketch, use that subshape's name QString label = make2DLabel(profile, loft->Profile.getSubValues()); ui->profileBaseEdit->setText(label); } @@ -112,6 +113,7 @@ TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView, bool /*newObj for (auto &subSet : loft->Sections.getSubListValues()) { Gui::Application::Instance->showViewProvider(subSet.first); + // TODO: if it is a single vertex of a sketch, use that subshape's name QString label = make2DLabel(subSet.first, subSet.second); QListWidgetItem* item = new QListWidgetItem(); item->setText(label); @@ -152,6 +154,7 @@ void TaskLoftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) App::Document* document = App::GetApplication().getDocument(msg.pDocName); App::DocumentObject* object = document ? document->getObject(msg.pObjectName) : nullptr; if (object) { + // TODO: if it is a single vertex of a sketch, use that subshape's name QString label = make2DLabel(object, {msg.pSubName}); if (selectionMode == refProfile) { ui->profileBaseEdit->setText(label); From ab26d4d0d20071112974f361283050e5b9708ed6 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Sun, 21 Nov 2021 22:00:40 -0500 Subject: [PATCH 041/133] [PD] Change some strings and comments in loft code Suggestions by @donovaly. --- src/Mod/PartDesign/App/FeatureLoft.cpp | 4 ++-- src/Mod/PartDesign/Gui/Command.cpp | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureLoft.cpp b/src/Mod/PartDesign/App/FeatureLoft.cpp index 11622296ea..8a62a80774 100644 --- a/src/Mod/PartDesign/App/FeatureLoft.cpp +++ b/src/Mod/PartDesign/App/FeatureLoft.cpp @@ -153,7 +153,7 @@ App::DocumentObjectExecReturn *Loft::execute(void) profilePoint = ex.Current(); } if (i > 1) - return new App::DocumentObjectExecReturn("Loft: Only one isolated point is needed if using a sketch with isolated points for section"); + return new App::DocumentObjectExecReturn("Loft: When using points for profile/sections, the sketch should have a single point"); } bool isLastSectionVertex = false; @@ -179,7 +179,7 @@ App::DocumentObjectExecReturn *Loft::execute(void) wires.push_back(ex.Current()); } if (j > 1) - return new App::DocumentObjectExecReturn("Loft: Only one isolated point is needed if using a sketch with isolated points for section"); + return new App::DocumentObjectExecReturn("Loft: When using points for profile/sections, the sketch should have a single point"); } if (!isLastSectionVertex && numWiresAdded < wiresections.size()) return new App::DocumentObjectExecReturn("Loft: Sections need to have the same amount of inner wires as the base section"); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index ec5d49db68..27a1b754a7 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -1005,11 +1005,14 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons auto objCmd = Gui::Command::getObjectCmd(feature); + // run the command in console to set the profile (without selected subelements) auto runProfileCmd = [=]() { FCMD_OBJ_CMD(Feat,"Profile = " << objCmd); }; + // run the command in console to set the profile with selected subelements + // useful to set, say, a face of a solid as the "profile" auto runProfileCmdWithSubs = [=]() { std::ostringstream ss; @@ -1023,6 +1026,9 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons // when a vertex is first selected auto subName = subs.empty() ? "" : subs.front(); + // `ProfileBased::getProfileShape()` and other methods will return + // just the sub-shapes if they are set. So when whole sketches are + // desired, don not set sub-values. if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) && !(subName.size() > 6 && subName.substr(0,6) == "Vertex")) runProfileCmd(); From b9e72f1a7ce289293ac440cc7494b6abc537d281 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Mon, 22 Nov 2021 12:21:26 +0800 Subject: [PATCH 042/133] App: fix subname encoding when saving property links --- src/App/PropertyLinks.cpp | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/App/PropertyLinks.cpp b/src/App/PropertyLinks.cpp index 4d4e696d74..5bdbb5286f 100644 --- a/src/App/PropertyLinks.cpp +++ b/src/App/PropertyLinks.cpp @@ -1321,20 +1321,20 @@ void PropertyLinkSub::Save (Base::Writer &writer) const writer.Stream() << writer.ind() << "getExportName() << "\" sub=\""; if(exporting) { std::string exportName; - writer.Stream() << exportSubName(exportName,obj,sub.c_str()); + writer.Stream() << encodeAttribute(exportSubName(exportName,obj,sub.c_str())); if(shadow.second.size() && _lSubList[i]==shadow.first) writer.Stream() << "\" " ATTR_MAPPED "=\"1"; } else { - writer.Stream() << sub; + writer.Stream() << encodeAttribute(sub); if(_lSubList[i].size()) { if(sub!=_lSubList[i]) { // Stores the actual value that is shadowed. For new version FC, // we will restore this shadowed value instead. - writer.Stream() << "\" " ATTR_SHADOWED "=\"" << _lSubList[i]; + writer.Stream() << "\" " ATTR_SHADOWED "=\"" << encodeAttribute(_lSubList[i]); }else if(shadow.first.size()) { // Here means the user set value is old style element name. // We shall then store the shadow somewhere else. - writer.Stream() << "\" " ATTR_SHADOW "=\"" << shadow.first; + writer.Stream() << "\" " ATTR_SHADOW "=\"" << encodeAttribute(shadow.first); } } } @@ -3316,16 +3316,17 @@ void PropertyXLink::Save (Base::Writer &writer) const { const auto &sub = shadowSub.second.empty()?subName:shadowSub.second; if(exporting) { std::string exportName; - writer.Stream() << "\" sub=\"" << exportSubName(exportName,_pcLink,sub.c_str()); + writer.Stream() << "\" sub=\"" << + encodeAttribute(exportSubName(exportName,_pcLink,sub.c_str())); if(shadowSub.second.size() && shadowSub.first==subName) writer.Stream() << "\" " ATTR_MAPPED "=\"1"; }else{ - writer.Stream() << "\" sub=\"" << sub; + writer.Stream() << "\" sub=\"" << encodeAttribute(sub); if(sub.size()) { if(sub!=subName) - writer.Stream() << "\" " ATTR_SHADOWED "=\"" << subName; + writer.Stream() << "\" " ATTR_SHADOWED "=\"" << encodeAttribute(subName); else if(shadowSub.first.size()) - writer.Stream() << "\" " ATTR_SHADOW "=\"" << shadowSub.first; + writer.Stream() << "\" " ATTR_SHADOW "=\"" << encodeAttribute(shadowSub.first); } } writer.Stream() << "\"/>" << std::endl; @@ -3341,16 +3342,16 @@ void PropertyXLink::Save (Base::Writer &writer) const { writer.Stream() << writer.ind() << "" << endl; From d34a5616a2b38c96ad05f9a0763ba7504dfb814d Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 22 Nov 2021 11:52:17 +0100 Subject: [PATCH 043/133] PD: If pad/pocket is directly used on several faces then determine the normal of the first face --- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 497f3ea6be..61642fa42c 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -65,7 +65,6 @@ # include # include # include -# include # include # include # include @@ -1180,18 +1179,21 @@ Base::Vector3d ProfileBased::getProfileNormal() const { } else { TopoDS_Shape shape = getVerifiedFace(true); - if (shape == TopoDS_Shape()) + if (shape.IsNull()) return SketchVector; - if (shape.ShapeType() == TopAbs_FACE) { - BRepAdaptor_Surface adapt(TopoDS::Face(shape)); + // the shape can be a single face or a compound of faces, only consider the first face + TopExp_Explorer ex(shape, TopAbs_FACE); + if (ex.More()) { + TopoDS_Face face = TopoDS::Face(ex.Current()); + BRepAdaptor_Surface adapt(face); double u = adapt.FirstUParameter() + (adapt.LastUParameter() - adapt.FirstUParameter())/2.; double v = adapt.FirstVParameter() + (adapt.LastVParameter() - adapt.FirstVParameter())/2.; BRepLProp_SLProps prop(adapt,u,v,2,Precision::Confusion()); if(prop.IsNormalDefined()) { gp_Pnt pnt; gp_Vec vec; // handles the orientation state of the shape - BRepGProp_Face(TopoDS::Face(shape)).Normal(u,v,pnt,vec); + BRepGProp_Face(face).Normal(u,v,pnt,vec); SketchVector = Base::Vector3d(vec.X(), vec.Y(), vec.Z()); } } From 563743e7e657321ae4e02eeeb9af83e378903e4e Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 22 Nov 2021 16:50:21 +0100 Subject: [PATCH 044/133] Gui: do not include generated ui file inside header file --- src/Gui/PropertyPage.cpp | 3 +++ src/Gui/WidgetFactory.cpp | 2 ++ src/Gui/Widgets.cpp | 10 ++++++---- src/Gui/Widgets.h | 16 +++++++++++++--- .../Inspection/Gui/ViewProviderInspection.cpp | 1 + src/Mod/TechDraw/Gui/QGIViewAnnotation.cpp | 2 ++ 6 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/Gui/PropertyPage.cpp b/src/Gui/PropertyPage.cpp index 303b730516..abb87001a0 100644 --- a/src/Gui/PropertyPage.cpp +++ b/src/Gui/PropertyPage.cpp @@ -22,6 +22,9 @@ #include "PreCompiled.h" +#ifndef _PreComp_ +# include +#endif #include "PropertyPage.h" #include "PrefWidgets.h" diff --git a/src/Gui/WidgetFactory.cpp b/src/Gui/WidgetFactory.cpp index 241c35f655..5ca34a3aa5 100644 --- a/src/Gui/WidgetFactory.cpp +++ b/src/Gui/WidgetFactory.cpp @@ -25,6 +25,8 @@ #ifndef _PreComp_ # include # include +# include +# include #endif #ifdef FC_OS_WIN32 diff --git a/src/Gui/Widgets.cpp b/src/Gui/Widgets.cpp index cf59f11167..b893ef6479 100644 --- a/src/Gui/Widgets.cpp +++ b/src/Gui/Widgets.cpp @@ -56,6 +56,7 @@ #include "DlgExpressionInput.h" #include "QuantitySpinBox_p.h" #include "Tools.h" +#include "ui_DlgTreeWidget.h" using namespace Gui; using namespace App; @@ -526,8 +527,9 @@ void ClearLineEdit::updateClearButton(const QString& text) */ CheckListDialog::CheckListDialog( QWidget* parent, Qt::WindowFlags fl ) : QDialog( parent, fl ) + , ui(new Ui_DlgTreeWidget) { - ui.setupUi(this); + ui->setupUi(this); } /** @@ -544,7 +546,7 @@ CheckListDialog::~CheckListDialog() void CheckListDialog::setCheckableItems( const QStringList& items ) { for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it ) { - QTreeWidgetItem* item = new QTreeWidgetItem(ui.treeWidget); + QTreeWidgetItem* item = new QTreeWidgetItem(ui->treeWidget); item->setText(0, *it); item->setCheckState(0, Qt::Unchecked); } @@ -557,7 +559,7 @@ void CheckListDialog::setCheckableItems( const QStringList& items ) void CheckListDialog::setCheckableItems( const QList& items ) { for ( QList::ConstIterator it = items.begin(); it != items.end(); ++it ) { - QTreeWidgetItem* item = new QTreeWidgetItem(ui.treeWidget); + QTreeWidgetItem* item = new QTreeWidgetItem(ui->treeWidget); item->setText(0, (*it).first); item->setCheckState(0, ( (*it).second ? Qt::Checked : Qt::Unchecked)); } @@ -576,7 +578,7 @@ QStringList CheckListDialog::getCheckedItems() const */ void CheckListDialog::accept () { - QTreeWidgetItemIterator it(ui.treeWidget, QTreeWidgetItemIterator::Checked); + QTreeWidgetItemIterator it(ui->treeWidget, QTreeWidgetItemIterator::Checked); while (*it) { checked.push_back((*it)->text(0)); ++it; diff --git a/src/Gui/Widgets.h b/src/Gui/Widgets.h index c4064eb50e..796a55404e 100644 --- a/src/Gui/Widgets.h +++ b/src/Gui/Widgets.h @@ -24,7 +24,7 @@ #ifndef GUI_WIDGETS_H #define GUI_WIDGETS_H -#include +#include #include #include #include @@ -36,7 +36,16 @@ #include #include #include "ExpressionBinding.h" -#include "Base/Parameter.h" +#include +#include +#include + + +class QGridLayout; +class QVBoxLayout; +class QTreeWidget; +class QTreeWidgetItem; +class QSpacerItem; namespace Gui { class PrefCheckBox; @@ -164,6 +173,7 @@ private: // ------------------------------------------------------------------------------ typedef QPair CheckListItem; +class Ui_DlgTreeWidget; /** * The CheckListDialog class provides a dialog with a QListView with @@ -187,7 +197,7 @@ public: private: QStringList checked; - Ui_DlgTreeWidget ui; + std::unique_ptr ui; }; // ------------------------------------------------------------------------------ diff --git a/src/Mod/Inspection/Gui/ViewProviderInspection.cpp b/src/Mod/Inspection/Gui/ViewProviderInspection.cpp index f04cc0c6fe..a5099038ca 100644 --- a/src/Mod/Inspection/Gui/ViewProviderInspection.cpp +++ b/src/Mod/Inspection/Gui/ViewProviderInspection.cpp @@ -24,6 +24,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include # include #endif diff --git a/src/Mod/TechDraw/Gui/QGIViewAnnotation.cpp b/src/Mod/TechDraw/Gui/QGIViewAnnotation.cpp index 5a252d0b54..d8e3c6571c 100644 --- a/src/Mod/TechDraw/Gui/QGIViewAnnotation.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewAnnotation.cpp @@ -24,6 +24,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ #include +#include #include #include #include @@ -34,6 +35,7 @@ #include #include #include +#include #include #endif From fc31a79eef2d7a7146c9d0177ae9a40dcc72acf9 Mon Sep 17 00:00:00 2001 From: luz paz Date: Mon, 22 Nov 2021 09:55:16 -0500 Subject: [PATCH 045/133] Gui: remove superfluous whitespace from translation string Avoids possible translation mistakes by only exposing non-whitespace strings. --- src/Gui/CommandPyImp.cpp | 2 +- src/Gui/Document.cpp | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Gui/CommandPyImp.cpp b/src/Gui/CommandPyImp.cpp index 332434ce65..853c19bf5d 100644 --- a/src/Gui/CommandPyImp.cpp +++ b/src/Gui/CommandPyImp.cpp @@ -101,7 +101,7 @@ PyObject* CommandPy::listByShortcut(PyObject *args) re.setCaseSensitivity(Qt::CaseInsensitive); if (!re.isValid()){ std::stringstream str; - str << "Invalid regular expression: " << shortcut_to_find; + str << "Invalid regular expression:" << ' ' << shortcut_to_find; throw Py::RuntimeError(str.str()); } diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index d5110459e2..04ac6abeff 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -1081,15 +1081,21 @@ static bool checkCanonicalPath(const std::map &docs) FC_WARN(" Document: " << docName(d).toUtf8().constData() << ": " << d->FileName.getValue()); if (count == 3) { - ts << QObject::tr("\n\nPlease check report view for more..."); + ts << "\n\n" + << QObject::tr("Please check report view for more..."); } else if (count < 3) { - ts << QObject::tr("\n\nPhysical path: ") << v.first - << QObject::tr("\nDocument: ") << docName(doc) - << QObject::tr("\n Path: ") << QString::fromUtf8(doc->FileName.getValue()); + ts << "\n\n" + << QObject::tr("Physical path:") << ' ' << v.first + << "\n" + << QObject::tr("Document:") << ' ' << docName(doc) + << "\n" << ' ' + << QObject::tr("Path:") << ' ' << QString::fromUtf8(doc->FileName.getValue()); for (auto d : v.second) { if (d == doc) continue; - ts << QObject::tr("\nDocument: ") << docName(d) - << QObject::tr("\n Path: ") << QString::fromUtf8(d->FileName.getValue()); + ts << "\n" + << QObject::tr("Document:") << ' ' << docName(d) + << "\n" << ' ' + << QObject::tr("Path:") << ' ' << QString::fromUtf8(d->FileName.getValue()); } } ++count; From e5ea670633034f032435737db22f5a4bd497742f Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Sun, 21 Nov 2021 18:58:34 +0100 Subject: [PATCH 046/133] [Sketcher][Bugfix] Fix crash when applying 'Constrain internal alignment' on contraints, fixes #4790 --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index f6a4f0b57b..ccd25e94a6 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -7209,13 +7209,13 @@ void CmdSketcherConstrainInternalAlignment::activated(int iMsg) const Part::Geometry *geo = Obj->getGeometry(GeoId); - if (geo->getTypeId() == Part::GeomPoint::getClassTypeId()) + if (geo && geo->getTypeId() == Part::GeomPoint::getClassTypeId()) pointids.push_back(GeoId); - else if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) + else if (geo && geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) lineids.push_back(GeoId); - else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) + else if (geo && geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) ellipseids.push_back(GeoId); - else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) + else if (geo && geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) arcsofellipseids.push_back(GeoId); else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), From 792277a848c5bb5d5cfbdf592e8c9991b7fa4889 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 22 Nov 2021 23:00:30 +0100 Subject: [PATCH 047/133] Gui: add button group that allows to uncheck all buttons in exclusive mode --- src/Gui/Widgets.cpp | 30 ++++++++++++++++++++++++++++++ src/Gui/Widgets.h | 20 ++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/Gui/Widgets.cpp b/src/Gui/Widgets.cpp index b893ef6479..e3c1c87147 100644 --- a/src/Gui/Widgets.cpp +++ b/src/Gui/Widgets.cpp @@ -1664,4 +1664,34 @@ void ExpLineEdit::keyPressEvent(QKeyEvent *event) QLineEdit::keyPressEvent(event); } +// -------------------------------------------------------------------- + +ButtonGroup::ButtonGroup(QObject *parent) + : QButtonGroup(parent) + , _exclusive(true) +{ + QButtonGroup::setExclusive(false); + + connect(this, QOverload::of(&QButtonGroup::buttonClicked), + [=](QAbstractButton *button) { + if (exclusive()) { + for (auto btn : buttons()) { + if (btn && btn != button && btn->isCheckable()) + btn->setChecked(false); + } + } + }); +} + +void ButtonGroup::setExclusive(bool on) +{ + _exclusive = on; +} + +bool ButtonGroup::exclusive() const +{ + return _exclusive; +} + + #include "moc_Widgets.cpp" diff --git a/src/Gui/Widgets.h b/src/Gui/Widgets.h index 796a55404e..c9aacb80be 100644 --- a/src/Gui/Widgets.h +++ b/src/Gui/Widgets.h @@ -24,6 +24,7 @@ #ifndef GUI_WIDGETS_H #define GUI_WIDGETS_H +#include #include #include #include @@ -572,6 +573,25 @@ private: bool autoClose; }; +/*! + * \brief The ButtonGroup class + * Unlike Qt's QButtonGroup this class allows it that in exclusive mode + * all buttons can be unchecked. + */ +class GuiExport ButtonGroup : public QButtonGroup +{ + Q_OBJECT + +public: + ButtonGroup(QObject *parent = nullptr); + + void setExclusive(bool on); + bool exclusive() const; + +private: + bool _exclusive; +}; + } // namespace Gui #endif // GUI_WIDGETS_H From 9d15df29d94410fd18b3001592020c2547261250 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Mon, 8 Nov 2021 22:36:40 +0100 Subject: [PATCH 048/133] [Gui] Expose API for corner axis cross visibility/size to Python --- src/Gui/View3DPy.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/Gui/View3DPy.h | 4 ++++ 2 files changed, 48 insertions(+) diff --git a/src/Gui/View3DPy.cpp b/src/Gui/View3DPy.cpp index 23a0a68da6..a5eae1992d 100644 --- a/src/Gui/View3DPy.cpp +++ b/src/Gui/View3DPy.cpp @@ -207,6 +207,14 @@ void View3DInventorPy::init_type() "hasClippingPlane(): check whether this clipping plane is active"); add_varargs_method("graphicsView",&View3DInventorPy::graphicsView, "graphicsView(): Access this view as QGraphicsView"); + add_varargs_method("setCornerCrossVisible",&View3DInventorPy::setCornerCrossVisible, + "setCornerCrossVisible(bool): Defines corner axis cross visibility"); + add_varargs_method("isCornerCrossVisible",&View3DInventorPy::isCornerCrossVisible, + "isCornerCrossVisible(): Returns current corner axis cross visibility"); + add_varargs_method("setCornerCrossSize",&View3DInventorPy::setCornerCrossSize, + "setCornerCrossSize(int): Defines corner axis cross size"); + add_varargs_method("getCornerCrossSize",&View3DInventorPy::getCornerCrossSize, + "getCornerCrossSize(): Returns current corner axis cross size"); add_varargs_method("cast_to_base", &View3DInventorPy::cast_to_base, "cast_to_base() cast to MDIView class"); } @@ -2646,6 +2654,42 @@ Py::Object View3DInventorPy::graphicsView(const Py::Tuple& args) return wrap.fromQWidget(getView3DIventorPtr()->getViewer(), "QGraphicsView"); } +Py::Object View3DInventorPy::setCornerCrossVisible(const Py::Tuple& args) +{ + int ok; + if (!PyArg_ParseTuple(args.ptr(), "i", &ok)) + throw Py::Exception(); + getView3DIventorPtr()->getViewer()->setFeedbackVisibility(ok!=0); + getView3DIventorPtr()->getViewer()->redraw(); // added because isViewing() returns False when focus is in Python Console + return Py::None(); +} + +Py::Object View3DInventorPy::isCornerCrossVisible(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + bool ok = getView3DIventorPtr()->getViewer()->isFeedbackVisible(); + return Py::Boolean(ok ? true : false); +} + +Py::Object View3DInventorPy::setCornerCrossSize(const Py::Tuple& args) +{ + int size=0; + if (!PyArg_ParseTuple(args.ptr(), "i", &size)) + throw Py::Exception(); + getView3DIventorPtr()->getViewer()->setFeedbackSize(size); + getView3DIventorPtr()->getViewer()->redraw(); // added because isViewing() returns False when focus is in Python Console + return Py::None(); +} + +Py::Object View3DInventorPy::getCornerCrossSize(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + int size = getView3DIventorPtr()->getViewer()->getFeedbackSize(); + return Py::Int(size); +} + Py::Object View3DInventorPy::cast_to_base(const Py::Tuple&) { return Gui::MDIViewPy::create(getView3DIventorPtr()); diff --git a/src/Gui/View3DPy.h b/src/Gui/View3DPy.h index 9a7bf17148..49076c6645 100644 --- a/src/Gui/View3DPy.h +++ b/src/Gui/View3DPy.h @@ -139,6 +139,10 @@ public: Py::Object toggleClippingPlane(const Py::Tuple& args, const Py::Dict &); Py::Object hasClippingPlane(const Py::Tuple& args); Py::Object graphicsView(const Py::Tuple& args); + Py::Object setCornerCrossVisible(const Py::Tuple& args); + Py::Object isCornerCrossVisible(const Py::Tuple& args); + Py::Object setCornerCrossSize(const Py::Tuple& args); + Py::Object getCornerCrossSize(const Py::Tuple& args); private: static void eventCallback(void * ud, SoEventCallback * n); From 3d329093022eded26d57a594eb7079a1c6cae057 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Wed, 17 Nov 2021 12:42:00 +0100 Subject: [PATCH 049/133] [Gui] Render corner cross labels as pixel maps so they are scalable --- src/Gui/View3DInventorViewer.cpp | 57 ++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index bedc3c6d22..cde72dc3cb 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -3268,10 +3268,48 @@ void View3DInventorViewer::setViewing(SbBool enable) //**************************************************************************** -// Bitmap representations of an "X", a "Y" and a "Z" for the axis cross. -static GLubyte xbmp[] = { 0x11,0x11,0x0a,0x04,0x0a,0x11,0x11 }; -static GLubyte ybmp[] = { 0x04,0x04,0x04,0x04,0x0a,0x11,0x11 }; -static GLubyte zbmp[] = { 0x1f,0x10,0x08,0x04,0x02,0x01,0x1f }; +// Pixel map representations of an "X", a "Y" and a "Z" for the axis cross. +#define O {0,255} // black pixel +#define I {255,0} // transparent pixel + +static uchar xPM[9][7][2] = { + {I,I,I,I,I,I,I}, + {I,O,I,I,I,O,I}, + {I,O,I,I,I,O,I}, + {I,I,O,I,O,I,I}, + {I,I,I,O,I,I,I}, + {I,I,O,I,O,I,I}, + {I,O,I,I,I,O,I}, + {I,O,I,I,I,O,I}, + {I,I,I,I,I,I,I} +}; + +static uchar yPM[9][7][2] = { + {I,I,I,I,I,I,I}, + {I,I,I,O,I,I,I}, + {I,I,I,O,I,I,I}, + {I,I,I,O,I,I,I}, + {I,I,I,O,I,I,I}, + {I,I,O,I,O,I,I}, + {I,O,I,I,I,O,I}, + {I,O,I,I,I,O,I}, + {I,I,I,I,I,I,I} +}; + +static uchar zPM[9][7][2] = { + {I,I,I,I,I,I,I}, + {I,O,O,O,O,O,I}, + {I,O,I,I,I,I,I}, + {I,I,O,I,I,I,I}, + {I,I,I,O,I,I,I}, + {I,I,I,I,O,I,I}, + {I,I,I,I,I,O,I}, + {I,O,O,O,O,O,I}, + {I,I,I,I,I,I,I} +}; + +#undef O +#undef I void View3DInventorViewer::drawAxisCross(void) { @@ -3429,12 +3467,17 @@ void View3DInventorViewer::drawAxisCross(void) else glColor3fv(SbVec3f(0.0f, 0.0f, 0.0f).getValue()); + //glEnable(GL_ALPHA_TEST); + //glAlphaFunc(GL_GREATER, 0.5); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glPixelZoom((float)axiscrossSize/10, (float)axiscrossSize/10); glRasterPos2d(xpos[0], xpos[1]); - glBitmap(8, 7, 0, 0, 0, 0, xbmp); + glDrawPixels(7, 9, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, xPM); glRasterPos2d(ypos[0], ypos[1]); - glBitmap(8, 7, 0, 0, 0, 0, ybmp); + glDrawPixels(7, 9, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, yPM); glRasterPos2d(zpos[0], zpos[1]); - glBitmap(8, 7, 0, 0, 0, 0, zbmp); + glDrawPixels(7, 9, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, zPM); glPixelStorei(GL_UNPACK_ALIGNMENT, unpack); glPopMatrix(); From 513b49aa7efb7f4ff32fb8b6e0e59df33efe11e1 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Wed, 17 Nov 2021 17:04:03 +0100 Subject: [PATCH 050/133] [Gui] Improve corner cross labels rendering by using larger antialiased pixmaps --- src/Gui/CornerCrossLetters.h | 235 +++++++++++++++++++++++++++++++ src/Gui/View3DInventorViewer.cpp | 57 +------- 2 files changed, 241 insertions(+), 51 deletions(-) create mode 100644 src/Gui/CornerCrossLetters.h diff --git a/src/Gui/CornerCrossLetters.h b/src/Gui/CornerCrossLetters.h new file mode 100644 index 0000000000..aec6e95048 --- /dev/null +++ b/src/Gui/CornerCrossLetters.h @@ -0,0 +1,235 @@ +#ifndef GUI_CORNERCROSSLETTERS_H +#define GUI_CORNERCROSSLETTERS_H + +namespace Gui { + +//**************************************************************************** + +// Pixel map representations of an "X", a "Y" and a "Z" for the axis cross. +// Each character is defined as a 21x27 grayscale RGBA pixel map +// 21x27 is 3x a standard 5x7 representation with 1px margin +// This allows good anti-aliasing aspect at any usable size +// It is generated with Gimp using Bitstream Charter Bold font, 28 px, on transparent background +// It is then directy exported as C source type after image is vertically flipped for direct GL usage +// With enabled options "Use macros instead of struct" and "Save alpha channel" + +#define XPM_WIDTH (21) +#define XPM_HEIGHT (27) +#define XPM_BYTES_PER_PIXEL (4) /* 2:RGB16, 3:RGB, 4:RGBA */ +#define XPM_PIXEL_DATA ((unsigned char*) XPM_pixel_data) +static const unsigned char XPM_pixel_data[21 * 27 * 4 + 1] = +("\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\261\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\320\000\000\000\003\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000w\000\000\000\377\000\000\000\377\000\000\000\377\000" + "\000\000\377\000\000\000Y\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\364\000\000\000\377\000\000\000\377\000\000" + "\000\377\000\000\000j\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\032\000\000" + "\000\363\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\264\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000u\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\355\000\000\000\023\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\245\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\363" + "\000\000\000\035\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\322\000\000\000\377\000\000" + "\000\377\000\000\000\377\000\000\000\230\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000<\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000l\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000:\000\000\000\376\000\000\000\377\000\000\000\377\000\000\000\375\000\000\000\062\000\000\000" + "\000\000\000\000\000\000\000\000\002\000\000\000\317\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\306\000\000\000" + "\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\233\000\000\000" + "\377\000\000\000\377\000\000\000\377\000\000\000\305\000\000\000\001\000\000\000\000\000\000\000h\000\000\000\377\000\000\000" + "\377\000\000\000\377\000\000\000\371\000\000\000*\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\021\000\000\000\352\000\000\000\377\000\000\000\377\000\000\000\377\000" + "\000\000]\000\000\000\022\000\000\000\354\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\177\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000^\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\347\000\000\000\241\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\325\000\000\000\006\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\277\000\000\000\377\000\000\000\377\000" + "\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\375\000\000\000\071\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000(\000\000\000\371\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\222\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\215\000\000\000\377\000\000\000" + "\377\000\000\000\377\000\000\000\377\000\000\000\375\000\000\000\026\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\003\000\000\000\315\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000" + "\202\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000l\000\000\000\377\000\000\000\377\000\000\000\377\000" + "\000\000\377\000\000\000\377\000\000\000\377\000\000\000\370\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\027\000\000" + "\000\360\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\305\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\265\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\243\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\302" + "\000\000\000\015\000\000\000\351\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000N\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000>\000\000\000\377\000" + "\000\000\377\000\000\000\377\000\000\000\376\000\000\000\063\000\000\000\000\000\000\000i\000\000\000\377\000\000\000\377\000" + "\000\000\377\000\000\000\337\000\000\000\011\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\004\000\000\000\324\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\241\000\000\000" + "\000\000\000\000\000\000\000\000\003\000\000\000\326\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\201\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000u\000\000\000\377\000\000\000" + "\377\000\000\000\377\000\000\000\365\000\000\000\033\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000M\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\367\000\000\000#\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\034\000\000\000\363\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\200\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\276\000\000\000\377\000\000\000\377\000\000\000\377\000\000" + "\000\264\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\253\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\345\000\000\000\012\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\062\000\000\000\376\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000M\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000G\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000_\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\243\000\000\000\377\000\000\000\377\000\000\000" + "\377\000\000\000\336\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000"); + +#define YPM_WIDTH (21) +#define YPM_HEIGHT (27) +#define YPM_BYTES_PER_PIXEL (4) /* 2:RGB16, 3:RGB, 4:RGBA */ +#define YPM_PIXEL_DATA ((unsigned char*) YPM_pixel_data) +static const unsigned char YPM_pixel_data[21 * 27 * 4 + 1] = +("\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\\\000\000\000\377\000\000\000" + "\377\000\000\000\377\000\000\000\330\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\\\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\330\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\\\000\000\000\377\000\000\000\377\000\000\000\377\000\000" + "\000\330\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\\\000\000\000" + "\377\000\000\000\377\000\000\000\377\000\000\000\330\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\\\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\330\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\\\000\000\000\377\000\000\000\377\000\000" + "\000\377\000\000\000\330\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\\\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\330\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\\\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\330\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\242\000\000\000\377\000" + "\000\000\377\000\000\000\377\000\000\000\365\000\000\000\026\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000'\000\000\000\374\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\216\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\246\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\367\000\000\000\033\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000+\000\000" + "\000\375\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\225" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\253\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\371\000" + "\000\000\377\000\000\000\377\000\000\000\377\000\000\000\371\000\000\000\037\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000/\000\000\000\376\000" + "\000\000\377\000\000\000\377\000\000\000\377\000\000\000d\000\000\000\340\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\235\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\260\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\332\000\000\000\003" + "\000\000\000e\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\373\000\000\000$\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\063\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\\\000\000\000\000\000\000\000\004\000\000\000\335\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\244\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\265\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\330\000\000\000\003\000\000\000" + "\000\000\000\000\000\000\000\000a\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\375\000\000\000*\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\070\000\000\000\377\000\000\000\377\000\000\000" + "\377\000\000\000\377\000\000\000Z\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\000\000\000\332\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\253\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\272\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\327\000\000\000\002\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000]\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\376\000\000\000" + "\060\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000<\000\000\000\377\000\000\000\377\000\000\000\377\000" + "\000\000\377\000\000\000X\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\327" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\262\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\277\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\325\000\000\000\002\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000Y\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000" + "\377\000\000\000\066\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000"); + +#define ZPM_WIDTH (21) +#define ZPM_HEIGHT (27) +#define ZPM_BYTES_PER_PIXEL (4) /* 2:RGB16, 3:RGB, 4:RGBA */ +#define ZPM_PIXEL_DATA ((unsigned char*) ZPM_pixel_data) +static const unsigned char ZPM_pixel_data[21 * 27 * 4 + 1] = +("\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000T\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000" + "\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\214\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000T\000\000\000" + "\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\214\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000L\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000" + "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\214\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\003\000\000\000\312\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\360\000\000" + "\000u\000\000\000t\000\000\000t\000\000\000t\000\000\000t\000\000\000t\000\000\000t\000\000\000t\000\000\000t\000\000\000?\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000.\000\000\000\372\000\000\000\377\000\000\000" + "\377\000\000\000\377\000\000\000d\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\204\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\357\000\000\000\031\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007\000\000\000\327\000\000\000\377\000\000\000\377\000" + "\000\000\377\000\000\000\255\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000;\000\000\000\376\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000R\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\225\000\000\000\377\000\000\000\377\000\000\000\377\000" + "\000\000\346\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\015" + "\000\000\000\342\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\233\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000K\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000" + "\377\000\000\000A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\246" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\334\000\000\000\011\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\025\000\000\000\353\000\000\000\377\000\000\000\377\000\000\000\377\000" + "\000\000\212\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\\\000\000" + "\000\377\000\000\000\377\000\000\000\377\000\000\000\374\000\000\000\062\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\266\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\317" + "\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\363" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000x\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000m\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\367\000\000\000%\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\011\000\000\000t\000\000\000t\000\000" + "\000t\000\000\000t\000\000\000t\000\000\000t\000\000\000t\000\000\000t\000\000\000v\000\000\000\363\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\300\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\024\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000" + "\000?\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\024\000\000\000\377\000\000\000\377\000" + "\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000" + "\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000H\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\024\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000" + "\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000H\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"); + +} + +#endif //GUI_CORNERCROSSLETTERS_H diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index cde72dc3cb..08c9500dd1 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -150,6 +150,8 @@ #include "ViewProviderLink.h" +#include "CornerCrossLetters.h" + FC_LOG_LEVEL_INIT("3DViewer",true,true) //#define FC_LOGGING_CB @@ -3266,51 +3268,6 @@ void View3DInventorViewer::setViewing(SbBool enable) inherited::setViewing(enable); } -//**************************************************************************** - -// Pixel map representations of an "X", a "Y" and a "Z" for the axis cross. -#define O {0,255} // black pixel -#define I {255,0} // transparent pixel - -static uchar xPM[9][7][2] = { - {I,I,I,I,I,I,I}, - {I,O,I,I,I,O,I}, - {I,O,I,I,I,O,I}, - {I,I,O,I,O,I,I}, - {I,I,I,O,I,I,I}, - {I,I,O,I,O,I,I}, - {I,O,I,I,I,O,I}, - {I,O,I,I,I,O,I}, - {I,I,I,I,I,I,I} -}; - -static uchar yPM[9][7][2] = { - {I,I,I,I,I,I,I}, - {I,I,I,O,I,I,I}, - {I,I,I,O,I,I,I}, - {I,I,I,O,I,I,I}, - {I,I,I,O,I,I,I}, - {I,I,O,I,O,I,I}, - {I,O,I,I,I,O,I}, - {I,O,I,I,I,O,I}, - {I,I,I,I,I,I,I} -}; - -static uchar zPM[9][7][2] = { - {I,I,I,I,I,I,I}, - {I,O,O,O,O,O,I}, - {I,O,I,I,I,I,I}, - {I,I,O,I,I,I,I}, - {I,I,I,O,I,I,I}, - {I,I,I,I,O,I,I}, - {I,I,I,I,I,O,I}, - {I,O,O,O,O,O,I}, - {I,I,I,I,I,I,I} -}; - -#undef O -#undef I - void View3DInventorViewer::drawAxisCross(void) { // FIXME: convert this to a superimposition scenegraph instead of @@ -3467,17 +3424,15 @@ void View3DInventorViewer::drawAxisCross(void) else glColor3fv(SbVec3f(0.0f, 0.0f, 0.0f).getValue()); - //glEnable(GL_ALPHA_TEST); - //glAlphaFunc(GL_GREATER, 0.5); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glPixelZoom((float)axiscrossSize/10, (float)axiscrossSize/10); + glPixelZoom((float)axiscrossSize/30, (float)axiscrossSize/30); // 30 = 3 (character pixmap ratio) * 10 (default axiscrossSize) glRasterPos2d(xpos[0], xpos[1]); - glDrawPixels(7, 9, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, xPM); + glDrawPixels(XPM_WIDTH, XPM_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, XPM_PIXEL_DATA); glRasterPos2d(ypos[0], ypos[1]); - glDrawPixels(7, 9, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, yPM); + glDrawPixels(YPM_WIDTH, YPM_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, YPM_PIXEL_DATA); glRasterPos2d(zpos[0], zpos[1]); - glDrawPixels(7, 9, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, zPM); + glDrawPixels(ZPM_WIDTH, ZPM_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, ZPM_PIXEL_DATA); glPixelStorei(GL_UNPACK_ALIGNMENT, unpack); glPopMatrix(); From 9d82286bc8fe285bc8b7207c62879cb9fa6715df Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Wed, 17 Nov 2021 17:07:57 +0100 Subject: [PATCH 051/133] [Gui] Render corner cross lines with thin polygons so it can be scaled --- src/Gui/View3DInventorViewer.cpp | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index 08c9500dd1..7befb531d8 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -3451,11 +3451,33 @@ void View3DInventorViewer::drawAxisCross(void) // Draw an arrow for the axis representation directly through OpenGL. void View3DInventorViewer::drawArrow(void) { - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3f(1.0f, 0.0f, 0.0f); - glEnd(); glDisable(GL_CULL_FACE); + glBegin(GL_QUADS); + glVertex3f(0.0f, -0.02f, 0.02f); + glVertex3f(0.0f, 0.02f, 0.02f); + glVertex3f(1.0f - 1.0f / 3.0f, 0.02f, 0.02f); + glVertex3f(1.0f - 1.0f / 3.0f, -0.02f, 0.02f); + + glVertex3f(0.0f, -0.02f, -0.02f); + glVertex3f(0.0f, 0.02f, -0.02f); + glVertex3f(1.0f - 1.0f / 3.0f, 0.02f, -0.02f); + glVertex3f(1.0f - 1.0f / 3.0f, -0.02f, -0.02f); + + glVertex3f(0.0f, -0.02f, 0.02f); + glVertex3f(0.0f, -0.02f, -0.02f); + glVertex3f(1.0f - 1.0f / 3.0f, -0.02f, -0.02f); + glVertex3f(1.0f - 1.0f / 3.0f, -0.02f, 0.02f); + + glVertex3f(0.0f, 0.02f, 0.02f); + glVertex3f(0.0f, 0.02f, -0.02f); + glVertex3f(1.0f - 1.0f / 3.0f, 0.02f, -0.02f); + glVertex3f(1.0f - 1.0f / 3.0f, 0.02f, 0.02f); + + glVertex3f(0.0f, 0.02f, 0.02f); + glVertex3f(0.0f, 0.02f, -0.02f); + glVertex3f(0.0f, -0.02f, -0.02f); + glVertex3f(0.0f, -0.02f, 0.02f); + glEnd(); glBegin(GL_TRIANGLES); glVertex3f(1.0f, 0.0f, 0.0f); glVertex3f(1.0f - 1.0f / 3.0f, +0.5f / 4.0f, 0.0f); From 34ef43811cc8248c69be63a58f34ca9fd220d438 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Wed, 17 Nov 2021 18:04:12 +0100 Subject: [PATCH 052/133] [Gui] Add corner cross size as a preference in Display/3D View/General --- src/Gui/DlgSettings3DView.ui | 97 ++++++++++++++++++++++++++------ src/Gui/DlgSettings3DViewImp.cpp | 2 + src/Gui/SplitView3DInventor.cpp | 5 ++ src/Gui/View3DInventor.cpp | 4 ++ 4 files changed, 91 insertions(+), 17 deletions(-) diff --git a/src/Gui/DlgSettings3DView.ui b/src/Gui/DlgSettings3DView.ui index c4191841d9..6dadb4bf13 100644 --- a/src/Gui/DlgSettings3DView.ui +++ b/src/Gui/DlgSettings3DView.ui @@ -24,24 +24,76 @@ - - - Main coordinate system will always be shown in + + + + + Main coordinate system will always be shown in lower right corner within opened files - - - Show coordinate system in the corner - - - true - - - CornerCoordSystem - - - View - - + + + Show coordinate system in the corner + + + true + + + CornerCoordSystem + + + View + + + + + + + Qt::Horizontal + + + + 40 + + + + + + + + Relative size : + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Size of main coordinate system representation +in the corner -- in % of height/width of viewport + + + 2 + + + 100 + + + 10 + + + % + + + CornerCoordSystemSize + + + View + + + + @@ -626,6 +678,11 @@ bounding box size of the 3D object that is currently displayed. QDoubleSpinBox
Gui/PrefWidgets.h
+ + Gui::PrefSpinBox + QSpinBox +
Gui/PrefWidgets.h
+
@@ -677,5 +734,11 @@ bounding box size of the 3D object that is currently displayed. + + CheckBox_CornerCoordSystem + toggled(bool) + SpinBox_CornerCoordSystemSize + setEnabled(bool) + diff --git a/src/Gui/DlgSettings3DViewImp.cpp b/src/Gui/DlgSettings3DViewImp.cpp index b1fe1d71aa..5459ff4c91 100644 --- a/src/Gui/DlgSettings3DViewImp.cpp +++ b/src/Gui/DlgSettings3DViewImp.cpp @@ -89,6 +89,7 @@ void DlgSettings3DViewImp::saveSettings() hGrp->SetInt("MarkerSize", vBoxMarkerSize.toInt()); ui->CheckBox_CornerCoordSystem->onSave(); + ui->SpinBox_CornerCoordSystemSize->onSave(); ui->CheckBox_ShowAxisCross->onSave(); ui->CheckBox_WbByTab->onSave(); ui->CheckBox_ShowFPS->onSave(); @@ -106,6 +107,7 @@ void DlgSettings3DViewImp::saveSettings() void DlgSettings3DViewImp::loadSettings() { ui->CheckBox_CornerCoordSystem->onRestore(); + ui->SpinBox_CornerCoordSystemSize->onRestore(); ui->CheckBox_ShowAxisCross->onRestore(); ui->CheckBox_WbByTab->onRestore(); ui->CheckBox_ShowFPS->onRestore(); diff --git a/src/Gui/SplitView3DInventor.cpp b/src/Gui/SplitView3DInventor.cpp index 78a7102da5..654542dc85 100644 --- a/src/Gui/SplitView3DInventor.cpp +++ b/src/Gui/SplitView3DInventor.cpp @@ -98,6 +98,7 @@ void AbstractSplitView::setupSettings() // apply the user settings OnChange(*hGrp,"EyeDistance"); OnChange(*hGrp,"CornerCoordSystem"); + OnChange(*hGrp,"CornerCoordSystemSize"); OnChange(*hGrp,"UseAutoRotation"); OnChange(*hGrp,"Gradient"); OnChange(*hGrp,"BackgroundColor"); @@ -248,6 +249,10 @@ void AbstractSplitView::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) (*it)->setFeedbackVisibility(rGrp.GetBool("CornerCoordSystem",true)); } + else if (strcmp(Reason,"CornerCoordSystemSize") == 0) { + for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) + (*it)->setFeedbackSize(rGrp.GetInt("CornerCoordSystemSize",10)); + } else if (strcmp(Reason,"UseAutoRotation") == 0) { for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) (*it)->setAnimationEnabled(rGrp.GetBool("UseAutoRotation",false)); diff --git a/src/Gui/View3DInventor.cpp b/src/Gui/View3DInventor.cpp index c03281cfab..ab8e284b10 100644 --- a/src/Gui/View3DInventor.cpp +++ b/src/Gui/View3DInventor.cpp @@ -162,6 +162,7 @@ View3DInventor::View3DInventor(Gui::Document* pcDocument, QWidget* parent, // apply the user settings OnChange(*hGrp,"EyeDistance"); OnChange(*hGrp,"CornerCoordSystem"); + OnChange(*hGrp,"CornerCoordSystemSize"); OnChange(*hGrp,"ShowAxisCross"); OnChange(*hGrp,"UseAutoRotation"); OnChange(*hGrp,"Gradient"); @@ -378,6 +379,9 @@ void View3DInventor::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::M else if (strcmp(Reason,"CornerCoordSystem") == 0) { _viewer->setFeedbackVisibility(rGrp.GetBool("CornerCoordSystem",true)); } + else if (strcmp(Reason,"CornerCoordSystemSize") == 0) { + _viewer->setFeedbackSize(rGrp.GetInt("CornerCoordSystemSize",10)); + } else if (strcmp(Reason,"ShowAxisCross") == 0) { _viewer->setAxisCross(rGrp.GetBool("ShowAxisCross",false)); } From 81f4bcce66e2d2fda09a13b95699ab3186f84b0f Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 23 Nov 2021 00:33:12 +0100 Subject: [PATCH 053/133] Gui: [skip ci] fix -Wmultichar --- src/Gui/Document.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 04ac6abeff..9fbfed5dee 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -1088,13 +1088,13 @@ static bool checkCanonicalPath(const std::map &docs) << QObject::tr("Physical path:") << ' ' << v.first << "\n" << QObject::tr("Document:") << ' ' << docName(doc) - << "\n" << ' ' + << "\n " << QObject::tr("Path:") << ' ' << QString::fromUtf8(doc->FileName.getValue()); for (auto d : v.second) { if (d == doc) continue; ts << "\n" << QObject::tr("Document:") << ' ' << docName(d) - << "\n" << ' ' + << "\n " << QObject::tr("Path:") << ' ' << QString::fromUtf8(d->FileName.getValue()); } } From 4c72df348044a5b0cc329cb01a57e343dc82e214 Mon Sep 17 00:00:00 2001 From: Uwe Date: Tue, 23 Nov 2021 02:48:25 +0100 Subject: [PATCH 054/133] [PD] fix pad/pocket UI issues - update the preview when the direction is changed in the dialog - don't uncheck the direction viewbox without any reason - only recompute once - update the direction information on reversion - only pocket: add missing code we have in pad (proper code merging will follow the next days) --- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 35 ++++++++++-------- src/Mod/PartDesign/Gui/TaskPadParameters.h | 2 +- .../PartDesign/Gui/TaskPocketParameters.cpp | 37 ++++++++++++------- src/Mod/PartDesign/Gui/TaskPocketParameters.h | 2 +- 4 files changed, 45 insertions(+), 31 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index b7615e2b1f..1d6cbf128d 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -474,13 +474,6 @@ void TaskPadParameters::onDirectionCBChanged(int num) // in case the user is in selection mode, but changed his mind before selecting anything exitSelectionMode(); - try { - recomputeFeature(); - } - catch (const Base::Exception& e) { - e.ReportException(); - } - // disable AlongSketchNormal when the direction is already normal if (num == 0) ui->checkBoxAlongDirection->setEnabled(false); @@ -492,7 +485,6 @@ void TaskPadParameters::onDirectionCBChanged(int num) pcPad->UseCustomVector.setValue(true); } else { - ui->checkBoxDirection->setChecked(false); pcPad->UseCustomVector.setValue(false); } // if we dont use custom direction, only allow to show its direction @@ -507,7 +499,13 @@ void TaskPadParameters::onDirectionCBChanged(int num) ui->ZDirectionEdit->setEnabled(true); } // recompute and update the direction - recomputeFeature(); + pcPad->ReferenceAxis.setValue(lnk.getValue(), lnk.getSubValues()); + try { + recomputeFeature(); + } + catch (const Base::Exception& e) { + e.ReportException(); + } updateDirectionEdits(); } @@ -531,7 +529,7 @@ void TaskPadParameters::onXDirectionEditChanged(double len) PartDesign::Pad* pcPad = static_cast(vp->getObject()); pcPad->Direction.setValue(len, pcPad->Direction.getValue().y, pcPad->Direction.getValue().z); recomputeFeature(); - // checking for case of a null vector is done in FeaturePad.cpp + // checking for case of a null vector is done in FeatureExtrude.cpp // if there was a null vector, the normal vector of the sketch is used. // therefore the vector component edits must be updated updateDirectionEdits(); @@ -553,16 +551,23 @@ void TaskPadParameters::onZDirectionEditChanged(double len) updateDirectionEdits(); } -void TaskPadParameters::updateDirectionEdits(void) +void TaskPadParameters::updateDirectionEdits(bool Reversed) { PartDesign::Pad* pcPad = static_cast(vp->getObject()); // we don't want to execute the onChanged edits, but just update their contents ui->XDirectionEdit->blockSignals(true); ui->YDirectionEdit->blockSignals(true); ui->ZDirectionEdit->blockSignals(true); - ui->XDirectionEdit->setValue(pcPad->Direction.getValue().x); - ui->YDirectionEdit->setValue(pcPad->Direction.getValue().y); - ui->ZDirectionEdit->setValue(pcPad->Direction.getValue().z); + if (Reversed) { + ui->XDirectionEdit->setValue(-1 * pcPad->Direction.getValue().x); + ui->YDirectionEdit->setValue(-1 * pcPad->Direction.getValue().y); + ui->ZDirectionEdit->setValue(-1 * pcPad->Direction.getValue().z); + } + else { + ui->XDirectionEdit->setValue(pcPad->Direction.getValue().x); + ui->YDirectionEdit->setValue(pcPad->Direction.getValue().y); + ui->ZDirectionEdit->setValue(pcPad->Direction.getValue().z); + } ui->XDirectionEdit->blockSignals(false); ui->YDirectionEdit->blockSignals(false); ui->ZDirectionEdit->blockSignals(false); @@ -592,7 +597,7 @@ void TaskPadParameters::onReversedChanged(bool on) ui->checkBoxMidplane->setEnabled(!on); recomputeFeature(); // update the direction - updateDirectionEdits(); + updateDirectionEdits(on); } void TaskPadParameters::onModeChanged(int index) diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.h b/src/Mod/PartDesign/Gui/TaskPadParameters.h index 174fe43fad..54f6ca1d77 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.h @@ -96,7 +96,7 @@ private: QString getFaceName(void) const; void onSelectionChanged(const Gui::SelectionChanges& msg) override; void updateUI(int index); - void updateDirectionEdits(void); + void updateDirectionEdits(bool Reversed = false); private: QWidget* proxy; diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 016d4c9aa2..d7df987fac 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -478,13 +478,6 @@ void TaskPocketParameters::onDirectionCBChanged(int num) // in case the user is in selection mode, but changed his mind before selecting anything exitSelectionMode(); - try { - recomputeFeature(); - } - catch (const Base::Exception& e) { - e.ReportException(); - } - // disable AlongSketchNormal when the direction is already normal if (num == 0) ui->checkBoxAlongDirection->setEnabled(false); @@ -497,7 +490,6 @@ void TaskPocketParameters::onDirectionCBChanged(int num) pcPocket->UseCustomVector.setValue(true); } else { - ui->checkBoxDirection->setChecked(false); pcPocket->UseCustomVector.setValue(false); } // if we dont use custom direction, only allow to show its direction @@ -512,7 +504,13 @@ void TaskPocketParameters::onDirectionCBChanged(int num) ui->ZDirectionEdit->setEnabled(true); } // recompute and update the direction - recomputeFeature(); + pcPocket->ReferenceAxis.setValue(lnk.getValue(), lnk.getSubValues()); + try { + recomputeFeature(); + } + catch (const Base::Exception& e) { + e.ReportException(); + } updateDirectionEdits(); } @@ -536,7 +534,7 @@ void TaskPocketParameters::onXDirectionEditChanged(double len) PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); pcPocket->Direction.setValue(len, pcPocket->Direction.getValue().y, pcPocket->Direction.getValue().z); recomputeFeature(); - // checking for case of a null vector is done in FeaturePocket.cpp + // checking for case of a null vector is done in FeatureExtrude.cpp // if there was a null vector, the normal vector of the sketch is used. // therefore the vector component edits must be updated updateDirectionEdits(); @@ -558,16 +556,23 @@ void TaskPocketParameters::onZDirectionEditChanged(double len) updateDirectionEdits(); } -void TaskPocketParameters::updateDirectionEdits(void) +void TaskPocketParameters::updateDirectionEdits(bool Reversed) { PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); // we don't want to execute the onChanged edits, but just update their contents ui->XDirectionEdit->blockSignals(true); ui->YDirectionEdit->blockSignals(true); ui->ZDirectionEdit->blockSignals(true); - ui->XDirectionEdit->setValue(pcPocket->Direction.getValue().x); - ui->YDirectionEdit->setValue(pcPocket->Direction.getValue().y); - ui->ZDirectionEdit->setValue(pcPocket->Direction.getValue().z); + if (Reversed) { + ui->XDirectionEdit->setValue(-1 * pcPocket->Direction.getValue().x); + ui->YDirectionEdit->setValue(-1 * pcPocket->Direction.getValue().y); + ui->ZDirectionEdit->setValue(-1 * pcPocket->Direction.getValue().z); + } + else { + ui->XDirectionEdit->setValue(pcPocket->Direction.getValue().x); + ui->YDirectionEdit->setValue(pcPocket->Direction.getValue().y); + ui->ZDirectionEdit->setValue(pcPocket->Direction.getValue().z); + } ui->XDirectionEdit->blockSignals(false); ui->YDirectionEdit->blockSignals(false); ui->ZDirectionEdit->blockSignals(false); @@ -585,7 +590,11 @@ void TaskPocketParameters::onReversedChanged(bool on) { PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); pcPocket->Reversed.setValue(on); + // midplane is not sensible when reversed + ui->checkBoxMidplane->setEnabled(!on); recomputeFeature(); + // update the direction + updateDirectionEdits(on); } void TaskPocketParameters::onModeChanged(int index) diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.h b/src/Mod/PartDesign/Gui/TaskPocketParameters.h index db6e8abdef..1b57c3061b 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.h @@ -97,7 +97,7 @@ private: void onSelectionChanged(const Gui::SelectionChanges& msg) override; void updateUI(int index); - void updateDirectionEdits(void); + void updateDirectionEdits(bool Reversed = false); private: QWidget* proxy; From 1da079b34bce86db7ca79f4c365c35eea25bef20 Mon Sep 17 00:00:00 2001 From: Uwe Date: Tue, 23 Nov 2021 04:22:37 +0100 Subject: [PATCH 055/133] [PD] better solution for reversed pad/pocket handling - let FeatureExtrude set the right direction - use the UI as once intended: custom vector values are always taken as they are, so reversing a custom direction will not lead to a negation of the custom vector in the UI. The logic is: "take the vector as it is, and when Reversed is on, negate it additionally" --- src/Mod/PartDesign/App/FeatureExtrude.cpp | 12 ++++++++++- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 20 +++++++------------ src/Mod/PartDesign/Gui/TaskPadParameters.h | 2 +- .../PartDesign/Gui/TaskPocketParameters.cpp | 19 ++++++------------ src/Mod/PartDesign/Gui/TaskPocketParameters.h | 2 +- 5 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp index 54a3599328..5561aeffc2 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.cpp +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -126,6 +126,16 @@ Base::Vector3d FeatureExtrude::computeDirection(const Base::Vector3d& sketchVect // explicitly set the Direction so that the dialog shows also the used direction // if the sketch's normal vector was used - Direction.setValue(extrudeDirection); + // for a custom vector we cannot negate it since the Ui takes always the currently + // shown vector values as final direction, + // and when Reversed, it will be negated additionally + if (!UseCustomVector.getValue()) { + if (Reversed.getValue()) + Direction.setValue(-extrudeDirection); + else + Direction.setValue(extrudeDirection); + } + // don't return the direction including reversed since this is handled in + // FeatureSketchBased.cpp afterwards return extrudeDirection; } diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 1d6cbf128d..03651459d5 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -551,23 +551,16 @@ void TaskPadParameters::onZDirectionEditChanged(double len) updateDirectionEdits(); } -void TaskPadParameters::updateDirectionEdits(bool Reversed) +void TaskPadParameters::updateDirectionEdits() { PartDesign::Pad* pcPad = static_cast(vp->getObject()); // we don't want to execute the onChanged edits, but just update their contents ui->XDirectionEdit->blockSignals(true); ui->YDirectionEdit->blockSignals(true); ui->ZDirectionEdit->blockSignals(true); - if (Reversed) { - ui->XDirectionEdit->setValue(-1 * pcPad->Direction.getValue().x); - ui->YDirectionEdit->setValue(-1 * pcPad->Direction.getValue().y); - ui->ZDirectionEdit->setValue(-1 * pcPad->Direction.getValue().z); - } - else { - ui->XDirectionEdit->setValue(pcPad->Direction.getValue().x); - ui->YDirectionEdit->setValue(pcPad->Direction.getValue().y); - ui->ZDirectionEdit->setValue(pcPad->Direction.getValue().z); - } + ui->XDirectionEdit->setValue(pcPad->Direction.getValue().x); + ui->YDirectionEdit->setValue(pcPad->Direction.getValue().y); + ui->ZDirectionEdit->setValue(pcPad->Direction.getValue().z); ui->XDirectionEdit->blockSignals(false); ui->YDirectionEdit->blockSignals(false); ui->ZDirectionEdit->blockSignals(false); @@ -595,9 +588,10 @@ void TaskPadParameters::onReversedChanged(bool on) pcPad->Reversed.setValue(on); // midplane is not sensible when reversed ui->checkBoxMidplane->setEnabled(!on); - recomputeFeature(); // update the direction - updateDirectionEdits(on); + recomputeFeature(); + updateDirectionEdits(); + } void TaskPadParameters::onModeChanged(int index) diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.h b/src/Mod/PartDesign/Gui/TaskPadParameters.h index 54f6ca1d77..174fe43fad 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.h @@ -96,7 +96,7 @@ private: QString getFaceName(void) const; void onSelectionChanged(const Gui::SelectionChanges& msg) override; void updateUI(int index); - void updateDirectionEdits(bool Reversed = false); + void updateDirectionEdits(void); private: QWidget* proxy; diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index d7df987fac..c41d0d9a0c 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -556,23 +556,16 @@ void TaskPocketParameters::onZDirectionEditChanged(double len) updateDirectionEdits(); } -void TaskPocketParameters::updateDirectionEdits(bool Reversed) +void TaskPocketParameters::updateDirectionEdits() { PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); // we don't want to execute the onChanged edits, but just update their contents ui->XDirectionEdit->blockSignals(true); ui->YDirectionEdit->blockSignals(true); ui->ZDirectionEdit->blockSignals(true); - if (Reversed) { - ui->XDirectionEdit->setValue(-1 * pcPocket->Direction.getValue().x); - ui->YDirectionEdit->setValue(-1 * pcPocket->Direction.getValue().y); - ui->ZDirectionEdit->setValue(-1 * pcPocket->Direction.getValue().z); - } - else { - ui->XDirectionEdit->setValue(pcPocket->Direction.getValue().x); - ui->YDirectionEdit->setValue(pcPocket->Direction.getValue().y); - ui->ZDirectionEdit->setValue(pcPocket->Direction.getValue().z); - } + ui->XDirectionEdit->setValue(pcPocket->Direction.getValue().x); + ui->YDirectionEdit->setValue(pcPocket->Direction.getValue().y); + ui->ZDirectionEdit->setValue(pcPocket->Direction.getValue().z); ui->XDirectionEdit->blockSignals(false); ui->YDirectionEdit->blockSignals(false); ui->ZDirectionEdit->blockSignals(false); @@ -592,9 +585,9 @@ void TaskPocketParameters::onReversedChanged(bool on) pcPocket->Reversed.setValue(on); // midplane is not sensible when reversed ui->checkBoxMidplane->setEnabled(!on); - recomputeFeature(); // update the direction - updateDirectionEdits(on); + recomputeFeature(); + updateDirectionEdits(); } void TaskPocketParameters::onModeChanged(int index) diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.h b/src/Mod/PartDesign/Gui/TaskPocketParameters.h index 1b57c3061b..db6e8abdef 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.h @@ -97,7 +97,7 @@ private: void onSelectionChanged(const Gui::SelectionChanges& msg) override; void updateUI(int index); - void updateDirectionEdits(bool Reversed = false); + void updateDirectionEdits(void); private: QWidget* proxy; From 7f50605c61e614f0eb71ad8cc12ff30358f34244 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 23 Nov 2021 12:55:49 +0100 Subject: [PATCH 056/133] App: save version number of the most important libraries --- src/App/Application.cpp | 14 ++++++++++++++ src/Gui/Application.cpp | 3 +++ 2 files changed, 17 insertions(+) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 281b56946e..4e8b043821 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -138,6 +138,7 @@ #include #include #include +#include using namespace App; using namespace std; @@ -2525,6 +2526,19 @@ void Application::initConfig(int argc, char ** argv) // capture path SaveEnv("PATH"); + + // Save version numbers of the libraries +#ifdef OCC_VERSION_STRING_EXT + mConfig["OCC_VERSION"] = OCC_VERSION_STRING_EXT; +#endif + mConfig["BOOST_VERSION"] = BOOST_LIB_VERSION; + mConfig["PYTHON_VERSION"] = PY_VERSION; + mConfig["QT_VERSION"] = QT_VERSION_STR; + mConfig["EIGEN_VERSION"] = FC_EIGEN3_VERSION; + mConfig["PYSIDE_VERSION"] = FC_PYSIDE_VERSION; + mConfig["XERCESC_VERSION"] = FC_XERCESC_VERSION; + + logStatus(); } diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index ca1b8d7967..3697a2eb5a 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -139,6 +139,7 @@ #include #include "View3DViewerPy.h" #include +#include using namespace Gui; @@ -452,6 +453,8 @@ Application::Application(bool GUIenabled) Py_DECREF(descr); } + App::Application::Config()["COIN_VERSION"] = COIN_VERSION; + // Python console binding PythonDebugModule ::init_module(); PythonStdout ::init_type(); From 57ce37d86702674418df35ac9c6d3ae72fbd8a46 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 23 Nov 2021 20:13:02 +0100 Subject: [PATCH 057/133] App: add CMAKE_BINARY_DIR to search paths --- src/App/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/App/CMakeLists.txt b/src/App/CMakeLists.txt index be1699a541..cf28254422 100644 --- a/src/App/CMakeLists.txt +++ b/src/App/CMakeLists.txt @@ -48,6 +48,7 @@ fc_copy_file_if_different( # ----------------------------------------------------------------------------- include_directories( + ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}/src ${CMAKE_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR} From 263f2e91da962de890ddd4a08f6e321ab7f22f53 Mon Sep 17 00:00:00 2001 From: carlopav Date: Sun, 26 Sep 2021 22:34:32 +0200 Subject: [PATCH 058/133] Part: Auto-add primitives to active Part Modified DlgPrimitives.cpp to allow auto adding the newly created object to active Std_Part. Works with: box, cylinder, sphere, cone, torus, tube, primitives. --- src/Mod/Part/BasicShapes/CommandShapes.py | 3 +++ src/Mod/Part/Gui/CommandParametric.cpp | 25 +++++++++++++++++++++++ src/Mod/Part/Gui/DlgPrimitives.cpp | 16 +++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/src/Mod/Part/BasicShapes/CommandShapes.py b/src/Mod/Part/BasicShapes/CommandShapes.py index 1b2601f2f5..6b5639e244 100644 --- a/src/Mod/Part/BasicShapes/CommandShapes.py +++ b/src/Mod/Part/BasicShapes/CommandShapes.py @@ -53,6 +53,9 @@ class CommandTube: tube = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Tube") Shapes.TubeFeature(tube) vp = ViewProviderShapes.ViewProviderTube(tube.ViewObject) + activePart = FreeCADGui.activeView().getActiveObject('part') + if activePart: + activePart.addObject(tube) FreeCAD.ActiveDocument.recompute() vp.startDefaultEditMode(tube.ViewObject) diff --git a/src/Mod/Part/Gui/CommandParametric.cpp b/src/Mod/Part/Gui/CommandParametric.cpp index 7cb297458b..9196add7ae 100644 --- a/src/Mod/Part/Gui/CommandParametric.cpp +++ b/src/Mod/Part/Gui/CommandParametric.cpp @@ -30,9 +30,29 @@ # include #endif +#include #include #include #include +#include + +//=========================================================================== +// Utils +//=========================================================================== +namespace { +QString getAutoGroupCommandStr() +// Helper function to get the python code to add the newly created object to the active Part object if present +{ + App::Part* activePart = Gui::Application::Instance->activeView()->getActiveObject("part"); + if (activePart) { + QString activePartName = QString::fromLatin1(activePart->getNameInDocument()); + return QString::fromLatin1("App.ActiveDocument.getObject('%1\')." + "addObject(App.ActiveDocument.ActiveObject)\n") + .arg(activePartName); + } + return QString::fromLatin1("# Object created at document root."); +} +} //=========================================================================== // Part_Cylinder @@ -62,6 +82,7 @@ void CmdPartCylinder::activated(int iMsg) cmd = QString::fromLatin1("App.ActiveDocument.ActiveObject.Label = \"%1\"") .arg(qApp->translate("CmdPartCylinder","Cylinder")); runCommand(Doc,cmd.toUtf8()); + runCommand(Doc, getAutoGroupCommandStr().toUtf8()); commitCommand(); updateActive(); runCommand(Gui, "Gui.SendMsgToActiveView(\"ViewFit\")"); @@ -103,6 +124,7 @@ void CmdPartBox::activated(int iMsg) cmd = QString::fromLatin1("App.ActiveDocument.ActiveObject.Label = \"%1\"") .arg(qApp->translate("CmdPartBox","Cube")); runCommand(Doc,cmd.toUtf8()); + runCommand(Doc, getAutoGroupCommandStr().toUtf8()); commitCommand(); updateActive(); runCommand(Gui, "Gui.SendMsgToActiveView(\"ViewFit\")"); @@ -144,6 +166,7 @@ void CmdPartSphere::activated(int iMsg) cmd = QString::fromLatin1("App.ActiveDocument.ActiveObject.Label = \"%1\"") .arg(qApp->translate("CmdPartSphere","Sphere")); runCommand(Doc,cmd.toUtf8()); + runCommand(Doc, getAutoGroupCommandStr().toUtf8()); commitCommand(); updateActive(); runCommand(Gui, "Gui.SendMsgToActiveView(\"ViewFit\")"); @@ -185,6 +208,7 @@ void CmdPartCone::activated(int iMsg) cmd = QString::fromLatin1("App.ActiveDocument.ActiveObject.Label = \"%1\"") .arg(qApp->translate("CmdPartCone","Cone")); runCommand(Doc,cmd.toUtf8()); + runCommand(Doc, getAutoGroupCommandStr().toUtf8()); commitCommand(); updateActive(); runCommand(Gui, "Gui.SendMsgToActiveView(\"ViewFit\")"); @@ -226,6 +250,7 @@ void CmdPartTorus::activated(int iMsg) cmd = QString::fromLatin1("App.ActiveDocument.ActiveObject.Label = \"%1\"") .arg(qApp->translate("CmdPartTorus","Torus")); runCommand(Doc,cmd.toUtf8()); + runCommand(Doc, getAutoGroupCommandStr().toUtf8()); commitCommand(); updateActive(); runCommand(Gui, "Gui.SendMsgToActiveView(\"ViewFit\")"); diff --git a/src/Mod/Part/Gui/DlgPrimitives.cpp b/src/Mod/Part/Gui/DlgPrimitives.cpp index 3e428146ad..ee3193748b 100644 --- a/src/Mod/Part/Gui/DlgPrimitives.cpp +++ b/src/Mod/Part/Gui/DlgPrimitives.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +65,20 @@ using namespace PartGui; namespace PartGui { + QString getAutoGroupCommandStr(QString objectName) + // Helper function to get the python code to add the newly created object to the active Part object if present + { + App::Part* activePart = Gui::Application::Instance->activeView()->getActiveObject("part"); + if (activePart) { + QString activeObjectName = QString::fromLatin1(activePart->getNameInDocument()); + return QString::fromLatin1("App.ActiveDocument.getObject('%1\')." + "addObject(App.ActiveDocument.getObject('%2\'))\n") + .arg(activeObjectName) + .arg(objectName); + } + return QString::fromLatin1("# Object %1 created at document root").arg(objectName); + } + const char* gce_ErrorStatusText(gce_ErrorType et) { switch (et) @@ -1107,6 +1122,7 @@ void DlgPrimitives::createPrimitive(const QString& placement) QString prim = tr("Create %1").arg(ui->PrimitiveTypeCB->currentText()); Gui::Application::Instance->activeDocument()->openCommand(prim.toUtf8()); Gui::Command::runCommand(Gui::Command::Doc, cmd.toUtf8()); + Gui::Command::runCommand(Gui::Command::Doc, getAutoGroupCommandStr(name).toUtf8()); Gui::Application::Instance->activeDocument()->commitCommand(); Gui::Command::runCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()"); Gui::Command::runCommand(Gui::Command::Gui, "Gui.SendMsgToActiveView(\"ViewFit\")"); From ad408a0989e90c9a1bc19337b29a8b4ec0f6c611 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Thu, 18 Nov 2021 14:54:56 +0100 Subject: [PATCH 059/133] [Sketcher] Change diameter symbol used in presentation string, fixes #4779 Standard symbol \u2300 currently used generates text misalignment/cutout on some environments Replaced with \uD8 (capital O with stroke) that solves the issue -- and looks better --- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index e22254d2af..1ec7513d1e 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -3239,10 +3239,10 @@ QString ViewProviderSketch::getPresentationString(const Constraint *constraint) } if (constraint->Type == Sketcher::Diameter){ - valueStr.insert(0, QChar(8960)); // Diameter sign + valueStr.prepend(QChar(216)); // Diameter sign } else if (constraint->Type == Sketcher::Radius){ - valueStr.insert(0, QChar(82)); // Capital letter R + valueStr.prepend(QChar(82)); // Capital letter R } /** From c9a74d40d200bf6114f64e83fe9caa2fcf33e303 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Wed, 24 Nov 2021 09:03:35 -0600 Subject: [PATCH 060/133] Revert "Merge pull request #4626 from pavltom/GUI_TreeView_Item_Ordering" This reverts commit c62239d0ba0f6fc0d1c701578b6ae1fe7259d4a0, reversing changes made to bef1df4d404125dc4d8996dc57bd0183984100c4. See forums discussion: https://forum.freecadweb.org/viewtopic.php?p=549120 --- src/Gui/CommandView.cpp | 115 ------- src/Gui/Document.cpp | 30 +- src/Gui/Tree.cpp | 378 +-------------------- src/Gui/Tree.h | 23 +- src/Gui/ViewProviderDocumentObject.cpp | 24 -- src/Gui/ViewProviderDocumentObject.h | 7 - src/Gui/ViewProviderExtension.h | 2 - src/Gui/ViewProviderOrigin.h | 2 - src/Gui/ViewProviderOriginGroupExtension.h | 2 - src/Mod/Part/Gui/ViewProviderBoolean.h | 3 - src/Mod/Part/Gui/ViewProviderMirror.h | 6 - src/Mod/PartDesign/Gui/ViewProviderLoft.h | 4 +- src/Mod/PartDesign/Gui/ViewProviderPipe.h | 4 +- src/Mod/Test/CMakeLists.txt | 1 - src/Mod/Test/InitGui.py | 3 +- src/Mod/Test/TreeView.py | 244 ------------- 16 files changed, 22 insertions(+), 826 deletions(-) delete mode 100644 src/Mod/Test/TreeView.py diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index b6b858bc82..8b725210fb 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -3684,116 +3684,6 @@ void StdTreeDrag::activated(int) } } -//=========================================================================== -// Std_GroupMoveUp -//=========================================================================== -DEF_STD_CMD_A(StdGroupMoveUp) - -StdGroupMoveUp::StdGroupMoveUp() - : Command("Std_GroupMoveUp") -{ - sGroup = QT_TR_NOOP("TreeView"); - sMenuText = QT_TR_NOOP("Move up in group"); - sToolTipText = QT_TR_NOOP("Move object one place higher in its group"); - sStatusTip = sToolTipText; - sWhatsThis = "Std_GroupMoveUp"; - sPixmap = "button_up"; - sAccel = "Alt+Up"; - eType = 0; -} - -void StdGroupMoveUp::activated(int iMsg) -{ - Q_UNUSED(iMsg); - - TreeWidget *tree = TreeWidget::instance(); - if (!tree) { - return; - } - - std::vector selected; - if (!tree->getSelectedSiblingObjectItems(selected)) { - return; - } - - DocumentObjectItem *previous; - if (!tree->allowMoveUpInGroup(selected, &previous)) { - return; - } - - TreeWidget::moveSiblings(selected, previous, -1); -} - -bool StdGroupMoveUp::isActive(void) -{ - TreeWidget *tree = TreeWidget::instance(); - if (!tree) { - return false; - } - - std::vector selected; - if (!tree->getSelectedSiblingObjectItems(selected)) { - return false; - } - - return tree->allowMoveUpInGroup(selected); -} - -//=========================================================================== -// Std_GroupMoveDown -//=========================================================================== -DEF_STD_CMD_A(StdGroupMoveDown) - -StdGroupMoveDown::StdGroupMoveDown() - : Command("Std_GroupMoveDown") -{ - sGroup = QT_TR_NOOP("TreeView"); - sMenuText = QT_TR_NOOP("Move down in group"); - sToolTipText = QT_TR_NOOP("Move object one place lower in its group"); - sStatusTip = sToolTipText; - sWhatsThis = "Std_GroupMoveDown"; - sPixmap = "button_down"; - sAccel = "Alt+Down"; - eType = 0; -} - -void StdGroupMoveDown::activated(int iMsg) -{ - Q_UNUSED(iMsg); - - TreeWidget *tree = TreeWidget::instance(); - if (!tree) { - return; - } - - std::vector selected; - if (!tree->getSelectedSiblingObjectItems(selected)) { - return; - } - - DocumentObjectItem *next ; - if (!tree->allowMoveDownInGroup(selected, &next)) { - return; - } - - TreeWidget::moveSiblings(selected, next, +1); -} - -bool StdGroupMoveDown::isActive(void) -{ - TreeWidget *tree = TreeWidget::instance(); - if (!tree) { - return false; - } - - std::vector selected; - if (!tree->getSelectedSiblingObjectItems(selected)) { - return false; - } - - return tree->allowMoveDownInGroup(selected); -} - //====================================================================== // Std_TreeViewActions //=========================================================================== @@ -3828,11 +3718,6 @@ public: addCommand(new StdTreeDrag(),cmds.size()); addCommand(new StdTreeSelection(),cmds.size()); - - addCommand(); - - addCommand(new StdGroupMoveUp()); - addCommand(new StdGroupMoveDown()); }; virtual const char* className() const {return "StdCmdTreeViewActions";} }; diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 9fbfed5dee..6fa31a532e 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -727,9 +727,6 @@ void Document::slotNewObject(const App::DocumentObject& Obj) activeView->getViewer()->addViewProvider(pcProvider); } - // If no tree rank was assigned, do it now, otherwise keep the current one - pcProvider->TreeRank.setValue(pcProvider->TreeRank.getValue()); - // adding to the tree signalNewObject(*pcProvider); pcProvider->pcDocument = this; @@ -1438,29 +1435,13 @@ void Document::RestoreDocFile(Base::Reader &reader) expanded = true; } } - - int rank = 0; - if (localreader->hasAttribute("rank")) { - rank = localreader->getAttributeAsInteger("rank"); - } - ViewProvider* pObj = getViewProviderByName(name.c_str()); if (pObj) // check if this feature has been registered pObj->Restore(*localreader); - - ViewProviderDocumentObject *vpdo = dynamic_cast(pObj); - if (vpdo) { - if (rank <= 0 ) { - // For backward compatibility, use object ID as tree rank - rank = vpdo->getObject()->getID(); - } - vpdo->TreeRank.setValue(rank); - - if (expanded) { - this->signalExpandObject(*vpdo, TreeItemMode::ExpandItem, 0, 0); - } + if (pObj && expanded) { + Gui::ViewProviderDocumentObject* vp = static_cast(pObj); + this->signalExpandObject(*vp, TreeItemMode::ExpandItem,0,0); } - localreader->readEndElement("ViewProvider"); } localreader->readEndElement("ViewProviderData"); @@ -1580,11 +1561,6 @@ void Document::SaveDocFile (Base::Writer &writer) const if (obj->hasExtensions()) writer.Stream() << " Extensions=\"True\""; - ViewProviderDocumentObject *vpdo = dynamic_cast(obj); - if (vpdo && vpdo->TreeRank.getValue()) { - writer.Stream() << " rank=\"" << vpdo->TreeRank.getValue() << "\""; - } - writer.Stream() << ">" << std::endl; obj->Save(writer); writer.Stream() << writer.ind() << "" << std::endl; diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 53545268cb..6d400dbf66 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -340,18 +340,8 @@ public: } } } - - // Sort the child items by their tree rank - std::stable_sort(newChildren.begin(), newChildren.end(), - [this](App::DocumentObject *a, App::DocumentObject *b) { - ViewProviderDocumentObject *vpa = this->docItem->getViewProvider(a); - ViewProviderDocumentObject *vpb = this->docItem->getViewProvider(b); - return vpa->TreeRank.getValue() < vpb->TreeRank.getValue(); - }); - - // Mark updated in case the order of the children did change + // We still need to check the order of the children updated = updated || children!=newChildren; - children.swap(newChildren); childSet.swap(newSet); @@ -565,9 +555,6 @@ TreeWidget::TreeWidget(const char *name, QWidget* parent) this, SLOT(onItemSelectionChanged())); connect(this, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(onItemChanged(QTreeWidgetItem*, int))); - connect(MainWindow::getInstance(), SIGNAL(tabifiedDockWidgetActivated(QDockWidget *)), - this, SLOT(onTabifiedDockWidgetActivated(QDockWidget *))); - connect(this->preselectTimer, SIGNAL(timeout()), this, SLOT(onPreSelectTimer())); connect(this->selectTimer, SIGNAL(timeout()), @@ -1400,17 +1387,6 @@ void TreeWidget::keyPressEvent(QKeyEvent *event) return; } } - - if (event->modifiers() == Qt::AltModifier - && (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down)) { - // Consume the Alt+Up/Down keypresses. This is because if the "Move Up/Down in Group" - // key shortcut is inactive, they are interpreted as ordinary up/down single selection - // move, which results in confusing behavior on item group borders crossing - event->accept(); - return; - } - - QTreeWidget::keyPressEvent(event); } @@ -2361,10 +2337,6 @@ void TreeWidget::slotChangedViewObject(const Gui::ViewProvider& vp, const App::P ChangedObjects.emplace(vpd.getObject(),0); _updateStatus(); } - else if (&prop == &vpd.TreeRank) { - ReorderedObjects.insert(vpd.getObject()); - _updateStatus(); - } } } @@ -2526,47 +2498,6 @@ void TreeWidget::onUpdateStatus(void) } ChangedObjects.clear(); - // Sort parents of object items with adjusted order - std::set reorderParents; - for (auto &obj : ReorderedObjects) { - ViewProvider *vp = Application::Instance->getViewProvider(obj); - if (!vp || !vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) { - continue; - } - - auto docIt = DocumentMap.find(static_cast(vp)->getDocument()); - if (docIt == DocumentMap.end() || !docIt->second) { - continue; - } - - DocumentItem *docItem = docIt->second; - auto parentIt = docItem->_ParentMap.find(obj); - if (parentIt != docItem->_ParentMap.end() && parentIt->second.size() > 0) { - for (App::DocumentObject *parent : parentIt->second) { - auto dataIt = docItem->ObjectMap.find(parent); - if (dataIt == docItem->ObjectMap.end()) { - continue; - } - - for (DocumentObjectItem *parentItem : dataIt->second->items) { - reorderParents.insert(parentItem); - } - } - } - else { - reorderParents.insert(docItem); - } - } - ReorderedObjects.clear(); - - if (!reorderParents.empty()) { - for (QTreeWidgetItem *parentItem : reorderParents) { - sortObjectItems(parentItem, [](const DocumentObjectItem *a, const DocumentObjectItem *b) - { return a->object()->TreeRank.getValue() < b->object()->TreeRank.getValue(); }); - } - reorderParents.clear(); - } - FC_LOG("update item status"); TimingInit(); for (auto pos = DocumentMap.begin();pos!=DocumentMap.end();++pos) { @@ -2655,7 +2586,6 @@ void TreeWidget::onUpdateStatus(void) errItem = item; } } - if(errItem) scrollToItem(errItem); @@ -2690,27 +2620,6 @@ void TreeWidget::onItemEntered(QTreeWidgetItem * item) Selection().rmvPreselect(); } -void TreeWidget::onTabifiedDockWidgetActivated(QDockWidget *dockWidget) { - - QWidget *parent = this->parentWidget(); - while (parent) { - if (parent == dockWidget) { - this->setFocus(); - return; - } - - parent = parent->parentWidget(); - } -} - -void TreeWidget::focusInEvent(QFocusEvent *event) { - - _LastSelectedTreeWidget = this; - Application::Instance->updateActions(true); - - QTreeWidget::focusInEvent(event); -} - void TreeWidget::leaveEvent(QEvent *) { if(!updateBlocked && TreeParams::Instance()->PreSelection()) { preselectTimer->stop(); @@ -3057,209 +2966,6 @@ void TreeWidget::onSelectionChanged(const SelectionChanges& msg) } } -bool TreeWidget::getSelectedSiblingObjectItems(std::vector &items) const -{ - QList selected = this->selectedItems(); - if (selected.isEmpty()) { - return false; - } - - if (selected.first()->type() != TreeWidget::ObjectType) { - return false; - } - - QTreeWidgetItem *parentItem = selected.first()->parent(); - for (int i = 1; i < selected.size(); ++i) { - if (selected[i]->type() != TreeWidget::ObjectType || selected[i]->parent() != parentItem) { - return false; - } - } - - items.resize(items.size() + selected.size(), 0); - std::transform(selected.begin(), selected.end(), items.end() - selected.size(), - [](QTreeWidgetItem *i) { return static_cast(i); }); - std::sort(items.begin(), items.end(), - [parentItem](DocumentObjectItem *a, DocumentObjectItem *b) - { return parentItem->indexOfChild(a) < parentItem->indexOfChild(b); }); - - return true; -} - -bool TreeWidget::allowMoveUpInGroup(const std::vector &items, DocumentObjectItem **preceding) const -{ - if (!items.size()) { - return false; - } - - DocumentObjectItem *previous = items.front()->getPreviousSibling(); - if (!previous) { - return false; - } - - if (preceding) { - *preceding = previous; - } - - QTreeWidgetItem *parent = items.front()->parent(); - if (parent->type() == ObjectType) { - ViewProviderDocumentObject *docObj = static_cast(parent)->object(); - if (!docObj) { - return false; - } - - for (DocumentObjectItem *item : items) { - if (!docObj->allowTreeOrderSwap(item->object()->getObject(), previous->object()->getObject())) { - return false; - } - } - } - - return true; -} - -bool TreeWidget::allowMoveDownInGroup(const std::vector &items, DocumentObjectItem **succeeding) const -{ - if (!items.size()) { - return false; - } - - DocumentObjectItem *next = items.back()->getNextSibling(); - if (!next) { - return false; - } - - if (succeeding) { - *succeeding = next; - } - - QTreeWidgetItem *parent = items.back()->parent(); - if (parent->type() == ObjectType) { - ViewProviderDocumentObject *docObj = static_cast(parent)->object(); - if (!docObj) { - return false; - } - - for (DocumentObjectItem *item : items) { - if (!docObj->allowTreeOrderSwap(item->object()->getObject(), next->object()->getObject())) { - return false; - } - } - } - - return true; -} - -bool TreeWidget::moveSiblings(const std::vector &items, DocumentObjectItem *pivot, int direction) -{ - // Some sanity checks + make sure pivot is not within the items to be moved - if (!items.size() || !pivot || !direction || std::find(items.begin(), items.end(), pivot) != items.end()) { - return false; - } - - QTreeWidgetItem *parent = pivot->parent(); - if (!parent) { - return false; - } - - Gui::Document *doc = pivot->object()->getDocument(); - if (!doc) { - return false; - } - - int childCount = parent->childCount(); - std::vector groupItems(childCount, 0); - std::vector ranks(childCount); - - for (int i = 0; i < childCount; ++i) { - QTreeWidgetItem *treeItem = parent->child(i); - if (treeItem->type() != ObjectType) { - return false; - } - - groupItems[i] = static_cast(treeItem); - ranks[i] = static_cast(treeItem)->object()->TreeRank.getValue(); - } - - int insertIndex = parent->indexOfChild(pivot) + (direction > 0); - for (DocumentObjectItem *item : items) { - std::vector::iterator it = std::find(groupItems.begin(), groupItems.end(), item); - if (it == groupItems.end()) { - continue; - } - - int index = it - groupItems.begin(); - groupItems.erase(it); - - if (index < insertIndex) { - --insertIndex; - } - groupItems.insert(groupItems.begin() + insertIndex, item); - ++insertIndex; - } - - doc->openCommand(QT_TRANSLATE_NOOP("Command", direction > 0 ? "Move down in group" : "Move down in group")); - - int changes = 0; - for (int i = 0; i < childCount; ++i) { - App::PropertyInteger &rank = groupItems[i]->object()->TreeRank; - if (rank.getValue() != ranks[i]) { - rank.setValue(ranks[i]); - ++changes; - } - } - - return changes > 0; -} - -bool TreeWidget::sortObjectItems(QTreeWidgetItem *node, DocumentObjectItemComparator comparator) -{ - if (!node || !comparator || node->childCount() <= 0) { - return false; - } - - bool lock = blockConnection(true); - - std::vector sortedItems; - sortedItems.reserve(node->childCount()); - - for (int i = 0; i < node->childCount(); ++i) { - QTreeWidgetItem *treeItem = node->child(i); - if (treeItem->type() == TreeWidget::ObjectType) { - sortedItems.push_back(static_cast(treeItem)); - } - } - - std::stable_sort(sortedItems.begin(), sortedItems.end(), comparator); - - int sortedIndex = 0; - int swaps = 0; - for (int i = 0; i < node->childCount(); ++i) { - QTreeWidgetItem *treeItem = node->child(i); - if (treeItem->type() != TreeWidget::ObjectType) { - continue; - } - - DocumentObjectItem *sortedItem = sortedItems[sortedIndex++]; - if (sortedItem == treeItem) { - continue; - } - - std::vector expansion; - sortedItem->getExpandedSnapshot(expansion); - - node->removeChild(sortedItem); - node->insertChild(i, sortedItem); - ++swaps; - - std::vector::const_iterator expFrom = expansion.cbegin(); - sortedItem->applyExpandedSnapshot(expansion, expFrom); - } - - blockConnection(lock); - - return swaps > 0; -} - // ---------------------------------------------------------------------------- /* TRANSLATOR Gui::TreePanel */ @@ -3566,7 +3272,7 @@ bool DocumentItem::createNewItem(const Gui::ViewProviderDocumentObject& obj, parent = this; data->rootItem = item; if(index<0) - index = findRootIndex(&obj); + index = findRootIndex(obj.getObject()); } if(index<0) parent->addChild(item); @@ -3865,7 +3571,7 @@ void DocumentItem::populateItem(DocumentObjectItem *item, bool refresh, bool del DocumentObjectItem* childItem = static_cast(ci); if(childItem->requiredAtRoot()) { item->removeChild(childItem); - auto index = findRootIndex(childItem->object()); + auto index = findRootIndex(childItem->object()->getObject()); if(index>=0) this->insertChild(index,childItem); else @@ -3886,13 +3592,13 @@ void DocumentItem::populateItem(DocumentObjectItem *item, bool refresh, bool del getTree()->_updateStatus(); } -int DocumentItem::findRootIndex(const ViewProviderDocumentObject *childObj) const { - if (!TreeParams::Instance()->KeepRootOrder() || !childObj || !childObj->getObject() - || !childObj->getObject()->getNameInDocument()) { +int DocumentItem::findRootIndex(App::DocumentObject *childObj) { + if(!TreeParams::Instance()->KeepRootOrder() || !childObj || !childObj->getNameInDocument()) return -1; - } - // Use view provider's tree rank to find correct place at the root level. + // object id is monotonically increasing, so use this as a hint to insert + // object back so that we can have a stable order in root level. + int count = this->childCount(); if(!count) return -1; @@ -3903,10 +3609,9 @@ int DocumentItem::findRootIndex(const ViewProviderDocumentObject *childObj) cons for(last=count-1;last>=0;--last) { auto citem = this->child(last); if(citem->type() == TreeWidget::ObjectType) { - auto obj = static_cast(citem)->object(); - if (obj->TreeRank.getValue() <= childObj->TreeRank.getValue()) { - return last + 1; - } + auto obj = static_cast(citem)->object()->getObject(); + if(obj->getID()<=childObj->getID()) + return last+1; break; } } @@ -3915,10 +3620,9 @@ int DocumentItem::findRootIndex(const ViewProviderDocumentObject *childObj) cons for(first=0;firstchild(first); if(citem->type() == TreeWidget::ObjectType) { - auto obj = static_cast(citem)->object(); - if (obj->TreeRank.getValue() > childObj->TreeRank.getValue()) { + auto obj = static_cast(citem)->object()->getObject(); + if(obj->getID()>=childObj->getID()) return first; - } break; } } @@ -3934,8 +3638,8 @@ int DocumentItem::findRootIndex(const ViewProviderDocumentObject *childObj) cons auto citem = this->child(pos); if(citem->type() != TreeWidget::ObjectType) continue; - auto obj = static_cast(citem)->object(); - if (obj->TreeRank.getValue() < childObj->TreeRank.getValue()) { + auto obj = static_cast(citem)->object()->getObject(); + if(obj->getID()getID()) { first = ++pos; count -= step+1; } else @@ -5266,40 +4970,6 @@ DocumentObjectItem *DocumentObjectItem::getParentItem() const{ return static_cast(parent()); } -DocumentObjectItem *DocumentObjectItem::getNextSibling() const -{ - QTreeWidgetItem *parent = this->parent(); - if (parent) { - int index = parent->indexOfChild(const_cast(this)); - if (index >= 0) { - while (++index < parent->childCount()) { - QTreeWidgetItem *sibling = parent->child(index); - if (sibling->type() == TreeWidget::ObjectType) { - return static_cast(sibling); - } - } - } - } - - return 0; -} - -DocumentObjectItem *DocumentObjectItem::getPreviousSibling() const -{ - QTreeWidgetItem *parent = this->parent(); - if (parent) { - int index = parent->indexOfChild(const_cast(this)); - while (index > 0) { - QTreeWidgetItem *sibling = parent->child(--index); - if (sibling->type() == TreeWidget::ObjectType) { - return static_cast(sibling); - } - } - } - - return 0; -} - const char *DocumentObjectItem::getName() const { const char *name = object()->getObject()->getNameInDocument(); return name?name:""; @@ -5426,22 +5096,4 @@ TreeWidget *DocumentObjectItem::getTree() const{ return static_cast(treeWidget()); } -void DocumentObjectItem::getExpandedSnapshot(std::vector &snapshot) const -{ - snapshot.push_back(isExpanded()); - - for (int i = 0; i < childCount(); ++i) { - static_cast(child(i))->getExpandedSnapshot(snapshot); - } -} - -void DocumentObjectItem::applyExpandedSnapshot(const std::vector &snapshot, std::vector::const_iterator &from) -{ - setExpanded(*from++); - - for (int i = 0; i < childCount(); ++i) { - static_cast(child(i))->applyExpandedSnapshot(snapshot, from); - } -} - #include "moc_Tree.cpp" diff --git a/src/Gui/Tree.h b/src/Gui/Tree.h index 6997af4456..f644f81a64 100644 --- a/src/Gui/Tree.h +++ b/src/Gui/Tree.h @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -132,13 +131,6 @@ public: void synchronizeSelectionCheckBoxes(); - bool getSelectedSiblingObjectItems(std::vector &items) const; - - bool allowMoveUpInGroup(const std::vector &items, DocumentObjectItem **preceding = 0) const; - bool allowMoveDownInGroup(const std::vector &items, DocumentObjectItem **succeeding = 0) const; - - static bool moveSiblings(const std::vector &items, DocumentObjectItem *pivot, int direction); - protected: /// Observer message from the Selection void onSelectionChanged(const SelectionChanges& msg) override; @@ -163,7 +155,6 @@ protected: protected: void showEvent(QShowEvent *) override; void hideEvent(QHideEvent *) override; - void focusInEvent(QFocusEvent *event) override; void leaveEvent(QEvent *) override; void _updateStatus(bool delay=true); @@ -192,7 +183,6 @@ private Q_SLOTS: void onItemEntered(QTreeWidgetItem * item); void onItemCollapsed(QTreeWidgetItem * item); void onItemExpanded(QTreeWidgetItem * item); - void onTabifiedDockWidgetActivated(QDockWidget *dockWidget); void onUpdateStatus(void); Q_SIGNALS: @@ -222,9 +212,6 @@ private: bool CheckForDependents(); void addDependentToSelection(App::Document* doc, App::DocumentObject* docObject); - typedef bool (*DocumentObjectItemComparator)(const DocumentObjectItem *a, const DocumentObjectItem *b); - bool sortObjectItems(QTreeWidgetItem *node, DocumentObjectItemComparator comparator); - private: QAction* createGroupAction; QAction* relabelObjectAction; @@ -263,8 +250,6 @@ private: std::unordered_map > NewObjects; - std::set ReorderedObjects; - static std::set Instances; std::string myName; // for debugging purpose @@ -356,7 +341,7 @@ protected: QTreeWidgetItem *parent=0, int index=-1, DocumentObjectDataPtr ptrs = DocumentObjectDataPtr()); - int findRootIndex(const ViewProviderDocumentObject *childObj) const; + int findRootIndex(App::DocumentObject *childObj); DocumentObjectItem *findItemByObject(bool sync, App::DocumentObject *obj, const char *subname, bool select=false); @@ -456,14 +441,8 @@ public: int isParentGroup() const; DocumentObjectItem *getParentItem() const; - DocumentObjectItem *getNextSibling() const; - DocumentObjectItem *getPreviousSibling() const; - TreeWidget *getTree() const; - void getExpandedSnapshot(std::vector &snapshot) const; - void applyExpandedSnapshot(const std::vector &snapshot, std::vector::const_iterator &from); - private: void setCheckState(bool checked); diff --git a/src/Gui/ViewProviderDocumentObject.cpp b/src/Gui/ViewProviderDocumentObject.cpp index 208b18b1b8..fc7923a3bf 100644 --- a/src/Gui/ViewProviderDocumentObject.cpp +++ b/src/Gui/ViewProviderDocumentObject.cpp @@ -66,8 +66,6 @@ FC_LOG_LEVEL_INIT("Gui",true,true) using namespace Gui; -int ViewProviderDocumentObject::lastTreeRank = 0; - PROPERTY_SOURCE(Gui::ViewProviderDocumentObject, Gui::ViewProvider) ViewProviderDocumentObject::ViewProviderDocumentObject() @@ -92,8 +90,6 @@ ViewProviderDocumentObject::ViewProviderDocumentObject() "Element: On top only if some sub-element of the object is selected"); OnTopWhenSelected.setEnums(OnTopEnum); - ADD_PROPERTY_TYPE(TreeRank, (0), dogroup, App::PropertyType(App::Prop_Hidden|App::Prop_NoPersist), "Tree view item ordering key"); - sPixmap = "Feature"; } @@ -226,14 +222,6 @@ void ViewProviderDocumentObject::onChanged(const App::Property* prop) ? SoFCSelectionRoot::Box : SoFCSelectionRoot::Full; } } - else if (prop == &TreeRank) { - if (this->TreeRank.getValue() <= 0) { - this->TreeRank.setValue(++ViewProviderDocumentObject::lastTreeRank); - } - else if (this->TreeRank.getValue() > ViewProviderDocumentObject::lastTreeRank) { - ViewProviderDocumentObject::lastTreeRank = this->TreeRank.getValue(); - } - } if (prop && !prop->testStatus(App::Property::NoModify) && pcDocument @@ -690,15 +678,3 @@ std::string ViewProviderDocumentObject::getFullName() const { return pcObject->getFullName() + ".ViewObject"; return std::string("?"); } - -bool ViewProviderDocumentObject::allowTreeOrderSwap(const App::DocumentObject *child1, const App::DocumentObject *child2) const -{ - std::vector extensions = getExtensionsDerivedFromType(); - for (ViewProviderExtension *ext : extensions) { - if (!ext->extensionAllowTreeOrderSwap(child1, child2)) { - return false; - } - } - - return true; -} diff --git a/src/Gui/ViewProviderDocumentObject.h b/src/Gui/ViewProviderDocumentObject.h index 4d5a54df1d..3af4173d13 100644 --- a/src/Gui/ViewProviderDocumentObject.h +++ b/src/Gui/ViewProviderDocumentObject.h @@ -64,9 +64,6 @@ public: App::PropertyEnumeration OnTopWhenSelected; App::PropertyEnumeration SelectionStyle; - // Hidden properties - App::PropertyInteger TreeRank; - virtual void attach(App::DocumentObject *pcObject); virtual void reattach(App::DocumentObject *); virtual void update(const App::Property*) override; @@ -158,8 +155,6 @@ public: void setShowable(bool enable); bool isShowable() const; - virtual bool allowTreeOrderSwap(const App::DocumentObject *child1, const App::DocumentObject *child2) const; - protected: /*! Get the active mdi view of the document this view provider is part of. @note The returned mdi view doesn't need to be a 3d view but can be e.g. @@ -212,8 +207,6 @@ protected: App::DocumentObject *pcObject; Gui::Document* pcDocument; - static int lastTreeRank; - private: bool _Showable = true; diff --git a/src/Gui/ViewProviderExtension.h b/src/Gui/ViewProviderExtension.h index fa96fd3c2d..27af83db83 100644 --- a/src/Gui/ViewProviderExtension.h +++ b/src/Gui/ViewProviderExtension.h @@ -110,8 +110,6 @@ public: virtual bool extensionGetElementPicked(const SoPickedPoint *, std::string &) const {return false;} virtual bool extensionGetDetailPath(const char *, SoFullPath *, SoDetail *&) const {return false;} - virtual bool extensionAllowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return true; } - private: bool m_ignoreOverlayIcon = false; //Gui::ViewProviderDocumentObject* m_viewBase = nullptr; diff --git a/src/Gui/ViewProviderOrigin.h b/src/Gui/ViewProviderOrigin.h index e46bdad450..e9fd870706 100644 --- a/src/Gui/ViewProviderOrigin.h +++ b/src/Gui/ViewProviderOrigin.h @@ -74,8 +74,6 @@ public: return false; } - virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; } - /// Returns default size. Use this if it is not possible to determine appropriate size by other means static double defaultSize(); protected: diff --git a/src/Gui/ViewProviderOriginGroupExtension.h b/src/Gui/ViewProviderOriginGroupExtension.h index 8e8abe38e0..1a28f7fe4e 100644 --- a/src/Gui/ViewProviderOriginGroupExtension.h +++ b/src/Gui/ViewProviderOriginGroupExtension.h @@ -48,8 +48,6 @@ public: void updateOriginSize(); - virtual bool extensionAllowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const override { return false; } - protected: void slotChangedObjectApp ( const App::DocumentObject& obj ); void slotChangedObjectGui ( const Gui::ViewProviderDocumentObject& obj ); diff --git a/src/Mod/Part/Gui/ViewProviderBoolean.h b/src/Mod/Part/Gui/ViewProviderBoolean.h index ac97433d90..3c379309ab 100644 --- a/src/Mod/Part/Gui/ViewProviderBoolean.h +++ b/src/Mod/Part/Gui/ViewProviderBoolean.h @@ -44,9 +44,6 @@ public: QIcon getIcon(void) const; void updateData(const App::Property*); bool onDelete(const std::vector &); - - virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; } - }; /// ViewProvider for the MultiFuse feature diff --git a/src/Mod/Part/Gui/ViewProviderMirror.h b/src/Mod/Part/Gui/ViewProviderMirror.h index 1664528a41..1753a66291 100644 --- a/src/Mod/Part/Gui/ViewProviderMirror.h +++ b/src/Mod/Part/Gui/ViewProviderMirror.h @@ -126,8 +126,6 @@ public: /// grouping handling std::vector claimChildren(void)const; bool onDelete(const std::vector &); - - virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; } }; class ViewProviderSweep : public ViewProviderPart @@ -143,8 +141,6 @@ public: /// grouping handling std::vector claimChildren(void)const; bool onDelete(const std::vector &); - - virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; } }; class ViewProviderOffset : public ViewProviderPart @@ -192,8 +188,6 @@ public: void setupContextMenu(QMenu*, QObject*, const char*); bool onDelete(const std::vector &); - virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; } - protected: virtual bool setEdit(int ModNum); virtual void unsetEdit(int ModNum); diff --git a/src/Mod/PartDesign/Gui/ViewProviderLoft.h b/src/Mod/PartDesign/Gui/ViewProviderLoft.h index a043d87261..01f24e76c5 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderLoft.h +++ b/src/Mod/PartDesign/Gui/ViewProviderLoft.h @@ -44,9 +44,7 @@ public: virtual bool onDelete(const std::vector &); void highlightReferences(const bool on, bool auxiliary); - - virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; } - + protected: virtual bool setEdit(int ModNum); virtual void unsetEdit(int ModNum); diff --git a/src/Mod/PartDesign/Gui/ViewProviderPipe.h b/src/Mod/PartDesign/Gui/ViewProviderPipe.h index 3215cdfd29..e3efe3a695 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPipe.h +++ b/src/Mod/PartDesign/Gui/ViewProviderPipe.h @@ -52,9 +52,7 @@ public: virtual bool onDelete(const std::vector &); void highlightReferences(Reference mode, bool on); - - virtual bool allowTreeOrderSwap(const App::DocumentObject *, const App::DocumentObject *) const { return false; } - + protected: virtual QIcon getIcon(void) const; virtual bool setEdit(int ModNum); diff --git a/src/Mod/Test/CMakeLists.txt b/src/Mod/Test/CMakeLists.txt index 741a12e451..81d1422ed8 100644 --- a/src/Mod/Test/CMakeLists.txt +++ b/src/Mod/Test/CMakeLists.txt @@ -13,7 +13,6 @@ SET(Test_SRCS unittestgui.py testmakeWireString.py TestPythonSyntax.py - TreeView.py ) SOURCE_GROUP("" FILES ${Test_SRCS}) diff --git a/src/Mod/Test/InitGui.py b/src/Mod/Test/InitGui.py index 2bd25e6850..cbb18f8588 100644 --- a/src/Mod/Test/InitGui.py +++ b/src/Mod/Test/InitGui.py @@ -77,5 +77,4 @@ Gui.addWorkbench(TestWorkbench()) FreeCAD.__unit_test__ += [ "Workbench", "Menu", "Menu.MenuDeleteCases", - "Menu.MenuCreateCases", - "TreeView"] + "Menu.MenuCreateCases" ] diff --git a/src/Mod/Test/TreeView.py b/src/Mod/Test/TreeView.py deleted file mode 100644 index 019309ae1a..0000000000 --- a/src/Mod/Test/TreeView.py +++ /dev/null @@ -1,244 +0,0 @@ - -# TreeView test module - -import os -import time -import tempfile -import unittest -import FreeCAD - -from PySide import QtCore, QtGui -import FreeCADGui - - -class TreeViewTestCase(unittest.TestCase): - def setUp(self): - pass - - def tearDown(self): - pass - - def getTreeWidget(self): - mainWnd = FreeCADGui.getMainWindow() - treeDock = mainWnd.findChild(QtGui.QDockWidget, "Tree View") - if treeDock is None: - treeDock = mainWnd.findChild(QtGui.QDockWidget, "Combo View") - if not treeDock is None: - tabWidget = treeDock.findChild(QtGui.QTabWidget, "combiTab") - if not tabWidget is None: - tabWidget.setCurrentIndex(0) - self.assertTrue(not treeDock is None, "No Tree View docks available") - - treeView = treeDock.findChild(QtGui.QTreeWidget) - self.assertTrue(not treeView is None, "No Tree View widget found") - - return treeView - - def waitForTreeViewSync(self): - start = time.time() - while time.time() < start + 0.5: - FreeCADGui.updateGui() - - def selectDocItem(self, docItem): - - treeView = self.getTreeWidget() - - if docItem.TypeId == "App::Document": - appNode = treeView.topLevelItem(0) - self.assertTrue(not appNode is None, "No Application top level node") - - docNode = next((appNode.child(i) for i in range(appNode.childCount()) - if appNode.child(i).text(0) == docItem.Label), None) - self.assertTrue(not docNode is None, "No test Document node") - treeView.setCurrentItem(docNode) - else: - FreeCADGui.Selection.clearSelection() - FreeCADGui.Selection.addSelection(docItem) - self.waitForTreeViewSync() - - def trySwapOuterTreeViewItems(self, docItem, transposable): - - self.selectDocItem(docItem) - treeView = self.getTreeWidget() - - selected = treeView.selectedItems() - self.assertTrue(len(selected) == 1, - "Unexpected count of selected items: " + str(len(selected))) - selected = selected[0] - - originalState = [ selected.child(i).text(0) for i in range(selected.childCount()) ] - self.assertTrue(len(originalState) >= 1, - "No children found in item " + selected.text(0)) - - targetState = originalState.copy() - if transposable: - targetState[0], targetState[-1] = targetState[-1], targetState[0] - - treeView.setCurrentItem(selected.child(0)) - self.waitForTreeViewSync() - - # One move down attempt more to test boundary behaviour - for i in range(len(originalState)): - FreeCADGui.runCommand("Std_GroupMoveDown") - self.waitForTreeViewSync() - - treeView.setCurrentItem(selected.child(len(originalState) - 2 if len(originalState) > 1 else 0)) - self.waitForTreeViewSync() - - # One move up attempt more to test boundary behaviour - for i in range(len(originalState) - 1): - FreeCADGui.runCommand("Std_GroupMoveUp") - self.waitForTreeViewSync() - - finalState = [ selected.child(i).text(0) for i in range(selected.childCount()) ] - self.assertTrue(targetState == finalState, - "Unexpected final state: %s\nExpected: %s" % (finalState, targetState)) - - def getChildrenOf(self, docItem): - - self.selectDocItem(docItem) - treeView = self.getTreeWidget() - - selected = treeView.selectedItems() - self.assertTrue(len(selected) == 1, - "Unexpected count of selected items: " + str(len(selected))) - selected = selected[0] - - return [ selected.child(i).text(0) for i in range(selected.childCount()) ] - - - def testMoveTransposableItems(self): - # Makes sense only if Gui is shown - if not FreeCAD.GuiUp: - return - - FreeCAD.TestEnvironment = True - - doc = FreeCAD.newDocument("TreeViewTest1") - FreeCAD.setActiveDocument(doc.Name) - - box = doc.addObject("Part::Box", "Box") - cyl = doc.addObject("Part::Cylinder", "Cylinder") - sph = doc.addObject("Part::Sphere", "Sphere") - con = doc.addObject("Part::Cone", "Cone") - doc.recompute() - - self.trySwapOuterTreeViewItems(doc, True) - - grp = doc.addObject("App::DocumentObjectGroup", "Group") - grp.addObjects([ box, cyl, sph, con ]) - doc.recompute() - - self.trySwapOuterTreeViewItems(grp, True) - - del FreeCAD.TestEnvironment - - - def testMoveUnmovableItems(self): - # Makes sense only if Gui is shown - if not FreeCAD.GuiUp: - return - - FreeCAD.TestEnvironment = True - - doc = FreeCAD.newDocument("TreeViewTest2") - FreeCAD.setActiveDocument(doc.Name) - - sph = doc.addObject("Part::Sphere", "Sphere") - con = doc.addObject("Part::Cone", "Cone") - doc.recompute() - - cut = doc.addObject("Part::Cut", "Cut") - cut.Base = sph - cut.Tool = con - doc.recompute() - - self.trySwapOuterTreeViewItems(cut, False) - - bdy = doc.addObject("PartDesign::Body", "Body") - box = doc.addObject("PartDesign::AdditiveBox", "Box") - bdy.addObject(box) - doc.recompute() - - FreeCADGui.Selection.clearSelection() - FreeCADGui.Selection.addSelection(bdy) - self.waitForTreeViewSync() - - treeView = self.getTreeWidget() - treeView.selectedItems()[0].setExpanded(True) - self.waitForTreeViewSync() - - FreeCADGui.Selection.clearSelection() - FreeCADGui.Selection.addSelection(doc.Name, bdy.Name, box.Name + ".Face6") - self.waitForTreeViewSync() - - cha = bdy.newObject("PartDesign::Chamfer", "Chamfer") - cha.Base = (box, ["Face6"]) - doc.recompute() - - cyl = doc.addObject("PartDesign::SubtractiveCylinder", "Cylinder") - bdy.addObject(cyl) - doc.recompute() - - self.trySwapOuterTreeViewItems(bdy, False) - - del FreeCAD.TestEnvironment - - - def testItemOrderSaveAndRestore(self): - # Makes sense only if Gui is shown - if not FreeCAD.GuiUp: - return - - FreeCAD.TestEnvironment = True - - doc = FreeCAD.newDocument("TreeViewTest3") - FreeCAD.setActiveDocument(doc.Name) - - grp = doc.addObject("App::DocumentObjectGroup", "Group") - box = doc.addObject("Part::Box", "Box") - cyl = doc.addObject("Part::Cylinder", "Cylinder") - sph = doc.addObject("Part::Sphere", "Sphere") - con = doc.addObject("Part::Cone", "Cone") - doc.recompute() - - origOrder = self.getChildrenOf(doc) - self.assertTrue(origOrder == ["Group", "Box", "Cylinder", "Sphere", "Cone"]) - - origOrderFile = tempfile.gettempdir() + os.sep + "TreeViewTest3_1.fcstd" - doc.saveAs(origOrderFile) - - FreeCADGui.Selection.clearSelection() - FreeCADGui.Selection.addSelection(con) - FreeCADGui.Selection.addSelection(cyl) - self.waitForTreeViewSync() - - FreeCADGui.runCommand("Std_GroupMoveUp") - self.waitForTreeViewSync() - - FreeCADGui.Selection.clearSelection() - FreeCADGui.Selection.addSelection(grp) - FreeCADGui.Selection.addSelection(box) - self.waitForTreeViewSync() - - FreeCADGui.runCommand("Std_GroupMoveDown") - self.waitForTreeViewSync() - - newOrder = self.getChildrenOf(doc) - self.assertTrue(newOrder == ["Cylinder", "Cone", "Sphere", "Group", "Box"]) - - newOrderFile = tempfile.gettempdir() + os.sep + "TreeViewTest3_2.fcstd" - doc.saveAs(newOrderFile) - - FreeCAD.closeDocument(doc.Name) - self.waitForTreeViewSync() - - doc = FreeCAD.open(origOrderFile) - order = self.getChildrenOf(doc) - self.assertTrue(order == origOrder) - - doc = FreeCAD.open(newOrderFile) - order = self.getChildrenOf(doc) - self.assertTrue(order == newOrder) - - del FreeCAD.TestEnvironment From 401db10fc600c37a8a715da31c5655b7cf423365 Mon Sep 17 00:00:00 2001 From: Roy-043 <70520633+Roy-043@users.noreply.github.com> Date: Wed, 24 Nov 2021 17:50:15 +0100 Subject: [PATCH 061/133] Update Draft.py Fixed missing commas. --- src/Mod/Draft/Draft.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 1307af47a8..f3b8e45d4c 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -120,11 +120,11 @@ from draftutils.gui_utils import (dim_symbol, dim_dash, dimDash) -from draftutils.groups import (is_group +from draftutils.groups import (is_group, get_group_names, getGroupNames, ungroup, - get_windows + get_windows, get_group_contents, getGroupContents, get_movable_children, From 325c5ec887d838ba1124ab2a8ae2a47eb0b8a30a Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 24 Nov 2021 18:27:21 +0100 Subject: [PATCH 062/133] Fix issue 0004791: DXF import fails for trivial circle --- src/Mod/Draft/App/DraftDxf.cpp | 5 ++++- src/Mod/Import/App/ImpExpDxf.cpp | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Mod/Draft/App/DraftDxf.cpp b/src/Mod/Draft/App/DraftDxf.cpp index 230fe392fb..88a585ee17 100644 --- a/src/Mod/Draft/App/DraftDxf.cpp +++ b/src/Mod/Draft/App/DraftDxf.cpp @@ -163,6 +163,9 @@ void DraftDxfRead::OnReadInsert(const double* point, const double* scale, const std::string prefix = "BLOCKS "; prefix += name; prefix += " "; + auto checkScale = [=](double v) { + return v != 0.0 ? v : 1.0; + }; for(std::map > ::const_iterator i = layers.begin(); i != layers.end(); ++i) { std::string k = i->first; if(k.substr(0, prefix.size()) == prefix) { @@ -178,7 +181,7 @@ void DraftDxfRead::OnReadInsert(const double* point, const double* scale, const if (!comp.IsNull()) { Part::TopoShape* pcomp = new Part::TopoShape(comp); Base::Matrix4D mat; - mat.scale(scale[0],scale[1],scale[2]); + mat.scale(checkScale(scale[0]),checkScale(scale[1]),checkScale(scale[2])); mat.rotZ(rotation); mat.move(point[0]*optionScaling,point[1]*optionScaling,point[2]*optionScaling); pcomp->transformShape(mat,true); diff --git a/src/Mod/Import/App/ImpExpDxf.cpp b/src/Mod/Import/App/ImpExpDxf.cpp index dcd88ef138..e5cc1b632d 100644 --- a/src/Mod/Import/App/ImpExpDxf.cpp +++ b/src/Mod/Import/App/ImpExpDxf.cpp @@ -320,6 +320,9 @@ void ImpExpDxfRead::OnReadInsert(const double* point, const double* scale, const std::string prefix = "BLOCKS "; prefix += name; prefix += " "; + auto checkScale = [=](double v) { + return v != 0.0 ? v : 1.0; + }; for(std::map > ::const_iterator i = layers.begin(); i != layers.end(); ++i) { std::string k = i->first; if(k.substr(0, prefix.size()) == prefix) { @@ -335,7 +338,7 @@ void ImpExpDxfRead::OnReadInsert(const double* point, const double* scale, const if (!comp.IsNull()) { Part::TopoShape* pcomp = new Part::TopoShape(comp); Base::Matrix4D mat; - mat.scale(scale[0],scale[1],scale[2]); + mat.scale(checkScale(scale[0]),checkScale(scale[1]),checkScale(scale[2])); mat.rotZ(rotation); mat.move(point[0]*optionScaling,point[1]*optionScaling,point[2]*optionScaling); pcomp->transformShape(mat,true); From fea1d3558bbff8896f3f152e21b31181ea3bc679 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 24 Nov 2021 19:11:34 +0100 Subject: [PATCH 063/133] App: remove code to copy user config from old to new location --- src/App/Application.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 4e8b043821..714bd83af9 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -2893,6 +2893,7 @@ QString getUserHome() * Returns a directory location where persistent data shared across applications can be stored. * This method returns the old non-XDG-compliant root path where to store config files and application data. */ +#if defined(FC_OS_WIN32) QString getOldGenericDataLocation(QString home) { #if defined(FC_OS_WIN32) @@ -2908,6 +2909,7 @@ QString getOldGenericDataLocation(QString home) return home; } +#endif /*! * \brief getSubDirectories @@ -3119,17 +3121,6 @@ void Application::ExtractUserPath() boost::filesystem::path config = findPath(configHome, customHome, subdirs, true); mConfig["UserConfigPath"] = pathToString(config) + PATHSEP; - std::vector oldsubdirs; - getOldDataLocation(mConfig, oldsubdirs); - boost::filesystem::path appData = findPath(getOldGenericDataLocation(homePath), customData, oldsubdirs, false); - - // If in new location user.cfg doesn't exist but in the old location then copy it - boost::filesystem::path oldUsercfg = appData / "user.cfg"; - boost::filesystem::path newUsercfg = config / "user.cfg"; - if (boost::filesystem::exists(oldUsercfg) && !boost::filesystem::exists(newUsercfg)) { - boost::filesystem::copy(oldUsercfg, newUsercfg); - } - // User cache path // From 00d9bb5dd976b30ed970197bac3bc7a6aec130f5 Mon Sep 17 00:00:00 2001 From: Alex Neufeld Date: Wed, 24 Nov 2021 12:34:08 -0700 Subject: [PATCH 064/133] Revert "Addon Manager: Added VendorParts workbench icon" This reverts commit 39c162f93863927a9d7d1070413364d09e634a5e. --- src/Mod/AddonManager/Resources/AddonManager.qrc | 1 - .../Resources/icons/VendorParts_workbench_icon.svg | 8 -------- 2 files changed, 9 deletions(-) delete mode 100644 src/Mod/AddonManager/Resources/icons/VendorParts_workbench_icon.svg diff --git a/src/Mod/AddonManager/Resources/AddonManager.qrc b/src/Mod/AddonManager/Resources/AddonManager.qrc index 2c53e1db0a..312e646a45 100644 --- a/src/Mod/AddonManager/Resources/AddonManager.qrc +++ b/src/Mod/AddonManager/Resources/AddonManager.qrc @@ -58,7 +58,6 @@ icons/Silk_workbench_icon.svg icons/timber_workbench_icon.svg icons/ThreadProfile_workbench_icon.svg - icons/VendorParts_workbench_icon.svg icons/WebTools_workbench_icon.svg icons/workfeature_workbench_icon.svg icons/yaml-workspace_workbench_icon.svg diff --git a/src/Mod/AddonManager/Resources/icons/VendorParts_workbench_icon.svg b/src/Mod/AddonManager/Resources/icons/VendorParts_workbench_icon.svg deleted file mode 100644 index ce06f586b4..0000000000 --- a/src/Mod/AddonManager/Resources/icons/VendorParts_workbench_icon.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - From 3465ac3add08f0ab1a35e79d0cb8d808c30aa40d Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 24 Nov 2021 21:28:32 +0100 Subject: [PATCH 065/133] Gui: [skip ci] do not trigger on_fileChooser_fileNameChanged when opening macro dialog --- src/Gui/DlgMacroExecuteImp.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Gui/DlgMacroExecuteImp.cpp b/src/Gui/DlgMacroExecuteImp.cpp index c40f3d9a72..952d56f902 100644 --- a/src/Gui/DlgMacroExecuteImp.cpp +++ b/src/Gui/DlgMacroExecuteImp.cpp @@ -28,6 +28,7 @@ # include # include # include +# include #endif #include "DlgMacroExecuteImp.h" @@ -84,10 +85,13 @@ DlgMacroExecuteImp::DlgMacroExecuteImp( QWidget* parent, Qt::WindowFlags fl ) { ui->setupUi(this); // retrieve the macro path from parameter or use the user data as default - std::string path = getWindowParameter()->GetASCII("MacroPath", - App::Application::getUserMacroDir().c_str()); - this->macroPath = QString::fromUtf8(path.c_str()); - ui->fileChooser->setFileName(this->macroPath); + { + QSignalBlocker blocker(ui->fileChooser); + std::string path = getWindowParameter()->GetASCII("MacroPath", + App::Application::getUserMacroDir().c_str()); + this->macroPath = QString::fromUtf8(path.c_str()); + ui->fileChooser->setFileName(this->macroPath); + } // Fill the List box QStringList labels; labels << tr("Macros"); From 9283aa0f72213d68bc89bf152a6dbca3a2fb9e3f Mon Sep 17 00:00:00 2001 From: Uwe Date: Thu, 25 Nov 2021 03:19:31 +0100 Subject: [PATCH 066/133] [PD] revert a part of commit 1da079b34 as discussed and polled in https://forum.freecadweb.org/viewtopic.php?f=8&t=64000 --- src/Mod/PartDesign/App/FeatureExtrude.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp index 5561aeffc2..54a3599328 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.cpp +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -126,16 +126,6 @@ Base::Vector3d FeatureExtrude::computeDirection(const Base::Vector3d& sketchVect // explicitly set the Direction so that the dialog shows also the used direction // if the sketch's normal vector was used - // for a custom vector we cannot negate it since the Ui takes always the currently - // shown vector values as final direction, - // and when Reversed, it will be negated additionally - if (!UseCustomVector.getValue()) { - if (Reversed.getValue()) - Direction.setValue(-extrudeDirection); - else - Direction.setValue(extrudeDirection); - } - // don't return the direction including reversed since this is handled in - // FeatureSketchBased.cpp afterwards + Direction.setValue(extrudeDirection); return extrudeDirection; } From 36489487113f5b65be52279165b28150323748a3 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 25 Nov 2021 15:11:46 +0100 Subject: [PATCH 067/133] Gui: in search bar set red background color as style sheet because a palette won't work if an application wide style sheet is set --- src/Gui/EditorView.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Gui/EditorView.cpp b/src/Gui/EditorView.cpp index 1ad2f0c972..9f41a88e60 100644 --- a/src/Gui/EditorView.cpp +++ b/src/Gui/EditorView.cpp @@ -820,9 +820,16 @@ void SearchBar::findText(bool skip, bool next, const QString& str) textEditor->setTextCursor(newCursor); - QPalette palette; - palette.setColor(QPalette::Active, QPalette::Base, found ? Qt::white : QColor(255, 80, 80)); - searchText->setPalette(palette); + QString styleSheet; + if (!found) { + styleSheet = QString::fromLatin1( + " QLineEdit {\n" + " background-color: rgb(221,144,161);\n" + " }\n" + ); + } + + searchText->setStyleSheet(styleSheet); } void SearchBar::updateButtons() From 9baf044e6a435fbf922e19851a1c11326659414b Mon Sep 17 00:00:00 2001 From: Roy-043 <70520633+Roy-043@users.noreply.github.com> Date: Thu, 25 Nov 2021 15:21:11 +0100 Subject: [PATCH 068/133] Draft: fix 3 snap issues 1. Draft_Snap_Parallel only worked beyond the endpoints of the edge. 2. It was very hard to select an edge for Draft_Snap_Parallel if no other snaps were active. 3. Only two snap objects were stored. --- src/Mod/Draft/draftguitools/gui_snapper.py | 58 +++++++++++----------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_snapper.py b/src/Mod/Draft/draftguitools/gui_snapper.py index 7e582bf3fa..25d10812b0 100644 --- a/src/Mod/Draft/draftguitools/gui_snapper.py +++ b/src/Mod/Draft/draftguitools/gui_snapper.py @@ -83,7 +83,7 @@ class Snapper: def __init__(self): self.activeview = None - self.lastObj = [None, None] + self.lastObj = [] self.maxEdges = 0 self.radius = 0 self.constraintAxis = None @@ -471,16 +471,16 @@ class Snapper: # snap to corners of section planes snaps.extend(self.snapToEndpoints(obj.Shape)) + # updating last objects list + if obj.Name in self.lastObj: + self.lastObj.remove(obj.Name) + self.lastObj.append(obj.Name) + if len(self.lastObj) > 8: + self.lastObj = self.lastObj[-8:] + if not snaps: return None - # updating last objects list - if not self.lastObj[1]: - self.lastObj[1] = obj.Name - elif self.lastObj[1] != obj.Name: - self.lastObj[0] = self.lastObj[1] - self.lastObj[1] = obj.Name - # calculating the nearest snap point shortest = 1000000000000000000 origin = App.Vector(self.snapInfo['x'], @@ -610,9 +610,9 @@ class Snapper: self.setCursor(tsnap[1]) return tsnap[2], eline - for o in (self.lastObj[1], self.lastObj[0]): - if o and (self.isEnabled('Extension') - or self.isEnabled('Parallel')): + for o in self.lastObj: + if (self.isEnabled('Extension') + or self.isEnabled('Parallel')): ob = App.ActiveDocument.getObject(o) if not ob: continue @@ -630,10 +630,10 @@ class Snapper: if DraftGeomUtils.geomType(e) != "Line": continue np = self.getPerpendicular(e,point) - if DraftGeomUtils.isPtOnEdge(np,e): - continue if (np.sub(point)).Length < self.radius: if self.isEnabled('Extension'): + if DraftGeomUtils.isPtOnEdge(np,e): + continue if np != e.Vertexes[0].Point: p0 = e.Vertexes[0].Point if self.tracker and not self.selectMode: @@ -664,20 +664,19 @@ class Snapper: self.lastExtensions[1] = self.lastExtensions[0] self.lastExtensions[0] = ne return np,ne - else: - if self.isEnabled('Parallel'): - if last: - ve = DraftGeomUtils.vec(e) - if not DraftVecUtils.isNull(ve): - de = Part.LineSegment(last,last.add(ve)).toShape() - np = self.getPerpendicular(de,point) - if (np.sub(point)).Length < self.radius: - if self.tracker and not self.selectMode: - self.tracker.setCoords(np) - self.tracker.setMarker(self.mk['parallel']) - self.tracker.on() - self.setCursor('parallel') - return np,de + elif self.isEnabled('Parallel'): + if last: + ve = DraftGeomUtils.vec(e) + if not DraftVecUtils.isNull(ve): + de = Part.LineSegment(last,last.add(ve)).toShape() + np = self.getPerpendicular(de,point) + if (np.sub(point)).Length < self.radius: + if self.tracker and not self.selectMode: + self.tracker.setCoords(np) + self.tracker.setMarker(self.mk['parallel']) + self.tracker.on() + self.setCursor('parallel') + return np,de return point,eline @@ -995,8 +994,8 @@ class Snapper: snaps = [] if self.isEnabled("Intersection"): # get the stored objects to calculate intersections - if self.lastObj[0]: - obj = App.ActiveDocument.getObject(self.lastObj[0]) + for o in self.lastObj[:-1]: + obj = App.ActiveDocument.getObject(o) if obj: if obj.isDerivedFrom("Part::Feature") or (Draft.getType(obj) == "Axis"): if (not self.maxEdges) or (len(obj.Shape.Edges) <= self.maxEdges): @@ -1226,6 +1225,7 @@ class Snapper: self.selectMode = False self.running = False self.holdPoints = [] + self.lastObj = [] def setSelectMode(self, mode): From bca145d8c743111bb6435a9e552da1a301b7c67c Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 26 Nov 2021 16:01:23 +0100 Subject: [PATCH 069/133] App: Added warning at startup if user mods are found in older location --- src/App/FreeCADInit.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/App/FreeCADInit.py b/src/App/FreeCADInit.py index 2a7b1d91a7..cafbffcd8a 100644 --- a/src/App/FreeCADInit.py +++ b/src/App/FreeCADInit.py @@ -133,6 +133,9 @@ def InitApplications(): if os.path.isdir(HomeMod): HomeMods = os.listdir(HomeMod) for i in HomeMods: ModDict[i.lower()] = os.path.join(HomeMod,i) + elif os.path.isdir(os.path.join(os.path.expanduser("~"),".FreeCAD","Mod")): + # Check if old location exists + Wrn ("User path has changed to " + FreeCAD.getUserAppDataDir() + ". Please move user modules and macros\n") # Search for additional modules in the macro directory if os.path.isdir(MacroMod): MacroMods = os.listdir(MacroMod) From 6a0cf8233ae47635371d79aed5705dd88fd35ff4 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 26 Nov 2021 15:20:13 +0100 Subject: [PATCH 070/133] PD: create a common base class of TaskPocketParameters and TaskPocketParameters to reduce code duplications --- src/Mod/PartDesign/Gui/CMakeLists.txt | 2 + .../PartDesign/Gui/TaskExtrudeParameters.cpp | 715 ++++++++++++++++++ .../PartDesign/Gui/TaskExtrudeParameters.h | 107 +++ src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 672 +--------------- src/Mod/PartDesign/Gui/TaskPadParameters.h | 57 +- src/Mod/PartDesign/Gui/TaskPadParameters.ui | 6 - .../PartDesign/Gui/TaskPocketParameters.cpp | 667 +--------------- src/Mod/PartDesign/Gui/TaskPocketParameters.h | 58 +- .../PartDesign/Gui/TaskPocketParameters.ui | 3 - 9 files changed, 867 insertions(+), 1420 deletions(-) create mode 100644 src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp create mode 100644 src/Mod/PartDesign/Gui/TaskExtrudeParameters.h diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index 01c0ad1cc0..36323b94f9 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -147,6 +147,8 @@ SET(PartDesignGuiTaskDlgs_SRCS TaskFeatureParameters.h TaskSketchBasedParameters.cpp TaskSketchBasedParameters.h + TaskExtrudeParameters.cpp + TaskExtrudeParameters.h TaskPadParameters.ui TaskPadParameters.cpp TaskPadParameters.h diff --git a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp new file mode 100644 index 0000000000..c7b55b6150 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp @@ -0,0 +1,715 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +# include +# include +# include +# include +#endif + +#include "ui_TaskPadParameters.h" +#include "TaskExtrudeParameters.h" +#include +#include +#include "ReferenceSelection.h" + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskExtrudeParameters */ + +TaskExtrudeParameters::TaskExtrudeParameters(ViewProviderSketchBased *SketchBasedView, QWidget *parent, + const std::string& pixmapname, const QString& parname) + : TaskSketchBasedParameters(SketchBasedView, parent, pixmapname, parname) + , ui(new Ui_TaskPadParameters) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui->setupUi(proxy); +#if QT_VERSION >= 0x040700 + ui->lineFaceName->setPlaceholderText(tr("No face selected")); +#endif + + this->groupLayout()->addWidget(proxy); +} + +void TaskExtrudeParameters::setupDialog(bool newObj) +{ + // Get the feature data + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + Base::Quantity l = extrude->Length.getQuantityValue(); + Base::Quantity l2 = extrude->Length2.getQuantityValue(); + Base::Quantity off = extrude->Offset.getQuantityValue(); + bool alongNormal = extrude->AlongSketchNormal.getValue(); + bool useCustom = extrude->UseCustomVector.getValue(); + double xs = extrude->Direction.getValue().x; + double ys = extrude->Direction.getValue().y; + double zs = extrude->Direction.getValue().z; + bool midplane = extrude->Midplane.getValue(); + bool reversed = extrude->Reversed.getValue(); + int index = extrude->Type.getValue(); // must extract value here, clear() kills it! + App::DocumentObject* obj = extrude->UpToFace.getValue(); + std::vector subStrings = extrude->UpToFace.getSubValues(); + std::string upToFace; + int faceId = -1; + if ((obj != NULL) && !subStrings.empty()) { + upToFace = subStrings.front(); + if (upToFace.substr(0,4) == "Face") + faceId = std::atoi(&upToFace[4]); + } + + // set decimals for the direction edits + // do this here before the edits are filed to avoid rounding mistakes + int UserDecimals = Base::UnitsApi::getDecimals(); + ui->XDirectionEdit->setDecimals(UserDecimals); + ui->YDirectionEdit->setDecimals(UserDecimals); + ui->ZDirectionEdit->setDecimals(UserDecimals); + + // Fill data into dialog elements + // the direction combobox is later filled in updateUI() + ui->lengthEdit->setValue(l); + ui->lengthEdit2->setValue(l2); + ui->offsetEdit->setValue(off); + ui->checkBoxAlongDirection->setChecked(alongNormal); + ui->checkBoxDirection->setChecked(useCustom); + onDirectionToggled(useCustom); + // disable to change the direction if not custom + if (!useCustom) { + ui->XDirectionEdit->setEnabled(false); + ui->YDirectionEdit->setEnabled(false); + ui->ZDirectionEdit->setEnabled(false); + } + ui->XDirectionEdit->setValue(xs); + ui->YDirectionEdit->setValue(ys); + ui->ZDirectionEdit->setValue(zs); + + // Bind input fields to properties + ui->lengthEdit->bind(extrude->Length); + ui->lengthEdit2->bind(extrude->Length2); + ui->offsetEdit->bind(extrude->Offset); + ui->XDirectionEdit->bind(App::ObjectIdentifier::parse(extrude, std::string("Direction.x"))); + ui->YDirectionEdit->bind(App::ObjectIdentifier::parse(extrude, std::string("Direction.y"))); + ui->ZDirectionEdit->bind(App::ObjectIdentifier::parse(extrude, std::string("Direction.z"))); + + ui->checkBoxMidplane->setChecked(midplane); + // According to bug #0000521 the reversed option + // shouldn't be de-activated if the pad has a support face + ui->checkBoxReversed->setChecked(reversed); + + // Set object labels + if (obj && PartDesign::Feature::isDatum(obj)) { + ui->lineFaceName->setText(QString::fromUtf8(obj->Label.getValue())); + ui->lineFaceName->setProperty("FeatureName", QByteArray(obj->getNameInDocument())); + } + else if (obj && faceId >= 0) { + ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3") + .arg(QString::fromUtf8(obj->Label.getValue())) + .arg(tr("Face")) + .arg(faceId)); + ui->lineFaceName->setProperty("FeatureName", QByteArray(obj->getNameInDocument())); + } + else { + ui->lineFaceName->clear(); + ui->lineFaceName->setProperty("FeatureName", QVariant()); + } + + ui->lineFaceName->setProperty("FaceName", QByteArray(upToFace.c_str())); + + translateModeList(index); + + QMetaObject::connectSlotsByName(this); + + connect(ui->lengthEdit, SIGNAL(valueChanged(double)), + this, SLOT(onLengthChanged(double))); + connect(ui->lengthEdit2, SIGNAL(valueChanged(double)), + this, SLOT(onLength2Changed(double))); + connect(ui->offsetEdit, SIGNAL(valueChanged(double)), + this, SLOT(onOffsetChanged(double))); + connect(ui->directionCB, SIGNAL(activated(int)), + this, SLOT(onDirectionCBChanged(int))); + connect(ui->checkBoxAlongDirection, SIGNAL(toggled(bool)), + this, SLOT(onAlongSketchNormalChanged(bool))); + connect(ui->checkBoxDirection, SIGNAL(toggled(bool)), + this, SLOT(onDirectionToggled(bool))); + connect(ui->XDirectionEdit, SIGNAL(valueChanged(double)), + this, SLOT(onXDirectionEditChanged(double))); + connect(ui->YDirectionEdit, SIGNAL(valueChanged(double)), + this, SLOT(onYDirectionEditChanged(double))); + connect(ui->ZDirectionEdit, SIGNAL(valueChanged(double)), + this, SLOT(onZDirectionEditChanged(double))); + connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)), + this, SLOT(onMidplaneChanged(bool))); + connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), + this, SLOT(onReversedChanged(bool))); + connect(ui->changeMode, SIGNAL(currentIndexChanged(int)), + this, SLOT(onModeChanged(int))); + connect(ui->buttonFace, SIGNAL(clicked()), + this, SLOT(onButtonFace())); + connect(ui->lineFaceName, SIGNAL(textEdited(QString)), + this, SLOT(onFaceName(QString))); + connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), + this, SLOT(onUpdateView(bool))); + + this->propReferenceAxis = &(extrude->ReferenceAxis); + + // Due to signals attached after changes took took into effect we should update the UI now. + updateUI(index); + + // if it is a newly created object use the last value of the history + // TODO: newObj doesn't supplied normally by any caller (2015-07-24, Fat-Zer) + if (newObj){ + ui->lengthEdit->setToLastUsedValue(); + ui->lengthEdit->selectNumber(); + ui->lengthEdit2->setToLastUsedValue(); + ui->lengthEdit2->selectNumber(); + ui->offsetEdit->setToLastUsedValue(); + ui->offsetEdit->selectNumber(); + } +} + +TaskExtrudeParameters::~TaskExtrudeParameters() +{ +} + +void TaskExtrudeParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + // if we have an edge selection for the extrude direction + if (!selectionFace) { + std::vector edge; + App::DocumentObject* selObj; + if (getReferencedSelection(vp->getObject(), msg, selObj, edge) && selObj) { + exitSelectionMode(); + propReferenceAxis->setValue(selObj, edge); + recomputeFeature(); + // update direction combobox + fillDirectionCombo(); + } + } + else { // if we have a selection of a face + QString refText = onAddSelection(msg); + if (refText.length() > 0) { + ui->lineFaceName->blockSignals(true); + ui->lineFaceName->setText(refText); + ui->lineFaceName->setProperty("FeatureName", QByteArray(msg.pObjectName)); + ui->lineFaceName->setProperty("FaceName", QByteArray(msg.pSubName)); + ui->lineFaceName->blockSignals(false); + // Turn off reference selection mode + onButtonFace(false); + } + else { + ui->lineFaceName->blockSignals(true); + ui->lineFaceName->clear(); + ui->lineFaceName->setProperty("FeatureName", QVariant()); + ui->lineFaceName->setProperty("FaceName", QVariant()); + ui->lineFaceName->blockSignals(false); + } + } + } else if (msg.Type == Gui::SelectionChanges::ClrSelection && selectionFace) { + ui->lineFaceName->blockSignals(true); + ui->lineFaceName->clear(); + ui->lineFaceName->setProperty("FeatureName", QVariant()); + ui->lineFaceName->setProperty("FaceName", QVariant()); + ui->lineFaceName->blockSignals(false); + } +} + +void TaskExtrudeParameters::onLengthChanged(double len) +{ + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + extrude->Length.setValue(len); + recomputeFeature(); +} + +void TaskExtrudeParameters::onLength2Changed(double len) +{ + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + extrude->Length2.setValue(len); + recomputeFeature(); +} + +void TaskExtrudeParameters::onOffsetChanged(double len) +{ + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + extrude->Offset.setValue(len); + recomputeFeature(); +} + +void TaskExtrudeParameters::fillDirectionCombo() +{ + bool oldVal_blockUpdate = blockUpdate; + blockUpdate = true; + + if (axesInList.empty()) { + bool hasFace = false; + ui->directionCB->clear(); + // we can have sketches or faces + // for sketches just get the sketch normal + PartDesign::ProfileBased* pcFeat = static_cast(vp->getObject()); + Part::Part2DObject* pcSketch = dynamic_cast(pcFeat->Profile.getValue()); + // for faces we test if it is verified and if we can get its normal + if (!pcSketch) { + try { + Part::Feature* pcFeature = pcFeat->getVerifiedObject(); + Base::Vector3d SketchVector = pcFeat->getProfileNormal(); + Q_UNUSED(pcFeature) + Q_UNUSED(SketchVector) + hasFace = true; + } + catch (const Base::Exception& e) { + new App::DocumentObjectExecReturn(e.what()); + } + } + if (pcSketch) + addAxisToCombo(pcSketch, "N_Axis", tr("Sketch normal")); + else if (hasFace) + addAxisToCombo(pcFeat->Profile.getValue(), std::string(), tr("Face normal"), false); + // add the other entries + addAxisToCombo(0, std::string(), tr("Select reference...")); + // we start with the sketch normal as proposal for the custom direction + if (pcSketch) + addAxisToCombo(pcSketch, "N_Axis", tr("Custom direction")); + else if (hasFace) + addAxisToCombo(pcFeat->Profile.getValue(), std::string(), tr("Custom direction"), false); + } + + // add current link, if not in list + // first, figure out the item number for current axis + int indexOfCurrent = -1; + App::DocumentObject* ax = propReferenceAxis->getValue(); + const std::vector& subList = propReferenceAxis->getSubValues(); + for (size_t i = 0; i < axesInList.size(); i++) { + if (ax == axesInList[i]->getValue() && subList == axesInList[i]->getSubValues()) { + indexOfCurrent = i; + break; + } + } + // if the axis is not yet listed in the combobox + if (indexOfCurrent == -1 && ax) { + assert(subList.size() <= 1); + std::string sub; + if (!subList.empty()) + sub = subList[0]; + addAxisToCombo(ax, sub, getRefStr(ax, subList)); + indexOfCurrent = axesInList.size() - 1; + // the axis is not the normal, thus enable along direction + ui->checkBoxAlongDirection->setEnabled(true); + // we don't have custom direction thus disable its settings + ui->XDirectionEdit->setEnabled(false); + ui->YDirectionEdit->setEnabled(false); + ui->ZDirectionEdit->setEnabled(false); + } + + // highlight either current index or set custom direction + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + bool hasCustom = extrude->UseCustomVector.getValue(); + if (indexOfCurrent != -1 && !hasCustom) + ui->directionCB->setCurrentIndex(indexOfCurrent); + if (hasCustom) + ui->directionCB->setCurrentIndex(2); + + blockUpdate = oldVal_blockUpdate; +} + +void TaskExtrudeParameters::addAxisToCombo(App::DocumentObject* linkObj, + std::string linkSubname, QString itemText, bool hasSketch) +{ + this->ui->directionCB->addItem(itemText); + this->axesInList.emplace_back(new App::PropertyLinkSub); + App::PropertyLinkSub& lnk = *(axesInList.back()); + // if we have a face, we leave the link empty since we cannot + // store the face normal as sublink + if (hasSketch) + lnk.setValue(linkObj, std::vector(1, linkSubname)); +} + +void TaskExtrudeParameters::onDirectionCBChanged(int num) +{ + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + + if (axesInList.empty()) + return; + + // we use this scheme for 'num' + // 0: normal to sketch or face + // 1: selection mode + // 2: custom + // 3-x: edges selected in the 3D model + + // check the axis + // when the link is empty we are either in selection mode + // or we are normal to a face + App::PropertyLinkSub& lnk = *(axesInList[num]); + if (num == 1) { + // enter reference selection mode + this->blockConnection(false); + // to distinguish that this is the direction selection + selectionFace = false; + TaskSketchBasedParameters::onSelectReference(true, true, false, true, true); + return; + } + else if (lnk.getValue() != 0) { + if (!extrude->getDocument()->isIn(lnk.getValue())) { + Base::Console().Error("Object was deleted\n"); + return; + } + propReferenceAxis->Paste(lnk); + } + + // in case the user is in selection mode, but changed his mind before selecting anything + exitSelectionMode(); + + // disable AlongSketchNormal when the direction is already normal + if (num == 0) + ui->checkBoxAlongDirection->setEnabled(false); + else + ui->checkBoxAlongDirection->setEnabled(true); + // if custom direction is used, show it + if (num == 2) { + ui->checkBoxDirection->setChecked(true); + extrude->UseCustomVector.setValue(true); + } + else { + extrude->UseCustomVector.setValue(false); + } + // if we dont use custom direction, only allow to show its direction + if (num != 2) { + ui->XDirectionEdit->setEnabled(false); + ui->YDirectionEdit->setEnabled(false); + ui->ZDirectionEdit->setEnabled(false); + } + else { + ui->XDirectionEdit->setEnabled(true); + ui->YDirectionEdit->setEnabled(true); + ui->ZDirectionEdit->setEnabled(true); + } + // recompute and update the direction + extrude->ReferenceAxis.setValue(lnk.getValue(), lnk.getSubValues()); + try { + recomputeFeature(); + } + catch (const Base::Exception& e) { + e.ReportException(); + } + updateDirectionEdits(); +} + +void TaskExtrudeParameters::onAlongSketchNormalChanged(bool on) +{ + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + extrude->AlongSketchNormal.setValue(on); + recomputeFeature(); +} + +void TaskExtrudeParameters::onDirectionToggled(bool on) +{ + if (on) + ui->groupBoxDirection->show(); + else + ui->groupBoxDirection->hide(); +} + +void TaskExtrudeParameters::onXDirectionEditChanged(double len) +{ + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + extrude->Direction.setValue(len, extrude->Direction.getValue().y, extrude->Direction.getValue().z); + recomputeFeature(); + // checking for case of a null vector is done in FeatureExtrude.cpp + // if there was a null vector, the normal vector of the sketch is used. + // therefore the vector component edits must be updated + updateDirectionEdits(); +} + +void TaskExtrudeParameters::onYDirectionEditChanged(double len) +{ + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + extrude->Direction.setValue(extrude->Direction.getValue().x, len, extrude->Direction.getValue().z); + recomputeFeature(); + updateDirectionEdits(); +} + +void TaskExtrudeParameters::onZDirectionEditChanged(double len) +{ + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + extrude->Direction.setValue(extrude->Direction.getValue().x, extrude->Direction.getValue().y, len); + recomputeFeature(); + updateDirectionEdits(); +} + +void TaskExtrudeParameters::updateDirectionEdits() +{ + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + // we don't want to execute the onChanged edits, but just update their contents + ui->XDirectionEdit->blockSignals(true); + ui->YDirectionEdit->blockSignals(true); + ui->ZDirectionEdit->blockSignals(true); + ui->XDirectionEdit->setValue(extrude->Direction.getValue().x); + ui->YDirectionEdit->setValue(extrude->Direction.getValue().y); + ui->ZDirectionEdit->setValue(extrude->Direction.getValue().z); + ui->XDirectionEdit->blockSignals(false); + ui->YDirectionEdit->blockSignals(false); + ui->ZDirectionEdit->blockSignals(false); +} + +void TaskExtrudeParameters::onMidplaneChanged(bool on) +{ + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + extrude->Midplane.setValue(on); + // reversed is not sensible when midplane + ui->checkBoxReversed->setEnabled(!on); + recomputeFeature(); +} + +void TaskExtrudeParameters::onReversedChanged(bool on) +{ + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + extrude->Reversed.setValue(on); + // midplane is not sensible when reversed + ui->checkBoxMidplane->setEnabled(!on); + // update the direction + recomputeFeature(); + updateDirectionEdits(); +} + +void TaskExtrudeParameters::onButtonFace(const bool pressed) +{ + this->blockConnection(!pressed); + + // to distinguish that this is the direction selection + selectionFace = true; + + // only faces are allowed + TaskSketchBasedParameters::onSelectReference(pressed, false, true, false); + + // Update button if onButtonFace() is called explicitly + ui->buttonFace->setChecked(pressed); +} + +void TaskExtrudeParameters::onFaceName(const QString& text) +{ + if (text.isEmpty()) { + // if user cleared the text field then also clear the properties + ui->lineFaceName->setProperty("FeatureName", QVariant()); + ui->lineFaceName->setProperty("FaceName", QVariant()); + } + else { + // expect that the label of an object is used + QStringList parts = text.split(QChar::fromLatin1(':')); + QString label = parts[0]; + QVariant name = objectNameByLabel(label, ui->lineFaceName->property("FeatureName")); + if (name.isValid()) { + parts[0] = name.toString(); + QString uptoface = parts.join(QString::fromLatin1(":")); + ui->lineFaceName->setProperty("FeatureName", name); + ui->lineFaceName->setProperty("FaceName", setUpToFace(uptoface)); + } + else { + ui->lineFaceName->setProperty("FeatureName", QVariant()); + ui->lineFaceName->setProperty("FaceName", QVariant()); + } + } +} + +double TaskExtrudeParameters::getLength(void) const +{ + return ui->lengthEdit->value().getValue(); +} + +double TaskExtrudeParameters::getLength2(void) const +{ + return ui->lengthEdit2->value().getValue(); +} + +double TaskExtrudeParameters::getOffset(void) const +{ + return ui->offsetEdit->value().getValue(); +} + +bool TaskExtrudeParameters::getAlongSketchNormal(void) const +{ + return ui->checkBoxAlongDirection->isChecked(); +} + +bool TaskExtrudeParameters::getCustom(void) const +{ + // index 2 is hardcoded to custom vector + return ui->directionCB->currentIndex() == 2 ? true : false; +} + +std::string TaskExtrudeParameters::getReferenceAxis(void) const +{ + std::vector sub; + App::DocumentObject* obj; + getReferenceAxis(obj, sub); + return buildLinkSingleSubPythonStr(obj, sub); +} + +double TaskExtrudeParameters::getXDirection(void) const +{ + return ui->XDirectionEdit->value(); +} + +double TaskExtrudeParameters::getYDirection(void) const +{ + return ui->YDirectionEdit->value(); +} + +double TaskExtrudeParameters::getZDirection(void) const +{ + return ui->ZDirectionEdit->value(); +} + +bool TaskExtrudeParameters::getReversed(void) const +{ + return ui->checkBoxReversed->isChecked(); +} + +bool TaskExtrudeParameters::getMidplane(void) const +{ + return ui->checkBoxMidplane->isChecked(); +} + +int TaskExtrudeParameters::getMode(void) const +{ + return ui->changeMode->currentIndex(); +} + +QString TaskExtrudeParameters::getFaceName(void) const +{ + // 'Up to face' mode + if (getMode() == 3) { + QVariant featureName = ui->lineFaceName->property("FeatureName"); + if (featureName.isValid()) { + QString faceName = ui->lineFaceName->property("FaceName").toString(); + return getFaceReference(featureName.toString(), faceName); + } + } + return QString::fromLatin1("None"); +} + +void TaskExtrudeParameters::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->lengthEdit->blockSignals(true); + ui->lengthEdit2->blockSignals(true); + ui->offsetEdit->blockSignals(true); + ui->XDirectionEdit->blockSignals(true); + ui->YDirectionEdit->blockSignals(true); + ui->ZDirectionEdit->blockSignals(true); + ui->directionCB->blockSignals(true); + int index = ui->directionCB->currentIndex(); + ui->directionCB->clear(); + ui->directionCB->addItem(tr("Sketch normal")); + ui->directionCB->addItem(tr("Select reference...")); + ui->directionCB->addItem(tr("Custom direction")); + ui->directionCB->setCurrentIndex(index); + ui->lineFaceName->blockSignals(true); + ui->changeMode->blockSignals(true); + ui->retranslateUi(proxy); + translateModeList(ui->changeMode->currentIndex()); + + ui->lineFaceName->setPlaceholderText(tr("No face selected")); + QVariant featureName = ui->lineFaceName->property("FeatureName"); + if (featureName.isValid()) { + QStringList parts = ui->lineFaceName->text().split(QChar::fromLatin1(':')); + QByteArray upToFace = ui->lineFaceName->property("FaceName").toByteArray(); + int faceId = -1; + bool ok = false; + if (upToFace.indexOf("Face") == 0) { + faceId = upToFace.remove(0,4).toInt(&ok); + } + + if (ok) { + ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3") + .arg(parts[0]) + .arg(tr("Face")) + .arg(faceId)); + } + else { + ui->lineFaceName->setText(parts[0]); + } + } + + ui->lengthEdit->blockSignals(false); + ui->lengthEdit2->blockSignals(false); + ui->offsetEdit->blockSignals(false); + ui->XDirectionEdit->blockSignals(false); + ui->YDirectionEdit->blockSignals(false); + ui->ZDirectionEdit->blockSignals(false); + ui->directionCB->blockSignals(false); + ui->lineFaceName->blockSignals(false); + ui->changeMode->blockSignals(false); + } +} + +void TaskExtrudeParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const +{ + if (axesInList.empty()) + throw Base::RuntimeError("Not initialized!"); + + int num = ui->directionCB->currentIndex(); + const App::PropertyLinkSub& lnk = *(axesInList[num]); + if (lnk.getValue() == 0) { + // Note: It is possible that a face of an object is directly padded/pocketed without defining a profile shape + obj = nullptr; + sub.clear(); + } + else { + PartDesign::ProfileBased* pcDirection = static_cast(vp->getObject()); + if (!pcDirection->getDocument()->isIn(lnk.getValue())) + throw Base::RuntimeError("Object was deleted"); + + obj = lnk.getValue(); + sub = lnk.getSubValues(); + } +} + +void TaskExtrudeParameters::saveHistory(void) +{ + // save the user values to history + ui->lengthEdit->pushToHistory(); + ui->lengthEdit2->pushToHistory(); + ui->offsetEdit->pushToHistory(); +} + +void TaskExtrudeParameters::onModeChanged(int) +{ + // implement in sub-class +} + +void TaskExtrudeParameters::updateUI(int) +{ + // implement in sub-class +} + +void TaskExtrudeParameters::translateModeList(int) +{ + // implement in sub-class +} + +#include "moc_TaskExtrudeParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.h b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.h new file mode 100644 index 0000000000..14ad607300 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_TASKVIEW_TaskExtrudeParameters_H +#define GUI_TASKVIEW_TaskExtrudeParameters_H + +#include +#include +#include + +#include "TaskSketchBasedParameters.h" +#include "ViewProviderSketchBased.h" + +class Ui_TaskPadParameters; + +namespace App { +class Property; +} + +namespace PartDesignGui { + + +class TaskExtrudeParameters : public TaskSketchBasedParameters +{ + Q_OBJECT + +public: + TaskExtrudeParameters(ViewProviderSketchBased *SketchBasedView, QWidget *parent, + const std::string& pixmapname, const QString& parname); + ~TaskExtrudeParameters(); + + virtual void saveHistory() override; + + void fillDirectionCombo(); + void addAxisToCombo(App::DocumentObject* linkObj, std::string linkSubname, QString itemText, + bool hasSketch = true); + +protected Q_SLOTS: + void onLengthChanged(double); + void onLength2Changed(double); + void onOffsetChanged(double); + void onDirectionCBChanged(int); + void onAlongSketchNormalChanged(bool); + void onDirectionToggled(bool); + void onXDirectionEditChanged(double); + void onYDirectionEditChanged(double); + void onZDirectionEditChanged(double); + void onMidplaneChanged(bool); + void onReversedChanged(bool); + void onButtonFace(const bool pressed = true); + void onFaceName(const QString& text); + virtual void onModeChanged(int); + +protected: + void setupDialog(bool); + void changeEvent(QEvent *e) override; + App::PropertyLinkSub* propReferenceAxis; + void getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const; + + double getLength(void) const; + double getLength2(void) const; + bool getAlongSketchNormal(void) const; + bool getCustom(void) const; + std::string getReferenceAxis(void) const; + double getXDirection(void) const; + double getYDirection(void) const; + double getZDirection(void) const; + double getOffset(void) const; + bool getReversed(void) const; + bool getMidplane(void) const; + int getMode(void) const; + QString getFaceName(void) const; + void onSelectionChanged(const Gui::SelectionChanges& msg) override; + virtual void translateModeList(int index); + virtual void updateUI(int index); + void updateDirectionEdits(void); + +protected: + QWidget* proxy; + std::unique_ptr ui; + bool selectionFace; + std::vector> axesInList; +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TaskExtrudeParameters_H diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 03651459d5..d193222925 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -47,7 +47,6 @@ #include #include #include -#include "TaskSketchBasedParameters.h" #include "ReferenceSelection.h" using namespace PartDesignGui; @@ -56,158 +55,32 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskPadParameters */ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView, QWidget *parent, bool newObj) - : TaskSketchBasedParameters(PadView, parent, "PartDesign_Pad", tr("Pad parameters")) - , ui(new Ui_TaskPadParameters) + : TaskExtrudeParameters(PadView, parent, "PartDesign_Pad", tr("Pad parameters")) { - // we need a separate container widget to add all controls to - proxy = new QWidget(this); - ui->setupUi(proxy); -#if QT_VERSION >= 0x040700 - ui->lineFaceName->setPlaceholderText(tr("No face selected")); -#endif - - this->groupLayout()->addWidget(proxy); + ui->offsetEdit->setToolTip(tr("Offset from face at which pad will end")); + ui->checkBoxReversed->setToolTip(tr("Reverses pad direction")); // set the history path ui->lengthEdit->setParamGrpPath(QByteArray("User parameter:BaseApp/History/PadLength")); ui->lengthEdit2->setParamGrpPath(QByteArray("User parameter:BaseApp/History/PadLength2")); ui->offsetEdit->setParamGrpPath(QByteArray("User parameter:BaseApp/History/PadOffset")); - // Get the feature data - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - Base::Quantity l = pcPad->Length.getQuantityValue(); - Base::Quantity l2 = pcPad->Length2.getQuantityValue(); - bool alongNormal = pcPad->AlongSketchNormal.getValue(); - bool useCustom = pcPad->UseCustomVector.getValue(); - double xs = pcPad->Direction.getValue().x; - double ys = pcPad->Direction.getValue().y; - double zs = pcPad->Direction.getValue().z; - Base::Quantity off = pcPad->Offset.getQuantityValue(); - bool midplane = pcPad->Midplane.getValue(); - bool reversed = pcPad->Reversed.getValue(); - int index = pcPad->Type.getValue(); // must extract value here, clear() kills it! - App::DocumentObject* obj = pcPad->UpToFace.getValue(); - std::vector subStrings = pcPad->UpToFace.getSubValues(); - std::string upToFace; - int faceId = -1; - if ((obj != NULL) && !subStrings.empty()) { - upToFace = subStrings.front(); - if (upToFace.substr(0,4) == "Face") - faceId = std::atoi(&upToFace[4]); - } + setupDialog(newObj); +} - // set decimals for the direction edits - // do this here before the edits are filed to avoid rounding mistakes - int UserDecimals = Base::UnitsApi::getDecimals(); - ui->XDirectionEdit->setDecimals(UserDecimals); - ui->YDirectionEdit->setDecimals(UserDecimals); - ui->ZDirectionEdit->setDecimals(UserDecimals); - - // Fill data into dialog elements - // the direction combobox is later filled in updateUI() - ui->lengthEdit->setValue(l); - ui->lengthEdit2->setValue(l2); - ui->checkBoxAlongDirection->setChecked(alongNormal); - ui->checkBoxDirection->setChecked(useCustom); - onDirectionToggled(useCustom); - // disable to change the direction if not custom - if (!useCustom) { - ui->XDirectionEdit->setEnabled(false); - ui->YDirectionEdit->setEnabled(false); - ui->ZDirectionEdit->setEnabled(false); - } - ui->XDirectionEdit->setValue(xs); - ui->YDirectionEdit->setValue(ys); - ui->ZDirectionEdit->setValue(zs); - ui->offsetEdit->setValue(off); - - // Bind input fields to properties - ui->lengthEdit->bind(pcPad->Length); - ui->lengthEdit2->bind(pcPad->Length2); - ui->XDirectionEdit->bind(App::ObjectIdentifier::parse(pcPad, std::string("Direction.x"))); - ui->YDirectionEdit->bind(App::ObjectIdentifier::parse(pcPad, std::string("Direction.y"))); - ui->ZDirectionEdit->bind(App::ObjectIdentifier::parse(pcPad, std::string("Direction.z"))); - ui->offsetEdit->bind(pcPad->Offset); - - ui->checkBoxMidplane->setChecked(midplane); - // According to bug #0000521 the reversed option - // shouldn't be de-activated if the pad has a support face - ui->checkBoxReversed->setChecked(reversed); - - // Set object labels - if (obj && PartDesign::Feature::isDatum(obj)) { - ui->lineFaceName->setText(QString::fromUtf8(obj->Label.getValue())); - ui->lineFaceName->setProperty("FeatureName", QByteArray(obj->getNameInDocument())); - } - else if (obj && faceId >= 0) { - ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3") - .arg(QString::fromUtf8(obj->Label.getValue())) - .arg(tr("Face")) - .arg(faceId)); - ui->lineFaceName->setProperty("FeatureName", QByteArray(obj->getNameInDocument())); - } - else { - ui->lineFaceName->clear(); - ui->lineFaceName->setProperty("FeatureName", QVariant()); - } - ui->lineFaceName->setProperty("FaceName", QByteArray(upToFace.c_str())); +TaskPadParameters::~TaskPadParameters() +{ +} +void TaskPadParameters::translateModeList(int index) +{ ui->changeMode->clear(); - ui->changeMode->insertItem(0, tr("Dimension")); - ui->changeMode->insertItem(1, tr("To last")); - ui->changeMode->insertItem(2, tr("To first")); - ui->changeMode->insertItem(3, tr("Up to face")); - ui->changeMode->insertItem(4, tr("Two dimensions")); + ui->changeMode->addItem(tr("Dimension")); + ui->changeMode->addItem(tr("To last")); + ui->changeMode->addItem(tr("To first")); + ui->changeMode->addItem(tr("Up to face")); + ui->changeMode->addItem(tr("Two dimensions")); ui->changeMode->setCurrentIndex(index); - - QMetaObject::connectSlotsByName(this); - - connect(ui->lengthEdit, SIGNAL(valueChanged(double)), - this, SLOT(onLengthChanged(double))); - connect(ui->lengthEdit2, SIGNAL(valueChanged(double)), - this, SLOT(onLength2Changed(double))); - connect(ui->directionCB, SIGNAL(activated(int)), - this, SLOT(onDirectionCBChanged(int))); - connect(ui->checkBoxAlongDirection, SIGNAL(toggled(bool)), - this, SLOT(onAlongSketchNormalChanged(bool))); - connect(ui->checkBoxDirection, SIGNAL(toggled(bool)), - this, SLOT(onDirectionToggled(bool))); - connect(ui->XDirectionEdit, SIGNAL(valueChanged(double)), - this, SLOT(onXDirectionEditChanged(double))); - connect(ui->YDirectionEdit, SIGNAL(valueChanged(double)), - this, SLOT(onYDirectionEditChanged(double))); - connect(ui->ZDirectionEdit, SIGNAL(valueChanged(double)), - this, SLOT(onZDirectionEditChanged(double))); - connect(ui->offsetEdit, SIGNAL(valueChanged(double)), - this, SLOT(onOffsetChanged(double))); - connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)), - this, SLOT(onMidplaneChanged(bool))); - connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), - this, SLOT(onReversedChanged(bool))); - connect(ui->changeMode, SIGNAL(currentIndexChanged(int)), - this, SLOT(onModeChanged(int))); - connect(ui->buttonFace, SIGNAL(clicked()), - this, SLOT(onButtonFace())); - connect(ui->lineFaceName, SIGNAL(textEdited(QString)), - this, SLOT(onFaceName(QString))); - connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), - this, SLOT(onUpdateView(bool))); - - this->propReferenceAxis = &(pcPad->ReferenceAxis); - - // Due to signals attached after changes took took into effect we should update the UI now. - updateUI(index); - - // if it is a newly created object use the last value of the history - // TODO: newObj doesn't supplied normally by any caller (2015-07-24, Fat-Zer) - if (newObj) { - ui->lengthEdit->setToLastUsedValue(); - ui->lengthEdit->selectNumber(); - ui->lengthEdit2->setToLastUsedValue(); - ui->lengthEdit2->selectNumber(); - ui->offsetEdit->setToLastUsedValue(); - ui->offsetEdit->selectNumber(); - } } void TaskPadParameters::updateUI(int index) @@ -293,307 +166,6 @@ void TaskPadParameters::updateUI(int index) } } -void TaskPadParameters::onSelectionChanged(const Gui::SelectionChanges& msg) -{ - if (msg.Type == Gui::SelectionChanges::AddSelection) { - // if we have an edge selection for the pad direction - if (!selectionFace) { - std::vector edge; - App::DocumentObject* selObj; - if (getReferencedSelection(vp->getObject(), msg, selObj, edge) && selObj) { - exitSelectionMode(); - propReferenceAxis->setValue(selObj, edge); - recomputeFeature(); - // update direction combobox - fillDirectionCombo(); - } - } - else { // if we have a selection of a face - QString refText = onAddSelection(msg); - if (refText.length() > 0) { - ui->lineFaceName->blockSignals(true); - ui->lineFaceName->setText(refText); - ui->lineFaceName->setProperty("FeatureName", QByteArray(msg.pObjectName)); - ui->lineFaceName->setProperty("FaceName", QByteArray(msg.pSubName)); - ui->lineFaceName->blockSignals(false); - // Turn off reference selection mode - onButtonFace(false); - } - else { - ui->lineFaceName->blockSignals(true); - ui->lineFaceName->clear(); - ui->lineFaceName->setProperty("FeatureName", QVariant()); - ui->lineFaceName->setProperty("FaceName", QVariant()); - ui->lineFaceName->blockSignals(false); - } - } - } else if (msg.Type == Gui::SelectionChanges::ClrSelection && selectionFace) { - ui->lineFaceName->blockSignals(true); - ui->lineFaceName->clear(); - ui->lineFaceName->setProperty("FeatureName", QVariant()); - ui->lineFaceName->setProperty("FaceName", QVariant()); - ui->lineFaceName->blockSignals(false); - } -} - -void TaskPadParameters::onLengthChanged(double len) -{ - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - pcPad->Length.setValue(len); - recomputeFeature(); -} - -void TaskPadParameters::onLength2Changed(double len) -{ - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - pcPad->Length2.setValue(len); - recomputeFeature(); -} - -void TaskPadParameters::fillDirectionCombo() -{ - bool oldVal_blockUpdate = blockUpdate; - blockUpdate = true; - - if (axesInList.empty()) { - bool hasFace = false; - ui->directionCB->clear(); - // we can have sketches or faces - // for sketches just get the sketch normal - PartDesign::ProfileBased* pcFeat = static_cast(vp->getObject()); - Part::Part2DObject* pcSketch = dynamic_cast(pcFeat->Profile.getValue()); - // for faces we test if it is verified and if we can get its normal - if (!pcSketch) { - try { - Part::Feature* pcFeature = pcFeat->getVerifiedObject(); - Base::Vector3d SketchVector = pcFeat->getProfileNormal(); - Q_UNUSED(pcFeature) - Q_UNUSED(SketchVector) - hasFace = true; - } - catch (const Base::Exception& e) { - new App::DocumentObjectExecReturn(e.what()); - } - } - if (pcSketch) - addAxisToCombo(pcSketch, "N_Axis", tr("Sketch normal")); - else if (hasFace) - addAxisToCombo(pcFeat->Profile.getValue(), std::string(), tr("Face normal"), false); - // add the other entries - addAxisToCombo(0, std::string(), tr("Select reference...")); - // we start with the sketch normal as proposal for the custom direction - if (pcSketch) - addAxisToCombo(pcSketch, "N_Axis", tr("Custom direction")); - else if (hasFace) - addAxisToCombo(pcFeat->Profile.getValue(), std::string(), tr("Custom direction"), false); - } - - // add current link, if not in list - // first, figure out the item number for current axis - int indexOfCurrent = -1; - App::DocumentObject* ax = propReferenceAxis->getValue(); - const std::vector& subList = propReferenceAxis->getSubValues(); - for (size_t i = 0; i < axesInList.size(); i++) { - if (ax == axesInList[i]->getValue() && subList == axesInList[i]->getSubValues()) { - indexOfCurrent = i; - break; - } - } - // if the axis is not yet listed in the combobox - if (indexOfCurrent == -1 && ax) { - assert(subList.size() <= 1); - std::string sub; - if (!subList.empty()) - sub = subList[0]; - addAxisToCombo(ax, sub, getRefStr(ax, subList)); - indexOfCurrent = axesInList.size() - 1; - // the axis is not the normal, thus enable along direction - ui->checkBoxAlongDirection->setEnabled(true); - // we don't have custom direction thus disable its settings - ui->XDirectionEdit->setEnabled(false); - ui->YDirectionEdit->setEnabled(false); - ui->ZDirectionEdit->setEnabled(false); - } - - // highlight either current index or set custom direction - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - bool hasCustom = pcPad->UseCustomVector.getValue(); - if (indexOfCurrent != -1 && !hasCustom) - ui->directionCB->setCurrentIndex(indexOfCurrent); - if (hasCustom) - ui->directionCB->setCurrentIndex(2); - - blockUpdate = oldVal_blockUpdate; -} - -void TaskPadParameters::addAxisToCombo(App::DocumentObject* linkObj, - std::string linkSubname, QString itemText, bool hasSketch) -{ - this->ui->directionCB->addItem(itemText); - this->axesInList.emplace_back(new App::PropertyLinkSub); - App::PropertyLinkSub& lnk = *(axesInList.back()); - // if we have a face, we leave the link empty since we cannot - // store the face normal as sublink - if (hasSketch) - lnk.setValue(linkObj, std::vector(1, linkSubname)); -} - -void TaskPadParameters::onDirectionCBChanged(int num) -{ - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - - if (axesInList.empty()) - return; - - // we use this scheme for 'num' - // 0: normal to sketch or face - // 1: selection mode - // 2: custom - // 3-x: edges selected in the 3D model - - // check the axis - // when the link is empty we are either in selection mode - // or we are normal to a face - App::PropertyLinkSub& lnk = *(axesInList[num]); - if (num == 1) { - // enter reference selection mode - this->blockConnection(false); - // to distinguish that this is the direction selection - selectionFace = false; - TaskSketchBasedParameters::onSelectReference(true, true, false, true, true); - return; - } - else if (lnk.getValue() != 0) { - if (!pcPad->getDocument()->isIn(lnk.getValue())) { - Base::Console().Error("Object was deleted\n"); - return; - } - propReferenceAxis->Paste(lnk); - } - - // in case the user is in selection mode, but changed his mind before selecting anything - exitSelectionMode(); - - // disable AlongSketchNormal when the direction is already normal - if (num == 0) - ui->checkBoxAlongDirection->setEnabled(false); - else - ui->checkBoxAlongDirection->setEnabled(true); - // if custom direction is used, show it - if (num == 2) { - ui->checkBoxDirection->setChecked(true); - pcPad->UseCustomVector.setValue(true); - } - else { - pcPad->UseCustomVector.setValue(false); - } - // if we dont use custom direction, only allow to show its direction - if (num != 2) { - ui->XDirectionEdit->setEnabled(false); - ui->YDirectionEdit->setEnabled(false); - ui->ZDirectionEdit->setEnabled(false); - } - else { - ui->XDirectionEdit->setEnabled(true); - ui->YDirectionEdit->setEnabled(true); - ui->ZDirectionEdit->setEnabled(true); - } - // recompute and update the direction - pcPad->ReferenceAxis.setValue(lnk.getValue(), lnk.getSubValues()); - try { - recomputeFeature(); - } - catch (const Base::Exception& e) { - e.ReportException(); - } - updateDirectionEdits(); -} - -void TaskPadParameters::onAlongSketchNormalChanged(bool on) -{ - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - pcPad->AlongSketchNormal.setValue(on); - recomputeFeature(); -} - -void TaskPadParameters::onDirectionToggled(bool on) -{ - if (on) - ui->groupBoxDirection->show(); - else - ui->groupBoxDirection->hide(); -} - -void TaskPadParameters::onXDirectionEditChanged(double len) -{ - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - pcPad->Direction.setValue(len, pcPad->Direction.getValue().y, pcPad->Direction.getValue().z); - recomputeFeature(); - // checking for case of a null vector is done in FeatureExtrude.cpp - // if there was a null vector, the normal vector of the sketch is used. - // therefore the vector component edits must be updated - updateDirectionEdits(); -} - -void TaskPadParameters::onYDirectionEditChanged(double len) -{ - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - pcPad->Direction.setValue(pcPad->Direction.getValue().x, len, pcPad->Direction.getValue().z); - recomputeFeature(); - updateDirectionEdits(); -} - -void TaskPadParameters::onZDirectionEditChanged(double len) -{ - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - pcPad->Direction.setValue(pcPad->Direction.getValue().x, pcPad->Direction.getValue().y, len); - recomputeFeature(); - updateDirectionEdits(); -} - -void TaskPadParameters::updateDirectionEdits() -{ - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - // we don't want to execute the onChanged edits, but just update their contents - ui->XDirectionEdit->blockSignals(true); - ui->YDirectionEdit->blockSignals(true); - ui->ZDirectionEdit->blockSignals(true); - ui->XDirectionEdit->setValue(pcPad->Direction.getValue().x); - ui->YDirectionEdit->setValue(pcPad->Direction.getValue().y); - ui->ZDirectionEdit->setValue(pcPad->Direction.getValue().z); - ui->XDirectionEdit->blockSignals(false); - ui->YDirectionEdit->blockSignals(false); - ui->ZDirectionEdit->blockSignals(false); -} - -void TaskPadParameters::onOffsetChanged(double len) -{ - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - pcPad->Offset.setValue(len); - recomputeFeature(); -} - -void TaskPadParameters::onMidplaneChanged(bool on) -{ - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - pcPad->Midplane.setValue(on); - // reversed is not sensible when midplane - ui->checkBoxReversed->setEnabled(!on); - recomputeFeature(); -} - -void TaskPadParameters::onReversedChanged(bool on) -{ - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - pcPad->Reversed.setValue(on); - // midplane is not sensible when reversed - ui->checkBoxMidplane->setEnabled(!on); - // update the direction - recomputeFeature(); - updateDirectionEdits(); - -} - void TaskPadParameters::onModeChanged(int index) { PartDesign::Pad* pcPad = static_cast(vp->getObject()); @@ -615,220 +187,6 @@ void TaskPadParameters::onModeChanged(int index) recomputeFeature(); } -void TaskPadParameters::onButtonFace(const bool pressed) -{ - this->blockConnection(!pressed); - - // to distinguish that this is the direction selection - selectionFace = true; - - // only faces are allowed - TaskSketchBasedParameters::onSelectReference(pressed, false, true, false); - - // Update button if onButtonFace() is called explicitly - ui->buttonFace->setChecked(pressed); -} - -void TaskPadParameters::onFaceName(const QString& text) -{ - if (text.isEmpty()) { - // if user cleared the text field then also clear the properties - ui->lineFaceName->setProperty("FeatureName", QVariant()); - ui->lineFaceName->setProperty("FaceName", QVariant()); - } - else { - // expect that the label of an object is used - QStringList parts = text.split(QChar::fromLatin1(':')); - QString label = parts[0]; - QVariant name = objectNameByLabel(label, ui->lineFaceName->property("FeatureName")); - if (name.isValid()) { - parts[0] = name.toString(); - QString uptoface = parts.join(QString::fromLatin1(":")); - ui->lineFaceName->setProperty("FeatureName", name); - ui->lineFaceName->setProperty("FaceName", setUpToFace(uptoface)); - } - else { - ui->lineFaceName->setProperty("FeatureName", QVariant()); - ui->lineFaceName->setProperty("FaceName", QVariant()); - } - } -} - -double TaskPadParameters::getLength(void) const -{ - return ui->lengthEdit->value().getValue(); -} - -double TaskPadParameters::getLength2(void) const -{ - return ui->lengthEdit2->value().getValue(); -} - -bool TaskPadParameters::getAlongSketchNormal(void) const -{ - return ui->checkBoxAlongDirection->isChecked(); -} - -bool TaskPadParameters::getCustom(void) const -{ - // index 2 is hardcoded to custom vector - return ui->directionCB->currentIndex() == 2 ? true : false; -} - -std::string TaskPadParameters::getReferenceAxis(void) const -{ - std::vector sub; - App::DocumentObject* obj; - getReferenceAxis(obj, sub); - return buildLinkSingleSubPythonStr(obj, sub); -} - -double TaskPadParameters::getXDirection(void) const -{ - return ui->XDirectionEdit->value(); -} - -double TaskPadParameters::getYDirection(void) const -{ - return ui->YDirectionEdit->value(); -} - -double TaskPadParameters::getZDirection(void) const -{ - return ui->ZDirectionEdit->value(); -} - -double TaskPadParameters::getOffset(void) const -{ - return ui->offsetEdit->value().getValue(); -} - -bool TaskPadParameters::getReversed(void) const -{ - return ui->checkBoxReversed->isChecked(); -} - -bool TaskPadParameters::getMidplane(void) const -{ - return ui->checkBoxMidplane->isChecked(); -} - -int TaskPadParameters::getMode(void) const -{ - return ui->changeMode->currentIndex(); -} - -QString TaskPadParameters::getFaceName(void) const -{ - // 'Up to face' mode - if (getMode() == 3) { - QVariant featureName = ui->lineFaceName->property("FeatureName"); - if (featureName.isValid()) { - QString faceName = ui->lineFaceName->property("FaceName").toString(); - return getFaceReference(featureName.toString(), faceName); - } - } - return QString::fromLatin1("None"); -} - -TaskPadParameters::~TaskPadParameters() -{ -} - -void TaskPadParameters::changeEvent(QEvent *e) -{ - TaskBox::changeEvent(e); - if (e->type() == QEvent::LanguageChange) { - ui->lengthEdit->blockSignals(true); - ui->lengthEdit2->blockSignals(true); - ui->XDirectionEdit->blockSignals(true); - ui->YDirectionEdit->blockSignals(true); - ui->ZDirectionEdit->blockSignals(true); - ui->directionCB->blockSignals(true); - int index = ui->directionCB->currentIndex(); - ui->directionCB->clear(); - ui->directionCB->addItem(tr("Sketch normal")); - ui->directionCB->addItem(tr("Select reference...")); - ui->directionCB->addItem(tr("Custom direction")); - ui->directionCB->setCurrentIndex(index); - ui->offsetEdit->blockSignals(true); - ui->lineFaceName->blockSignals(true); - ui->changeMode->blockSignals(true); - index = ui->changeMode->currentIndex(); - ui->retranslateUi(proxy); - ui->changeMode->clear(); - ui->changeMode->addItem(tr("Dimension")); - ui->changeMode->addItem(tr("To last")); - ui->changeMode->addItem(tr("To first")); - ui->changeMode->addItem(tr("Up to face")); - ui->changeMode->addItem(tr("Two dimensions")); - ui->changeMode->setCurrentIndex(index); - - ui->lineFaceName->setPlaceholderText(tr("No face selected")); - QVariant featureName = ui->lineFaceName->property("FeatureName"); - if (featureName.isValid()) { - QStringList parts = ui->lineFaceName->text().split(QChar::fromLatin1(':')); - QByteArray upToFace = ui->lineFaceName->property("FaceName").toByteArray(); - int faceId = -1; - bool ok = false; - if (upToFace.indexOf("Face") == 0) { - faceId = upToFace.remove(0,4).toInt(&ok); - } - - if (ok) { - ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3") - .arg(parts[0]) - .arg(tr("Face")) - .arg(faceId)); - } - else { - ui->lineFaceName->setText(parts[0]); - } - } - - ui->lengthEdit->blockSignals(false); - ui->lengthEdit2->blockSignals(false); - ui->XDirectionEdit->blockSignals(false); - ui->YDirectionEdit->blockSignals(false); - ui->ZDirectionEdit->blockSignals(false); - ui->directionCB->blockSignals(false); - ui->offsetEdit->blockSignals(false); - ui->lineFaceName->blockSignals(false); - ui->changeMode->blockSignals(false); - } -} - -void TaskPadParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const -{ - if (axesInList.empty()) - throw Base::RuntimeError("Not initialized!"); - - int num = ui->directionCB->currentIndex(); - const App::PropertyLinkSub& lnk = *(axesInList[num]); - if (lnk.getValue() == 0) { - // Note: Is is possible that a face of an object is directly padded without defining a profile shape - obj = nullptr; - sub.clear(); - //throw Base::RuntimeError("Still in reference selection mode; reference wasn't selected yet"); - } - else { - PartDesign::ProfileBased* pcDirection = static_cast(vp->getObject()); - if (!pcDirection->getDocument()->isIn(lnk.getValue())) - throw Base::RuntimeError("Object was deleted"); - - obj = lnk.getValue(); - sub = lnk.getSubValues(); - } -} - -void TaskPadParameters::saveHistory(void) -{ - // save the user values to history - ui->lengthEdit->pushToHistory(); - ui->lengthEdit2->pushToHistory(); - ui->offsetEdit->pushToHistory(); -} - void TaskPadParameters::apply() { auto obj = vp->getObject(); diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.h b/src/Mod/PartDesign/Gui/TaskPadParameters.h index 174fe43fad..a3701e1588 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.h @@ -28,11 +28,9 @@ #include #include -#include "TaskSketchBasedParameters.h" +#include "TaskExtrudeParameters.h" #include "ViewProviderPad.h" -class Ui_TaskPadParameters; - namespace App { class Property; } @@ -44,7 +42,7 @@ class ViewProvider; namespace PartDesignGui { -class TaskPadParameters : public TaskSketchBasedParameters +class TaskPadParameters : public TaskExtrudeParameters { Q_OBJECT @@ -52,57 +50,12 @@ public: TaskPadParameters(ViewProviderPad *PadView, QWidget *parent = 0, bool newObj=false); ~TaskPadParameters(); - virtual void saveHistory() override; virtual void apply() override; - void fillDirectionCombo(); - void addAxisToCombo(App::DocumentObject* linkObj, std::string linkSubname, QString itemText, - bool hasSketch = true); - -private Q_SLOTS: - void onLengthChanged(double); - void onLength2Changed(double); - void onDirectionCBChanged(int); - void onAlongSketchNormalChanged(bool); - void onDirectionToggled(bool); - void onXDirectionEditChanged(double); - void onYDirectionEditChanged(double); - void onZDirectionEditChanged(double); - void onOffsetChanged(double); - void onMidplaneChanged(bool); - void onReversedChanged(bool); - void onButtonFace(const bool pressed = true); - void onFaceName(const QString& text); - void onModeChanged(int); - -protected: - void changeEvent(QEvent *e) override; - App::PropertyLinkSub* propReferenceAxis; - void getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const; - private: - double getLength(void) const; - double getLength2(void) const; - bool getAlongSketchNormal(void) const; - bool getCustom(void) const; - std::string getReferenceAxis(void) const; - double getXDirection(void) const; - double getYDirection(void) const; - double getZDirection(void) const; - double getOffset(void) const; - bool getReversed(void) const; - bool getMidplane(void) const; - int getMode(void) const; - QString getFaceName(void) const; - void onSelectionChanged(const Gui::SelectionChanges& msg) override; - void updateUI(int index); - void updateDirectionEdits(void); - -private: - QWidget* proxy; - std::unique_ptr ui; - bool selectionFace; - std::vector> axesInList; + void onModeChanged(int index) override; + void translateModeList(int index) override; + void updateUI(int index) override; }; /// simulation dialog for the TaskView diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.ui b/src/Mod/PartDesign/Gui/TaskPadParameters.ui index 026cd8cd77..50967168dc 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.ui @@ -58,9 +58,6 @@
- - Offset from face at which pad will end - false @@ -256,9 +253,6 @@ measured along the specified direction - - Reverses pad direction - Reversed diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index c41d0d9a0c..d31f2e769d 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -30,7 +30,7 @@ # include #endif -#include "ui_TaskPocketParameters.h" +#include "ui_TaskPadParameters.h" #include "TaskPocketParameters.h" #include #include @@ -45,7 +45,6 @@ #include #include #include -#include "TaskSketchBasedParameters.h" #include "ReferenceSelection.h" using namespace PartDesignGui; @@ -54,157 +53,33 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskPocketParameters */ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidget *parent, bool newObj) - : TaskSketchBasedParameters(PocketView, parent, "PartDesign_Pocket", tr("Pocket parameters")) - , ui(new Ui_TaskPocketParameters) + : TaskExtrudeParameters(PocketView, parent, "PartDesign_Pocket", tr("Pocket parameters")) , oldLength(0) { - // we need a separate container widget to add all controls to - proxy = new QWidget(this); - ui->setupUi(proxy); -#if QT_VERSION >= 0x040700 - ui->lineFaceName->setPlaceholderText(tr("No face selected")); -#endif - - this->groupLayout()->addWidget(proxy); + ui->offsetEdit->setToolTip(tr("Offset from face at which pocket will end")); + ui->checkBoxReversed->setToolTip(tr("Reverses pocket direction")); // set the history path ui->lengthEdit->setParamGrpPath(QByteArray("User parameter:BaseApp/History/PocketLength")); ui->lengthEdit2->setParamGrpPath(QByteArray("User parameter:BaseApp/History/PocketLength2")); ui->offsetEdit->setParamGrpPath(QByteArray("User parameter:BaseApp/History/PocketOffset")); - // Get the feature data - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - Base::Quantity l = pcPocket->Length.getQuantityValue(); - Base::Quantity l2 = pcPocket->Length2.getQuantityValue(); - Base::Quantity off = pcPocket->Offset.getQuantityValue(); - bool alongNormal = pcPocket->AlongSketchNormal.getValue(); - bool useCustom = pcPocket->UseCustomVector.getValue(); - double xs = pcPocket->Direction.getValue().x; - double ys = pcPocket->Direction.getValue().y; - double zs = pcPocket->Direction.getValue().z; - bool midplane = pcPocket->Midplane.getValue(); - bool reversed = pcPocket->Reversed.getValue(); - int index = pcPocket->Type.getValue(); // must extract value here, clear() kills it! - App::DocumentObject* obj = pcPocket->UpToFace.getValue(); - std::vector subStrings = pcPocket->UpToFace.getSubValues(); - std::string upToFace; - int faceId = -1; - if ((obj != NULL) && !subStrings.empty()) { - upToFace = subStrings.front(); - if (upToFace.substr(0,4) == "Face") - faceId = std::atoi(&upToFace[4]); - } + setupDialog(newObj); +} - // set decimals for the direction edits - // do this here before the edits are filed to avoid rounding mistakes - int UserDecimals = Base::UnitsApi::getDecimals(); - ui->XDirectionEdit->setDecimals(UserDecimals); - ui->YDirectionEdit->setDecimals(UserDecimals); - ui->ZDirectionEdit->setDecimals(UserDecimals); - - // Fill data into dialog elements - // the direction combobox is later filled in updateUI() - ui->lengthEdit->setValue(l); - ui->lengthEdit2->setValue(l2); - ui->offsetEdit->setValue(off); - ui->checkBoxAlongDirection->setChecked(alongNormal); - ui->checkBoxDirection->setChecked(useCustom); - onDirectionToggled(useCustom); - // disable to change the direction if not custom - if (!useCustom) { - ui->XDirectionEdit->setEnabled(false); - ui->YDirectionEdit->setEnabled(false); - ui->ZDirectionEdit->setEnabled(false); - } - ui->XDirectionEdit->setValue(xs); - ui->YDirectionEdit->setValue(ys); - ui->ZDirectionEdit->setValue(zs); - ui->checkBoxMidplane->setChecked(midplane); - ui->checkBoxReversed->setChecked(reversed); - - // Set object labels - if (obj && PartDesign::Feature::isDatum(obj)) { - ui->lineFaceName->setText(QString::fromUtf8(obj->Label.getValue())); - ui->lineFaceName->setProperty("FeatureName", QByteArray(obj->getNameInDocument())); - } - else if (obj && faceId >= 0) { - ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3") - .arg(QString::fromUtf8(obj->Label.getValue())) - .arg(tr("Face")) - .arg(faceId)); - ui->lineFaceName->setProperty("FeatureName", QByteArray(obj->getNameInDocument())); - } - else { - ui->lineFaceName->clear(); - ui->lineFaceName->setProperty("FeatureName", QVariant()); - } - - ui->lineFaceName->setProperty("FaceName", QByteArray(upToFace.c_str())); +TaskPocketParameters::~TaskPocketParameters() +{ +} +void TaskPocketParameters::translateModeList(int index) +{ ui->changeMode->clear(); - ui->changeMode->insertItem(0, tr("Dimension")); - ui->changeMode->insertItem(1, tr("Through all")); - ui->changeMode->insertItem(2, tr("To first")); - ui->changeMode->insertItem(3, tr("Up to face")); - ui->changeMode->insertItem(4, tr("Two dimensions")); + ui->changeMode->addItem(tr("Dimension")); + ui->changeMode->addItem(tr("Through all")); + ui->changeMode->addItem(tr("To first")); + ui->changeMode->addItem(tr("Up to face")); + ui->changeMode->addItem(tr("Two dimensions")); ui->changeMode->setCurrentIndex(index); - - // Bind input fields to properties - ui->lengthEdit->bind(pcPocket->Length); - ui->lengthEdit2->bind(pcPocket->Length2); - ui->offsetEdit->bind(pcPocket->Offset); - ui->XDirectionEdit->bind(App::ObjectIdentifier::parse(pcPocket, std::string("Direction.x"))); - ui->YDirectionEdit->bind(App::ObjectIdentifier::parse(pcPocket, std::string("Direction.y"))); - ui->ZDirectionEdit->bind(App::ObjectIdentifier::parse(pcPocket, std::string("Direction.z"))); - - QMetaObject::connectSlotsByName(this); - - connect(ui->lengthEdit, SIGNAL(valueChanged(double)), - this, SLOT(onLengthChanged(double))); - connect(ui->lengthEdit2, SIGNAL(valueChanged(double)), - this, SLOT(onLength2Changed(double))); - connect(ui->offsetEdit, SIGNAL(valueChanged(double)), - this, SLOT(onOffsetChanged(double))); - connect(ui->directionCB, SIGNAL(activated(int)), - this, SLOT(onDirectionCBChanged(int))); - connect(ui->checkBoxAlongDirection, SIGNAL(toggled(bool)), - this, SLOT(onAlongSketchNormalChanged(bool))); - connect(ui->checkBoxDirection, SIGNAL(toggled(bool)), - this, SLOT(onDirectionToggled(bool))); - connect(ui->XDirectionEdit, SIGNAL(valueChanged(double)), - this, SLOT(onXDirectionEditChanged(double))); - connect(ui->YDirectionEdit, SIGNAL(valueChanged(double)), - this, SLOT(onYDirectionEditChanged(double))); - connect(ui->ZDirectionEdit, SIGNAL(valueChanged(double)), - this, SLOT(onZDirectionEditChanged(double))); - connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)), - this, SLOT(onMidplaneChanged(bool))); - connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), - this, SLOT(onReversedChanged(bool))); - connect(ui->changeMode, SIGNAL(currentIndexChanged(int)), - this, SLOT(onModeChanged(int))); - connect(ui->buttonFace, SIGNAL(clicked()), - this, SLOT(onButtonFace())); - connect(ui->lineFaceName, SIGNAL(textEdited(QString)), - this, SLOT(onFaceName(QString))); - connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), - this, SLOT(onUpdateView(bool))); - - this->propReferenceAxis = &(pcPocket->ReferenceAxis); - - // Due to signals attached after changes took took into effect we should update the UI now. - updateUI(index); - - // if it is a newly created object use the last value of the history - // TODO: newObj doesn't supplied normally by any caller (2015-07-24, Fat-Zer) - if (newObj){ - ui->lengthEdit->setToLastUsedValue(); - ui->lengthEdit->selectNumber(); - ui->lengthEdit2->setToLastUsedValue(); - ui->lengthEdit2->selectNumber(); - ui->offsetEdit->setToLastUsedValue(); - ui->offsetEdit->selectNumber(); - } } void TaskPocketParameters::updateUI(int index) @@ -213,6 +88,7 @@ void TaskPocketParameters::updateUI(int index) fillDirectionCombo(); // disable/hide everything unless we are sure we don't need it + // exception: the direction parameters are in any case visible bool isLengthEditVisible = false; bool isLengthEdit2Visible = false; bool isOffsetEditVisible = false; @@ -289,307 +165,6 @@ void TaskPocketParameters::updateUI(int index) } } -void TaskPocketParameters::onSelectionChanged(const Gui::SelectionChanges& msg) -{ - if (msg.Type == Gui::SelectionChanges::AddSelection) { - // if we have an edge selection for the pocket direction - if (!selectionFace) { - std::vector edge; - App::DocumentObject* selObj; - if (getReferencedSelection(vp->getObject(), msg, selObj, edge) && selObj) { - exitSelectionMode(); - propReferenceAxis->setValue(selObj, edge); - recomputeFeature(); - // update direction combobox - fillDirectionCombo(); - } - } - else { // if we have a selection of a face - QString refText = onAddSelection(msg); - if (refText.length() > 0) { - ui->lineFaceName->blockSignals(true); - ui->lineFaceName->setText(refText); - ui->lineFaceName->setProperty("FeatureName", QByteArray(msg.pObjectName)); - ui->lineFaceName->setProperty("FaceName", QByteArray(msg.pSubName)); - ui->lineFaceName->blockSignals(false); - // Turn off reference selection mode - onButtonFace(false); - } - else { - ui->lineFaceName->blockSignals(true); - ui->lineFaceName->clear(); - ui->lineFaceName->setProperty("FeatureName", QVariant()); - ui->lineFaceName->setProperty("FaceName", QVariant()); - ui->lineFaceName->blockSignals(false); - } - } - } else if (msg.Type == Gui::SelectionChanges::ClrSelection) { - ui->lineFaceName->blockSignals(true); - ui->lineFaceName->clear(); - ui->lineFaceName->setProperty("FeatureName", QVariant()); - ui->lineFaceName->setProperty("FaceName", QVariant()); - ui->lineFaceName->blockSignals(false); - } -} - -void TaskPocketParameters::onLengthChanged(double len) -{ - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - pcPocket->Length.setValue(len); - recomputeFeature(); -} - -void TaskPocketParameters::onLength2Changed(double len) -{ - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - pcPocket->Length2.setValue(len); - recomputeFeature(); -} - -void TaskPocketParameters::onOffsetChanged(double len) -{ - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - pcPocket->Offset.setValue(len); - recomputeFeature(); -} - -void TaskPocketParameters::fillDirectionCombo() -{ - bool oldVal_blockUpdate = blockUpdate; - blockUpdate = true; - - if (axesInList.empty()) { - bool hasFace = false; - ui->directionCB->clear(); - // we can have sketches or faces - // for sketches just get the sketch normal - PartDesign::ProfileBased* pcFeat = static_cast(vp->getObject()); - Part::Part2DObject* pcSketch = dynamic_cast(pcFeat->Profile.getValue()); - // for faces we test if it is verified and if we can get its normal - if (!pcSketch) { - try { - Part::Feature* pcFeature = pcFeat->getVerifiedObject(); - Base::Vector3d SketchVector = pcFeat->getProfileNormal(); - Q_UNUSED(pcFeature) - Q_UNUSED(SketchVector) - hasFace = true; - } - catch (const Base::Exception& e) { - new App::DocumentObjectExecReturn(e.what()); - } - } - if (pcSketch) - addAxisToCombo(pcSketch, "N_Axis", tr("Sketch normal")); - else if (hasFace) - addAxisToCombo(pcFeat->Profile.getValue(), std::string(), tr("Face normal"), false); - // add the other entries - addAxisToCombo(0, std::string(), tr("Select reference...")); - // we start with the sketch normal as proposal for the custom direction - if (pcSketch) - addAxisToCombo(pcSketch, "N_Axis", tr("Custom direction")); - else if (hasFace) - addAxisToCombo(pcFeat->Profile.getValue(), std::string(), tr("Custom direction"), false); - } - - // add current link, if not in list - // first, figure out the item number for current axis - int indexOfCurrent = -1; - App::DocumentObject* ax = propReferenceAxis->getValue(); - const std::vector& subList = propReferenceAxis->getSubValues(); - for (size_t i = 0; i < axesInList.size(); i++) { - if (ax == axesInList[i]->getValue() && subList == axesInList[i]->getSubValues()) { - indexOfCurrent = i; - break; - } - } - // if the axis is not yet listed in the combobox - if (indexOfCurrent == -1 && ax) { - assert(subList.size() <= 1); - std::string sub; - if (!subList.empty()) - sub = subList[0]; - addAxisToCombo(ax, sub, getRefStr(ax, subList)); - indexOfCurrent = axesInList.size() - 1; - // the axis is not the normal, thus enable along direction - ui->checkBoxAlongDirection->setEnabled(true); - // we don't have custom direction thus disable its settings - ui->XDirectionEdit->setEnabled(false); - ui->YDirectionEdit->setEnabled(false); - ui->ZDirectionEdit->setEnabled(false); - } - - // highlight either current index or set custom direction - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - bool hasCustom = pcPocket->UseCustomVector.getValue(); - if (indexOfCurrent != -1 && !hasCustom) - ui->directionCB->setCurrentIndex(indexOfCurrent); - if (hasCustom) - ui->directionCB->setCurrentIndex(2); - - blockUpdate = oldVal_blockUpdate; -} - -void TaskPocketParameters::addAxisToCombo(App::DocumentObject* linkObj, - std::string linkSubname, QString itemText, bool hasSketch) -{ - this->ui->directionCB->addItem(itemText); - this->axesInList.emplace_back(new App::PropertyLinkSub); - App::PropertyLinkSub& lnk = *(axesInList.back()); - lnk.setValue(linkObj, std::vector(1, linkSubname)); - // if we have a face, we leave the link empty since we cannot - // store the face normal as sublink - if (hasSketch) - lnk.setValue(linkObj, std::vector(1, linkSubname)); -} - -void TaskPocketParameters::onDirectionCBChanged(int num) -{ - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - - if (axesInList.empty() || !pcPocket) - return; - - // we use this scheme for 'num' - // 0: normal to sketch or face - // 1: selection mode - // 2: custom - // 3-x: edges selected in the 3D model - - // check the axis - // when the link is empty we are either in selection mode - // or we are normal to a face - App::PropertyLinkSub& lnk = *(axesInList[num]); - if (num == 1) { - // enter reference selection mode - this->blockConnection(false); - // to distinguish that this is the direction selection - selectionFace = false; - TaskSketchBasedParameters::onSelectReference(true, true, false, true, true); - return; - } - else if (lnk.getValue() != 0) { - if (!pcPocket->getDocument()->isIn(lnk.getValue())) { - Base::Console().Error("Object was deleted\n"); - return; - } - propReferenceAxis->Paste(lnk); - } - - // in case the user is in selection mode, but changed his mind before selecting anything - exitSelectionMode(); - - // disable AlongSketchNormal when the direction is already normal - if (num == 0) - ui->checkBoxAlongDirection->setEnabled(false); - else - ui->checkBoxAlongDirection->setEnabled(true); - // if custom direction is used, show it - if (num == 2) { - ui->checkBoxDirection->setChecked(true); - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - pcPocket->UseCustomVector.setValue(true); - } - else { - pcPocket->UseCustomVector.setValue(false); - } - // if we dont use custom direction, only allow to show its direction - if (num != 2) { - ui->XDirectionEdit->setEnabled(false); - ui->YDirectionEdit->setEnabled(false); - ui->ZDirectionEdit->setEnabled(false); - } - else { - ui->XDirectionEdit->setEnabled(true); - ui->YDirectionEdit->setEnabled(true); - ui->ZDirectionEdit->setEnabled(true); - } - // recompute and update the direction - pcPocket->ReferenceAxis.setValue(lnk.getValue(), lnk.getSubValues()); - try { - recomputeFeature(); - } - catch (const Base::Exception& e) { - e.ReportException(); - } - updateDirectionEdits(); -} - -void TaskPocketParameters::onAlongSketchNormalChanged(bool on) -{ - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - pcPocket->AlongSketchNormal.setValue(on); - recomputeFeature(); -} - -void TaskPocketParameters::onDirectionToggled(bool on) -{ - if (on) - ui->groupBoxDirection->show(); - else - ui->groupBoxDirection->hide(); -} - -void TaskPocketParameters::onXDirectionEditChanged(double len) -{ - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - pcPocket->Direction.setValue(len, pcPocket->Direction.getValue().y, pcPocket->Direction.getValue().z); - recomputeFeature(); - // checking for case of a null vector is done in FeatureExtrude.cpp - // if there was a null vector, the normal vector of the sketch is used. - // therefore the vector component edits must be updated - updateDirectionEdits(); -} - -void TaskPocketParameters::onYDirectionEditChanged(double len) -{ - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - pcPocket->Direction.setValue(pcPocket->Direction.getValue().x, len, pcPocket->Direction.getValue().z); - recomputeFeature(); - updateDirectionEdits(); -} - -void TaskPocketParameters::onZDirectionEditChanged(double len) -{ - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - pcPocket->Direction.setValue(pcPocket->Direction.getValue().x, pcPocket->Direction.getValue().y, len); - recomputeFeature(); - updateDirectionEdits(); -} - -void TaskPocketParameters::updateDirectionEdits() -{ - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - // we don't want to execute the onChanged edits, but just update their contents - ui->XDirectionEdit->blockSignals(true); - ui->YDirectionEdit->blockSignals(true); - ui->ZDirectionEdit->blockSignals(true); - ui->XDirectionEdit->setValue(pcPocket->Direction.getValue().x); - ui->YDirectionEdit->setValue(pcPocket->Direction.getValue().y); - ui->ZDirectionEdit->setValue(pcPocket->Direction.getValue().z); - ui->XDirectionEdit->blockSignals(false); - ui->YDirectionEdit->blockSignals(false); - ui->ZDirectionEdit->blockSignals(false); -} - -void TaskPocketParameters::onMidplaneChanged(bool on) -{ - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - pcPocket->Midplane.setValue(on); - ui->checkBoxReversed->setEnabled(!on); - recomputeFeature(); -} - -void TaskPocketParameters::onReversedChanged(bool on) -{ - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - pcPocket->Reversed.setValue(on); - // midplane is not sensible when reversed - ui->checkBoxMidplane->setEnabled(!on); - // update the direction - recomputeFeature(); - updateDirectionEdits(); -} - void TaskPocketParameters::onModeChanged(int index) { PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); @@ -628,214 +203,6 @@ void TaskPocketParameters::onModeChanged(int index) recomputeFeature(); } -void TaskPocketParameters::onButtonFace(const bool pressed) -{ - this->blockConnection(!pressed); - - TaskSketchBasedParameters::onSelectReference(pressed, false, true, false); - - // Update button if onButtonFace() is called explicitly - ui->buttonFace->setChecked(pressed); -} - -void TaskPocketParameters::onFaceName(const QString& text) -{ - if (text.isEmpty()) { - // if user cleared the text field then also clear the properties - ui->lineFaceName->setProperty("FeatureName", QVariant()); - ui->lineFaceName->setProperty("FaceName", QVariant()); - } - else { - // expect that the label of an object is used - QStringList parts = text.split(QChar::fromLatin1(':')); - QString label = parts[0]; - QVariant name = objectNameByLabel(label, ui->lineFaceName->property("FeatureName")); - if (name.isValid()) { - parts[0] = name.toString(); - QString uptoface = parts.join(QString::fromLatin1(":")); - ui->lineFaceName->setProperty("FeatureName", name); - ui->lineFaceName->setProperty("FaceName", setUpToFace(uptoface)); - } - else { - ui->lineFaceName->setProperty("FeatureName", QVariant()); - ui->lineFaceName->setProperty("FaceName", QVariant()); - } - } -} - -double TaskPocketParameters::getLength(void) const -{ - return ui->lengthEdit->value().getValue(); -} - -double TaskPocketParameters::getLength2(void) const -{ - return ui->lengthEdit2->value().getValue(); -} - -double TaskPocketParameters::getOffset(void) const -{ - return ui->offsetEdit->value().getValue(); -} - -bool TaskPocketParameters::getAlongSketchNormal(void) const -{ - return ui->checkBoxAlongDirection->isChecked(); -} - -bool TaskPocketParameters::getCustom(void) const -{ - // index 2 is hardcoded to custom vector - return ui->directionCB->currentIndex() == 2 ? true : false; -} - -std::string TaskPocketParameters::getReferenceAxis(void) const -{ - std::vector sub; - App::DocumentObject* obj; - getReferenceAxis(obj, sub); - return buildLinkSingleSubPythonStr(obj, sub); -} - -double TaskPocketParameters::getXDirection(void) const -{ - return ui->XDirectionEdit->value(); -} - -double TaskPocketParameters::getYDirection(void) const -{ - return ui->YDirectionEdit->value(); -} - -double TaskPocketParameters::getZDirection(void) const -{ - return ui->ZDirectionEdit->value(); -} - -bool TaskPocketParameters::getReversed(void) const -{ - return ui->checkBoxReversed->isChecked(); -} - -bool TaskPocketParameters::getMidplane(void) const -{ - return ui->checkBoxMidplane->isChecked(); -} - -int TaskPocketParameters::getMode(void) const -{ - return ui->changeMode->currentIndex(); -} - -QString TaskPocketParameters::getFaceName(void) const -{ - // 'Up to face' mode - if (getMode() == 3) { - QVariant featureName = ui->lineFaceName->property("FeatureName"); - if (featureName.isValid()) { - QString faceName = ui->lineFaceName->property("FaceName").toString(); - return getFaceReference(featureName.toString(), faceName); - } - } - return QString::fromLatin1("None"); -} - -TaskPocketParameters::~TaskPocketParameters() -{ -} - -void TaskPocketParameters::changeEvent(QEvent *e) -{ - TaskBox::changeEvent(e); - if (e->type() == QEvent::LanguageChange) { - ui->lengthEdit->blockSignals(true); - ui->lengthEdit2->blockSignals(true); - ui->offsetEdit->blockSignals(true); - ui->XDirectionEdit->blockSignals(true); - ui->YDirectionEdit->blockSignals(true); - ui->ZDirectionEdit->blockSignals(true); - ui->directionCB->blockSignals(true); - int index = ui->directionCB->currentIndex(); - ui->directionCB->clear(); - ui->directionCB->addItem(tr("Sketch normal")); - ui->directionCB->addItem(tr("Select reference...")); - ui->directionCB->addItem(tr("Custom direction")); - ui->directionCB->setCurrentIndex(index); - ui->lineFaceName->blockSignals(true); - ui->changeMode->blockSignals(true); - index = ui->changeMode->currentIndex(); - ui->retranslateUi(proxy); - ui->changeMode->clear(); - ui->changeMode->addItem(tr("Dimension")); - ui->changeMode->addItem(tr("Through all")); - ui->changeMode->addItem(tr("To first")); - ui->changeMode->addItem(tr("Up to face")); - ui->changeMode->addItem(tr("Two dimensions")); - ui->changeMode->setCurrentIndex(index); - -#if QT_VERSION >= 0x040700 - ui->lineFaceName->setPlaceholderText(tr("No face selected")); -#endif - QVariant featureName = ui->lineFaceName->property("FeatureName"); - if (featureName.isValid()) { - QStringList parts = ui->lineFaceName->text().split(QChar::fromLatin1(':')); - QByteArray upToFace = ui->lineFaceName->property("FaceName").toByteArray(); - int faceId = -1; - bool ok = false; - if (upToFace.indexOf("Face") == 0) { - faceId = upToFace.remove(0,4).toInt(&ok); - } - - if (ok) { - ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3") - .arg(parts[0]) - .arg(tr("Face")) - .arg(faceId)); - } - else { - ui->lineFaceName->setText(parts[0]); - } - } - - ui->lengthEdit->blockSignals(false); - ui->lengthEdit2->blockSignals(false); - ui->offsetEdit->blockSignals(false); - ui->lineFaceName->blockSignals(false); - ui->changeMode->blockSignals(false); - } -} - -void TaskPocketParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const -{ - if (axesInList.empty()) - throw Base::RuntimeError("Not initialized!"); - - int num = ui->directionCB->currentIndex(); - const App::PropertyLinkSub& lnk = *(axesInList[num]); - if (lnk.getValue() == 0) { - // Note: Is is possible that a face of an object is directly pocketed without defining a profile shape - obj = nullptr; - sub.clear(); - //throw Base::RuntimeError("Still in reference selection mode; reference wasn't selected yet"); - } - else { - PartDesign::ProfileBased* pcDirection = static_cast(vp->getObject()); - if (!pcDirection->getDocument()->isIn(lnk.getValue())) - throw Base::RuntimeError("Object was deleted"); - - obj = lnk.getValue(); - sub = lnk.getSubValues(); - } -} - -void TaskPocketParameters::saveHistory(void) -{ - // save the user values to history - ui->lengthEdit->pushToHistory(); - ui->lengthEdit2->pushToHistory(); - ui->offsetEdit->pushToHistory(); -} - void TaskPocketParameters::apply() { auto obj = vp->getObject(); diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.h b/src/Mod/PartDesign/Gui/TaskPocketParameters.h index db6e8abdef..0621ac3056 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.h @@ -28,11 +28,9 @@ #include #include -#include "TaskSketchBasedParameters.h" +#include "TaskExtrudeParameters.h" #include "ViewProviderPocket.h" -class Ui_TaskPocketParameters; - namespace App { class Property; } @@ -44,7 +42,7 @@ class ViewProvider; namespace PartDesignGui { -class TaskPocketParameters : public TaskSketchBasedParameters +class TaskPocketParameters : public TaskExtrudeParameters { Q_OBJECT @@ -52,59 +50,15 @@ public: TaskPocketParameters(ViewProviderPocket *PocketView, QWidget *parent = 0, bool newObj=false); ~TaskPocketParameters(); - virtual void saveHistory() override; virtual void apply() override; - void fillDirectionCombo(); - void addAxisToCombo(App::DocumentObject* linkObj, std::string linkSubname, QString itemText, - bool hasSketch = true); - -private Q_SLOTS: - void onLengthChanged(double); - void onLength2Changed(double); - void onOffsetChanged(double); - void onDirectionCBChanged(int); - void onAlongSketchNormalChanged(bool); - void onDirectionToggled(bool); - void onXDirectionEditChanged(double); - void onYDirectionEditChanged(double); - void onZDirectionEditChanged(double); - void onMidplaneChanged(bool); - void onReversedChanged(bool); - void onButtonFace(const bool pressed = true); - void onFaceName(const QString& text); - void onModeChanged(int); - -protected: - void changeEvent(QEvent *e) override; - App::PropertyLinkSub* propReferenceAxis; - void getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const; +private: + void onModeChanged(int index) override; + void translateModeList(int index) override; + void updateUI(int index) override; private: - double getLength(void) const; - double getLength2(void) const; - double getOffset(void) const; - bool getAlongSketchNormal(void) const; - bool getCustom(void) const; - std::string getReferenceAxis(void) const; - double getXDirection(void) const; - double getYDirection(void) const; - double getZDirection(void) const; - int getMode(void) const; - bool getMidplane(void) const; - bool getReversed(void) const; - QString getFaceName(void) const; - - void onSelectionChanged(const Gui::SelectionChanges& msg) override; - void updateUI(int index); - void updateDirectionEdits(void); - -private: - QWidget* proxy; - std::unique_ptr ui; double oldLength; - bool selectionFace; - std::vector> axesInList; }; /// simulation dialog for the TaskView diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.ui b/src/Mod/PartDesign/Gui/TaskPocketParameters.ui index 4b1171b122..e67e7f6b77 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.ui @@ -58,9 +58,6 @@ - - Offset from face at which pocket will end - false From 828b1b6d0a6e8f40b24ccecb7e39ce0dabdddcdd Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 26 Nov 2021 16:46:58 +0100 Subject: [PATCH 071/133] PD: add enum class to TaskPocketParameters to avoid to work with magic numbers --- .../PartDesign/Gui/TaskPocketParameters.cpp | 44 +++++++------------ src/Mod/PartDesign/Gui/TaskPocketParameters.h | 8 ++++ 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index d31f2e769d..06401f0fff 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -32,20 +32,10 @@ #include "ui_TaskPadParameters.h" #include "TaskPocketParameters.h" -#include -#include -#include -#include -#include -#include #include -#include -#include #include -#include #include #include -#include "ReferenceSelection.h" using namespace PartDesignGui; using namespace Gui; @@ -90,15 +80,16 @@ void TaskPocketParameters::updateUI(int index) // disable/hide everything unless we are sure we don't need it // exception: the direction parameters are in any case visible bool isLengthEditVisible = false; - bool isLengthEdit2Visible = false; + bool isLengthEdit2Visible = false; bool isOffsetEditVisible = false; bool isOffsetEditEnabled = true; bool isMidplateEnabled = false; bool isReversedEnabled = false; bool isFaceEditEnabled = false; - // dimension - if (index == 0) { + Modes mode = static_cast(index); + + if (mode == Modes::Dimension) { isLengthEditVisible = true; ui->lengthEdit->selectNumber(); // Make sure that the spin box has the focus to get key events @@ -109,23 +100,20 @@ void TaskPocketParameters::updateUI(int index) // Reverse only makes sense if Midplane is not true isReversedEnabled = !ui->checkBoxMidplane->isChecked(); } - // through all - else if (index == 1) { + else if (mode == Modes::ThroughAll) { isOffsetEditVisible = true; isOffsetEditEnabled = false; // offset may have some meaning for through all but it doesn't work isMidplateEnabled = true; isReversedEnabled = !ui->checkBoxMidplane->isChecked(); } - // up to first - else if (index == 2) { + else if (mode == Modes::ToFirst) { isOffsetEditVisible = true; isReversedEnabled = true; // Will change the direction it seeks for its first face? // It may work not quite as expected but useful if sketch oriented upside-down. // (may happen in bodies) // FIXME: Fix probably lies somewhere in IF block on line 125 of FeaturePocket.cpp } - // up to face - else if (index == 3) { + else if (mode == Modes::UpToFace) { isOffsetEditVisible = true; isReversedEnabled = true; isFaceEditEnabled = true; @@ -134,12 +122,11 @@ void TaskPocketParameters::updateUI(int index) if (ui->lineFaceName->property("FeatureName").isNull()) onButtonFace(true); } - // two dimensions - else { + else if (mode == Modes::TwoDimensions) { isLengthEditVisible = true; isLengthEdit2Visible = true; isReversedEnabled = true; - } + } ui->lengthEdit->setVisible( isLengthEditVisible ); ui->lengthEdit->setEnabled( isLengthEditVisible ); @@ -169,8 +156,8 @@ void TaskPocketParameters::onModeChanged(int index) { PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - switch (index) { - case 0: + switch (static_cast(index)) { + case Modes::Dimension: // Why? See below for "UpToFace" if (oldLength < Precision::Confusion()) oldLength = 5.0; @@ -178,15 +165,15 @@ void TaskPocketParameters::onModeChanged(int index) ui->lengthEdit->setValue(oldLength); pcPocket->Type.setValue("Length"); break; - case 1: + case Modes::ThroughAll: oldLength = pcPocket->Length.getValue(); pcPocket->Type.setValue("ThroughAll"); break; - case 2: + case Modes::ToFirst: oldLength = pcPocket->Length.getValue(); pcPocket->Type.setValue("UpToFirst"); break; - case 3: + case Modes::UpToFace: // Because of the code at the beginning of Pocket::execute() which is used to detect // broken legacy parts, we must set the length to zero here! oldLength = pcPocket->Length.getValue(); @@ -194,9 +181,10 @@ void TaskPocketParameters::onModeChanged(int index) pcPocket->Length.setValue(0.0); ui->lengthEdit->setValue(0.0); break; - default: + case Modes::TwoDimensions: oldLength = pcPocket->Length.getValue(); pcPocket->Type.setValue("TwoLengths"); + break; } updateUI(index); diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.h b/src/Mod/PartDesign/Gui/TaskPocketParameters.h index 0621ac3056..ae95bd2d2a 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.h @@ -46,6 +46,14 @@ class TaskPocketParameters : public TaskExtrudeParameters { Q_OBJECT + enum class Modes { + Dimension, + ThroughAll, + ToFirst, + UpToFace, + TwoDimensions + }; + public: TaskPocketParameters(ViewProviderPocket *PocketView, QWidget *parent = 0, bool newObj=false); ~TaskPocketParameters(); From e412c3f4cc13af62fdff14a9e8d1bbc3d2c29d86 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 26 Nov 2021 16:58:59 +0100 Subject: [PATCH 072/133] PD: add enum class to TaskPadParameters to avoid to work with magic numbers --- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 56 +++++++++---------- src/Mod/PartDesign/Gui/TaskPadParameters.h | 8 +++ .../PartDesign/Gui/TaskPocketParameters.cpp | 4 +- src/Mod/PartDesign/Gui/TaskPocketParameters.h | 2 +- 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index d193222925..9e7d902178 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -32,22 +32,10 @@ #include "ui_TaskPadParameters.h" #include "TaskPadParameters.h" -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include -#include -#include #include #include -#include "ReferenceSelection.h" using namespace PartDesignGui; using namespace Gui; @@ -99,8 +87,9 @@ void TaskPadParameters::updateUI(int index) bool isReversedVisible = false; bool isFaceEditEnabled = false; - // dimension - if (index == 0) { + Modes mode = static_cast(index); + + if (mode == Modes::Dimension) { isLengthEditVisible = true; ui->lengthEdit->selectNumber(); // Make sure that the spin box has the focus to get key events @@ -113,14 +102,12 @@ void TaskPadParameters::updateUI(int index) isReversedEnabled = !ui->checkBoxMidplane->isChecked(); isReversedVisible = true; } - // up to first/last - else if (index == 1 || index == 2) { + else if (mode == Modes::ToLast || mode == Modes::ToFirst) { isOffsetEditVisible = true; isReversedEnabled = true; isReversedVisible = true; } - // up to face - else if (index == 3) { + else if (mode == Modes::ToFace) { isOffsetEditVisible = true; isFaceEditEnabled = true; QMetaObject::invokeMethod(ui->lineFaceName, "setFocus", Qt::QueuedConnection); @@ -130,8 +117,7 @@ void TaskPadParameters::updateUI(int index) isReversedEnabled = true; isReversedVisible = true; } - // two dimensions - else { + else if (mode == Modes::TwoDimensions) { isLengthEditVisible = true; isLengthEdit2Visible = true; isMidplaneEnabled = !ui->checkBoxReversed->isChecked(); @@ -170,17 +156,25 @@ void TaskPadParameters::onModeChanged(int index) { PartDesign::Pad* pcPad = static_cast(vp->getObject()); - switch (index) { - case 0: - pcPad->Type.setValue("Length"); - // Avoid error message - if (ui->lengthEdit->value() < Base::Quantity(Precision::Confusion(), Base::Unit::Length)) - ui->lengthEdit->setValue(5.0); - break; - case 1: pcPad->Type.setValue("UpToLast"); break; - case 2: pcPad->Type.setValue("UpToFirst"); break; - case 3: pcPad->Type.setValue("UpToFace"); break; - default: pcPad->Type.setValue("TwoLengths"); + switch (static_cast(index)) { + case Modes::Dimension: + pcPad->Type.setValue("Length"); + // Avoid error message + if (ui->lengthEdit->value() < Base::Quantity(Precision::Confusion(), Base::Unit::Length)) + ui->lengthEdit->setValue(5.0); + break; + case Modes::ToLast: + pcPad->Type.setValue("UpToLast"); + break; + case Modes::ToFirst: + pcPad->Type.setValue("UpToFirst"); + break; + case Modes::ToFace: + pcPad->Type.setValue("UpToFace"); + break; + case Modes::TwoDimensions: + pcPad->Type.setValue("TwoLengths"); + break; } updateUI(index); diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.h b/src/Mod/PartDesign/Gui/TaskPadParameters.h index a3701e1588..b5acca2f3e 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.h @@ -46,6 +46,14 @@ class TaskPadParameters : public TaskExtrudeParameters { Q_OBJECT + enum class Modes { + Dimension, + ToLast, + ToFirst, + ToFace, + TwoDimensions + }; + public: TaskPadParameters(ViewProviderPad *PadView, QWidget *parent = 0, bool newObj=false); ~TaskPadParameters(); diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 06401f0fff..086318c86f 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -113,7 +113,7 @@ void TaskPocketParameters::updateUI(int index) // (may happen in bodies) // FIXME: Fix probably lies somewhere in IF block on line 125 of FeaturePocket.cpp } - else if (mode == Modes::UpToFace) { + else if (mode == Modes::ToFace) { isOffsetEditVisible = true; isReversedEnabled = true; isFaceEditEnabled = true; @@ -173,7 +173,7 @@ void TaskPocketParameters::onModeChanged(int index) oldLength = pcPocket->Length.getValue(); pcPocket->Type.setValue("UpToFirst"); break; - case Modes::UpToFace: + case Modes::ToFace: // Because of the code at the beginning of Pocket::execute() which is used to detect // broken legacy parts, we must set the length to zero here! oldLength = pcPocket->Length.getValue(); diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.h b/src/Mod/PartDesign/Gui/TaskPocketParameters.h index ae95bd2d2a..30c1414495 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.h @@ -50,7 +50,7 @@ class TaskPocketParameters : public TaskExtrudeParameters Dimension, ThroughAll, ToFirst, - UpToFace, + ToFace, TwoDimensions }; From 8e6c5a497be7b5557ed95879975b3832419209de Mon Sep 17 00:00:00 2001 From: sliptonic Date: Fri, 26 Nov 2021 13:27:44 -0600 Subject: [PATCH 073/133] make sure depthparams handles negative steps and finish step correctly revised test --- src/Mod/Path/PathScripts/PathUtils.py | 5 +- src/Mod/Path/PathTests/TestPathDepthParams.py | 243 ++++++++++-------- 2 files changed, 143 insertions(+), 105 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathUtils.py b/src/Mod/Path/PathScripts/PathUtils.py index 5152ae044a..8e5c1e0b42 100644 --- a/src/Mod/Path/PathScripts/PathUtils.py +++ b/src/Mod/Path/PathScripts/PathUtils.py @@ -788,8 +788,6 @@ class depth_params(object): def __init__(self, clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths=None, equalstep=False): '''self, clearance_height, safe_height, start_depth, step_down, z_finish_depth, final_depth, [user_depths=None], equalstep=False''' - if z_finish_step > step_down: - raise ValueError('z_finish_step must be less than step_down') self.__clearance_height = clearance_height self.__safe_height = safe_height @@ -801,6 +799,9 @@ class depth_params(object): self.data = self.__get_depths(equalstep=equalstep) self.index = 0 + if self.__z_finish_step > self.__step_down: + raise ValueError('z_finish_step must be less than step_down') + def __iter__(self): self.index = 0 return self diff --git a/src/Mod/Path/PathTests/TestPathDepthParams.py b/src/Mod/Path/PathTests/TestPathDepthParams.py index 3dfa419e7f..fed0779fc8 100644 --- a/src/Mod/Path/PathTests/TestPathDepthParams.py +++ b/src/Mod/Path/PathTests/TestPathDepthParams.py @@ -26,151 +26,188 @@ import unittest class depthTestCases(unittest.TestCase): def test00(self): - '''Stepping down to zero ''' - clearance_height= 15 - safe_height = 12 + """Stepping down to zero""" + args = { + "clearance_height": 15, + "safe_height": 12, + "start_depth": 10, + "step_down": 2, + "z_finish_step": 1, + "final_depth": 0, + "user_depths": None, + } - start_depth = 10 - step_down = 2 - z_finish_step = 1 - final_depth = 0 - user_depths = None + expected = [8, 6, 4, 2, 1, 0] - expected =[8,6,4,2,1,0] - - d = PathUtils.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) + d = PathUtils.depth_params(**args) r = [i for i in d] - self.assertListEqual (r, expected) + self.assertListEqual(r, expected) def test10(self): - '''Stepping from zero to a negative depth ''' + """Stepping from zero to a negative depth""" - clearance_height= 10 - safe_height = 5 + args = { + "clearance_height": 10, + "safe_height": 5, + "start_depth": 0, + "step_down": 2, + "z_finish_step": 0, + "final_depth": -10, + "user_depths": None, + } - start_depth = 0 - step_down = 2 - z_finish_step = 0 - final_depth = -10 - user_depths = None + expected = [-2, -4, -6, -8, -10] - expected =[-2, -4, -6, -8, -10] - - d = PathUtils.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) + d = PathUtils.depth_params(**args) r = [i for i in d] - self.assertListEqual (r, expected) + self.assertListEqual(r, expected) def test20(self): - '''Start and end are equal or start lower than finish ''' - clearance_height= 15 - safe_height = 12 + """Start and end are equal or start lower than finish""" - start_depth = 10 - step_down = 2 - z_finish_step = 0 - final_depth = 10 - user_depths = None + args = { + "clearance_height": 15, + "safe_height": 12, + "start_depth": 10, + "step_down": 2, + "z_finish_step": 0, + "final_depth": 10, + "user_depths": None, + } + expected = [10] - expected =[10] - - d = PathUtils.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) + d = PathUtils.depth_params(**args) r = [i for i in d] - self.assertListEqual (r, expected) + self.assertListEqual(r, expected) - start_depth = 10 - final_depth = 15 + args["start_depth"] = 10 + args["final_depth"] = 15 - expected =[] + expected = [] - d = PathUtils.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) + d = PathUtils.depth_params(**args) r = [i for i in d] - self.assertListEqual (r, expected) + self.assertListEqual(r, expected) def test30(self): - '''User Parameters passed in''' - clearance_height= 10 - safe_height = 5 + """User Parameters passed in""" + args = { + "clearance_height": 10, + "safe_height": 5, + "start_depth": 0, + "step_down": 2, + "z_finish_step": 0, + "final_depth": -10, + "user_depths": [2, 4, 8, 10, 11, 12], + } - start_depth = 0 - step_down = 2 - z_finish_step = 0 - final_depth = -10 - user_depths = [2, 4, 8, 10, 11, 12] + expected = [2, 4, 8, 10, 11, 12] - expected =[2, 4, 8, 10, 11, 12] - - d = PathUtils.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) + d = PathUtils.depth_params(**args) r = [i for i in d] - self.assertListEqual (r, expected) + self.assertListEqual(r, expected) def test40(self): - '''z_finish_step passed in.''' - clearance_height= 10 - safe_height = 5 + """z_finish_step passed in.""" + args = { + "clearance_height": 10, + "safe_height": 5, + "start_depth": 0, + "step_down": 2, + "z_finish_step": 1, + "final_depth": -10, + "user_depths": None, + } - start_depth = 0 - step_down = 2 - z_finish_step = 1 - final_depth = -10 - user_depths = None + expected = [-2, -4, -6, -8, -9, -10] - expected =[-2, -4, -6, -8, -9, -10] - - d = PathUtils.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) + d = PathUtils.depth_params(**args) r = [i for i in d] - self.assertListEqual (r, expected) - + self.assertListEqual(r, expected) def test50(self): - '''stepping down with equalstep=True''' - clearance_height= 10 - safe_height = 5 + """stepping down with equalstep=True""" + args = { + "clearance_height": 10, + "safe_height": 5, + "start_depth": 10, + "step_down": 3, + "z_finish_step": 0, + "final_depth": 0, + "user_depths": None, + "equalstep": True, + } - start_depth = 10 - step_down = 3 - z_finish_step = 0 - final_depth = 0 - user_depths = None + expected = [7.5, 5.0, 2.5, 0] - expected =[7.5, 5.0, 2.5, 0] - - d = PathUtils.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths, equalstep=True) + d = PathUtils.depth_params(**args) r = [i for i in d] - self.assertListEqual (r, expected) - + self.assertListEqual(r, expected) def test60(self): - '''stepping down with equalstep=True and a finish depth''' - clearance_height= 10 - safe_height = 5 + """stepping down with equalstep=True and a finish depth""" + args = { + "clearance_height": 10, + "safe_height": 5, + "start_depth": 10, + "step_down": 3, + "z_finish_step": 1, + "final_depth": 0, + "user_depths": None, + } - start_depth = 10 - step_down = 3 - z_finish_step = 1 - final_depth = 0 - user_depths = None + expected = [7.0, 4.0, 1.0, 0] - expected =[7.0, 4.0, 1.0, 0] - - d = PathUtils.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths, equalstep=True) + d = PathUtils.depth_params(**args) r = [i for i in d] - self.assertListEqual (r, expected) + self.assertListEqual(r, expected) def test70(self): - '''stepping down with stepdown greater than total depth''' - clearance_height= 10 - safe_height = 5 + """stepping down with stepdown greater than total depth""" + args = { + "clearance_height": 10, + "safe_height": 5, + "start_depth": 10, + "step_down": 20, + "z_finish_step": 1, + "final_depth": 0, + "user_depths": None, + } - start_depth = 10 - step_down = 20 - z_finish_step = 1 - final_depth = 0 - user_depths = None + expected = [1.0, 0] - expected =[1.0, 0] - - d = PathUtils.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) + d = PathUtils.depth_params(**args) r = [i for i in d] - self.assertListEqual (r, expected) + self.assertListEqual(r, expected) + def test80(self): + """Test handling of negative step-down, negative finish step, and relative size of step/finish""" + # negative steps should be converted to positive values + args = { + "clearance_height": 3, + "safe_height": 3, + "start_depth": 2, + "step_down": -1, + "z_finish_step": -1, + "final_depth": 0, + "user_depths": None, + } + + expected = [1.0, 0] + + d = PathUtils.depth_params(**args) + r = [i for i in d] + self.assertListEqual(r, expected) + + # a step_down less than the finish step is an error + args = { + "clearance_height": 3, + "safe_height": 3, + "start_depth": 2, + "step_down": 0.1, + "z_finish_step": 1, + "final_depth": 0, + "user_depths": None, + } + self.assertRaises(ValueError, PathUtils.depth_params, **args) From cb8330d5bd916f609bab420dc091c6bffff82702 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 26 Nov 2021 21:51:14 +0100 Subject: [PATCH 074/133] PD: code-refactoring of TaskExtrudeParameters --- .../PartDesign/Gui/TaskExtrudeParameters.cpp | 371 ++++++++++-------- .../PartDesign/Gui/TaskExtrudeParameters.h | 22 +- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 12 +- .../PartDesign/Gui/TaskPocketParameters.cpp | 12 +- 4 files changed, 242 insertions(+), 175 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp index c7b55b6150..27c3ad9a00 100644 --- a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp @@ -50,33 +50,39 @@ TaskExtrudeParameters::TaskExtrudeParameters(ViewProviderSketchBased *SketchBase // we need a separate container widget to add all controls to proxy = new QWidget(this); ui->setupUi(proxy); -#if QT_VERSION >= 0x040700 ui->lineFaceName->setPlaceholderText(tr("No face selected")); -#endif this->groupLayout()->addWidget(proxy); } -void TaskExtrudeParameters::setupDialog(bool newObj) +TaskExtrudeParameters::~TaskExtrudeParameters() +{ +} + +void TaskExtrudeParameters::setupDialog() { // Get the feature data PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); Base::Quantity l = extrude->Length.getQuantityValue(); Base::Quantity l2 = extrude->Length2.getQuantityValue(); Base::Quantity off = extrude->Offset.getQuantityValue(); + bool alongNormal = extrude->AlongSketchNormal.getValue(); bool useCustom = extrude->UseCustomVector.getValue(); + double xs = extrude->Direction.getValue().x; double ys = extrude->Direction.getValue().y; double zs = extrude->Direction.getValue().z; + bool midplane = extrude->Midplane.getValue(); bool reversed = extrude->Reversed.getValue(); + int index = extrude->Type.getValue(); // must extract value here, clear() kills it! App::DocumentObject* obj = extrude->UpToFace.getValue(); std::vector subStrings = extrude->UpToFace.getSubValues(); std::string upToFace; int faceId = -1; - if ((obj != NULL) && !subStrings.empty()) { + if (obj && !subStrings.empty()) { upToFace = subStrings.front(); if (upToFace.substr(0,4) == "Face") faceId = std::atoi(&upToFace[4]); @@ -94,9 +100,11 @@ void TaskExtrudeParameters::setupDialog(bool newObj) ui->lengthEdit->setValue(l); ui->lengthEdit2->setValue(l2); ui->offsetEdit->setValue(off); + ui->checkBoxAlongDirection->setChecked(alongNormal); ui->checkBoxDirection->setChecked(useCustom); onDirectionToggled(useCustom); + // disable to change the direction if not custom if (!useCustom) { ui->XDirectionEdit->setEnabled(false); @@ -141,6 +149,26 @@ void TaskExtrudeParameters::setupDialog(bool newObj) translateModeList(index); + connectSlots(); + + this->propReferenceAxis = &(extrude->ReferenceAxis); + + // Due to signals attached after changes took took into effect we should update the UI now. + updateUI(index); +} + +void TaskExtrudeParameters::readValuesFromHistory() +{ + ui->lengthEdit->setToLastUsedValue(); + ui->lengthEdit->selectNumber(); + ui->lengthEdit2->setToLastUsedValue(); + ui->lengthEdit2->selectNumber(); + ui->offsetEdit->setToLastUsedValue(); + ui->offsetEdit->selectNumber(); +} + +void TaskExtrudeParameters::connectSlots() +{ QMetaObject::connectSlotsByName(this); connect(ui->lengthEdit, SIGNAL(valueChanged(double)), @@ -150,17 +178,17 @@ void TaskExtrudeParameters::setupDialog(bool newObj) connect(ui->offsetEdit, SIGNAL(valueChanged(double)), this, SLOT(onOffsetChanged(double))); connect(ui->directionCB, SIGNAL(activated(int)), - this, SLOT(onDirectionCBChanged(int))); + this, SLOT(onDirectionCBChanged(int))); connect(ui->checkBoxAlongDirection, SIGNAL(toggled(bool)), - this, SLOT(onAlongSketchNormalChanged(bool))); + this, SLOT(onAlongSketchNormalChanged(bool))); connect(ui->checkBoxDirection, SIGNAL(toggled(bool)), - this, SLOT(onDirectionToggled(bool))); + this, SLOT(onDirectionToggled(bool))); connect(ui->XDirectionEdit, SIGNAL(valueChanged(double)), - this, SLOT(onXDirectionEditChanged(double))); + this, SLOT(onXDirectionEditChanged(double))); connect(ui->YDirectionEdit, SIGNAL(valueChanged(double)), - this, SLOT(onYDirectionEditChanged(double))); + this, SLOT(onYDirectionEditChanged(double))); connect(ui->ZDirectionEdit, SIGNAL(valueChanged(double)), - this, SLOT(onZDirectionEditChanged(double))); + this, SLOT(onZDirectionEditChanged(double))); connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)), this, SLOT(onMidplaneChanged(bool))); connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), @@ -173,26 +201,17 @@ void TaskExtrudeParameters::setupDialog(bool newObj) this, SLOT(onFaceName(QString))); connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), this, SLOT(onUpdateView(bool))); - - this->propReferenceAxis = &(extrude->ReferenceAxis); - - // Due to signals attached after changes took took into effect we should update the UI now. - updateUI(index); - - // if it is a newly created object use the last value of the history - // TODO: newObj doesn't supplied normally by any caller (2015-07-24, Fat-Zer) - if (newObj){ - ui->lengthEdit->setToLastUsedValue(); - ui->lengthEdit->selectNumber(); - ui->lengthEdit2->setToLastUsedValue(); - ui->lengthEdit2->selectNumber(); - ui->offsetEdit->setToLastUsedValue(); - ui->offsetEdit->selectNumber(); - } } -TaskExtrudeParameters::~TaskExtrudeParameters() +void TaskExtrudeParameters::tryRecomputeFeature() { + try { + // recompute and update the direction + recomputeFeature(); + } + catch (const Base::Exception& e) { + e.ReportException(); + } } void TaskExtrudeParameters::onSelectionChanged(const Gui::SelectionChanges& msg) @@ -200,63 +219,85 @@ void TaskExtrudeParameters::onSelectionChanged(const Gui::SelectionChanges& msg) if (msg.Type == Gui::SelectionChanges::AddSelection) { // if we have an edge selection for the extrude direction if (!selectionFace) { - std::vector edge; - App::DocumentObject* selObj; - if (getReferencedSelection(vp->getObject(), msg, selObj, edge) && selObj) { - exitSelectionMode(); - propReferenceAxis->setValue(selObj, edge); - recomputeFeature(); - // update direction combobox - fillDirectionCombo(); - } + selectedReferenceAxis(msg); } - else { // if we have a selection of a face + // if we have a selection of a face + else { QString refText = onAddSelection(msg); if (refText.length() > 0) { - ui->lineFaceName->blockSignals(true); + QSignalBlocker block(ui->lineFaceName); ui->lineFaceName->setText(refText); ui->lineFaceName->setProperty("FeatureName", QByteArray(msg.pObjectName)); ui->lineFaceName->setProperty("FaceName", QByteArray(msg.pSubName)); - ui->lineFaceName->blockSignals(false); // Turn off reference selection mode onButtonFace(false); } else { - ui->lineFaceName->blockSignals(true); - ui->lineFaceName->clear(); - ui->lineFaceName->setProperty("FeatureName", QVariant()); - ui->lineFaceName->setProperty("FaceName", QVariant()); - ui->lineFaceName->blockSignals(false); + clearFaceName(); } } - } else if (msg.Type == Gui::SelectionChanges::ClrSelection && selectionFace) { - ui->lineFaceName->blockSignals(true); - ui->lineFaceName->clear(); - ui->lineFaceName->setProperty("FeatureName", QVariant()); - ui->lineFaceName->setProperty("FaceName", QVariant()); - ui->lineFaceName->blockSignals(false); } + else if (msg.Type == Gui::SelectionChanges::ClrSelection && selectionFace) { + clearFaceName(); + } +} + +void TaskExtrudeParameters::selectedReferenceAxis(const Gui::SelectionChanges& msg) +{ + std::vector edge; + App::DocumentObject* selObj; + if (getReferencedSelection(vp->getObject(), msg, selObj, edge) && selObj) { + exitSelectionMode(); + propReferenceAxis->setValue(selObj, edge); + tryRecomputeFeature(); + // update direction combobox + fillDirectionCombo(); + } +} + +void TaskExtrudeParameters::clearFaceName() +{ + QSignalBlocker block(ui->lineFaceName); + ui->lineFaceName->clear(); + ui->lineFaceName->setProperty("FeatureName", QVariant()); + ui->lineFaceName->setProperty("FaceName", QVariant()); + } void TaskExtrudeParameters::onLengthChanged(double len) { PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); extrude->Length.setValue(len); - recomputeFeature(); + tryRecomputeFeature(); } void TaskExtrudeParameters::onLength2Changed(double len) { PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); extrude->Length2.setValue(len); - recomputeFeature(); + tryRecomputeFeature(); } void TaskExtrudeParameters::onOffsetChanged(double len) { PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); extrude->Offset.setValue(len); - recomputeFeature(); + tryRecomputeFeature(); +} + +bool TaskExtrudeParameters::hasProfileFace(PartDesign::ProfileBased* profile) const +{ + try { + Part::Feature* pcFeature = profile->getVerifiedObject(); + Base::Vector3d SketchVector = profile->getProfileNormal(); + Q_UNUSED(pcFeature) + Q_UNUSED(SketchVector) + return true; + } + catch (const Base::Exception&) { + } + + return false; } void TaskExtrudeParameters::fillDirectionCombo() @@ -273,23 +314,17 @@ void TaskExtrudeParameters::fillDirectionCombo() Part::Part2DObject* pcSketch = dynamic_cast(pcFeat->Profile.getValue()); // for faces we test if it is verified and if we can get its normal if (!pcSketch) { - try { - Part::Feature* pcFeature = pcFeat->getVerifiedObject(); - Base::Vector3d SketchVector = pcFeat->getProfileNormal(); - Q_UNUSED(pcFeature) - Q_UNUSED(SketchVector) - hasFace = true; - } - catch (const Base::Exception& e) { - new App::DocumentObjectExecReturn(e.what()); - } + hasFace = hasProfileFace(pcFeat); } + if (pcSketch) addAxisToCombo(pcSketch, "N_Axis", tr("Sketch normal")); else if (hasFace) addAxisToCombo(pcFeat->Profile.getValue(), std::string(), tr("Face normal"), false); + // add the other entries addAxisToCombo(0, std::string(), tr("Select reference...")); + // we start with the sketch normal as proposal for the custom direction if (pcSketch) addAxisToCombo(pcSketch, "N_Axis", tr("Custom direction")); @@ -330,13 +365,13 @@ void TaskExtrudeParameters::fillDirectionCombo() if (indexOfCurrent != -1 && !hasCustom) ui->directionCB->setCurrentIndex(indexOfCurrent); if (hasCustom) - ui->directionCB->setCurrentIndex(2); + ui->directionCB->setCurrentIndex(DirectionModes::Custom); blockUpdate = oldVal_blockUpdate; } -void TaskExtrudeParameters::addAxisToCombo(App::DocumentObject* linkObj, - std::string linkSubname, QString itemText, bool hasSketch) +void TaskExtrudeParameters::addAxisToCombo(App::DocumentObject* linkObj, std::string linkSubname, + QString itemText, bool hasSketch) { this->ui->directionCB->addItem(itemText); this->axesInList.emplace_back(new App::PropertyLinkSub); @@ -364,7 +399,7 @@ void TaskExtrudeParameters::onDirectionCBChanged(int num) // when the link is empty we are either in selection mode // or we are normal to a face App::PropertyLinkSub& lnk = *(axesInList[num]); - if (num == 1) { + if (num == DirectionModes::Select) { // enter reference selection mode this->blockConnection(false); // to distinguish that this is the direction selection @@ -372,7 +407,7 @@ void TaskExtrudeParameters::onDirectionCBChanged(int num) TaskSketchBasedParameters::onSelectReference(true, true, false, true, true); return; } - else if (lnk.getValue() != 0) { + else if (lnk.getValue()) { if (!extrude->getDocument()->isIn(lnk.getValue())) { Base::Console().Error("Object was deleted\n"); return; @@ -384,20 +419,22 @@ void TaskExtrudeParameters::onDirectionCBChanged(int num) exitSelectionMode(); // disable AlongSketchNormal when the direction is already normal - if (num == 0) + if (num == DirectionModes::Normal) ui->checkBoxAlongDirection->setEnabled(false); else ui->checkBoxAlongDirection->setEnabled(true); + // if custom direction is used, show it - if (num == 2) { + if (num == DirectionModes::Custom) { ui->checkBoxDirection->setChecked(true); extrude->UseCustomVector.setValue(true); } else { extrude->UseCustomVector.setValue(false); } + // if we dont use custom direction, only allow to show its direction - if (num != 2) { + if (num != DirectionModes::Custom) { ui->XDirectionEdit->setEnabled(false); ui->YDirectionEdit->setEnabled(false); ui->ZDirectionEdit->setEnabled(false); @@ -407,14 +444,9 @@ void TaskExtrudeParameters::onDirectionCBChanged(int num) ui->YDirectionEdit->setEnabled(true); ui->ZDirectionEdit->setEnabled(true); } - // recompute and update the direction + extrude->ReferenceAxis.setValue(lnk.getValue(), lnk.getSubValues()); - try { - recomputeFeature(); - } - catch (const Base::Exception& e) { - e.ReportException(); - } + tryRecomputeFeature(); updateDirectionEdits(); } @@ -422,7 +454,7 @@ void TaskExtrudeParameters::onAlongSketchNormalChanged(bool on) { PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); extrude->AlongSketchNormal.setValue(on); - recomputeFeature(); + tryRecomputeFeature(); } void TaskExtrudeParameters::onDirectionToggled(bool on) @@ -437,7 +469,7 @@ void TaskExtrudeParameters::onXDirectionEditChanged(double len) { PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); extrude->Direction.setValue(len, extrude->Direction.getValue().y, extrude->Direction.getValue().z); - recomputeFeature(); + tryRecomputeFeature(); // checking for case of a null vector is done in FeatureExtrude.cpp // if there was a null vector, the normal vector of the sketch is used. // therefore the vector component edits must be updated @@ -448,7 +480,7 @@ void TaskExtrudeParameters::onYDirectionEditChanged(double len) { PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); extrude->Direction.setValue(extrude->Direction.getValue().x, len, extrude->Direction.getValue().z); - recomputeFeature(); + tryRecomputeFeature(); updateDirectionEdits(); } @@ -456,7 +488,7 @@ void TaskExtrudeParameters::onZDirectionEditChanged(double len) { PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); extrude->Direction.setValue(extrude->Direction.getValue().x, extrude->Direction.getValue().y, len); - recomputeFeature(); + tryRecomputeFeature(); updateDirectionEdits(); } @@ -464,15 +496,12 @@ void TaskExtrudeParameters::updateDirectionEdits() { PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); // we don't want to execute the onChanged edits, but just update their contents - ui->XDirectionEdit->blockSignals(true); - ui->YDirectionEdit->blockSignals(true); - ui->ZDirectionEdit->blockSignals(true); + QSignalBlocker xdir(ui->XDirectionEdit); + QSignalBlocker ydir(ui->YDirectionEdit); + QSignalBlocker zdir(ui->ZDirectionEdit); ui->XDirectionEdit->setValue(extrude->Direction.getValue().x); ui->YDirectionEdit->setValue(extrude->Direction.getValue().y); ui->ZDirectionEdit->setValue(extrude->Direction.getValue().z); - ui->XDirectionEdit->blockSignals(false); - ui->YDirectionEdit->blockSignals(false); - ui->ZDirectionEdit->blockSignals(false); } void TaskExtrudeParameters::onMidplaneChanged(bool on) @@ -481,7 +510,7 @@ void TaskExtrudeParameters::onMidplaneChanged(bool on) extrude->Midplane.setValue(on); // reversed is not sensible when midplane ui->checkBoxReversed->setEnabled(!on); - recomputeFeature(); + tryRecomputeFeature(); } void TaskExtrudeParameters::onReversedChanged(bool on) @@ -491,10 +520,32 @@ void TaskExtrudeParameters::onReversedChanged(bool on) // midplane is not sensible when reversed ui->checkBoxMidplane->setEnabled(!on); // update the direction - recomputeFeature(); + tryRecomputeFeature(); updateDirectionEdits(); } +void TaskExtrudeParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const +{ + if (axesInList.empty()) + throw Base::RuntimeError("Not initialized!"); + + int num = ui->directionCB->currentIndex(); + const App::PropertyLinkSub& lnk = *(axesInList[num]); + if (!lnk.getValue()) { + // Note: It is possible that a face of an object is directly padded/pocketed without defining a profile shape + obj = nullptr; + sub.clear(); + } + else { + PartDesign::ProfileBased* pcDirection = static_cast(vp->getObject()); + if (!pcDirection->getDocument()->isIn(lnk.getValue())) + throw Base::RuntimeError("Object was deleted"); + + obj = lnk.getValue(); + sub = lnk.getSubValues(); + } +} + void TaskExtrudeParameters::onButtonFace(const bool pressed) { this->blockConnection(!pressed); @@ -534,6 +585,31 @@ void TaskExtrudeParameters::onFaceName(const QString& text) } } +void TaskExtrudeParameters::translateFaceName() +{ + ui->lineFaceName->setPlaceholderText(tr("No face selected")); + QVariant featureName = ui->lineFaceName->property("FeatureName"); + if (featureName.isValid()) { + QStringList parts = ui->lineFaceName->text().split(QChar::fromLatin1(':')); + QByteArray upToFace = ui->lineFaceName->property("FaceName").toByteArray(); + int faceId = -1; + bool ok = false; + if (upToFace.indexOf("Face") == 0) { + faceId = upToFace.remove(0,4).toInt(&ok); + } + + if (ok) { + ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3") + .arg(parts[0]) + .arg(tr("Face")) + .arg(faceId)); + } + else { + ui->lineFaceName->setText(parts[0]); + } + } +} + double TaskExtrudeParameters::getLength(void) const { return ui->lengthEdit->value().getValue(); @@ -549,15 +625,14 @@ double TaskExtrudeParameters::getOffset(void) const return ui->offsetEdit->value().getValue(); } -bool TaskExtrudeParameters::getAlongSketchNormal(void) const +bool TaskExtrudeParameters::getAlongSketchNormal(void) const { return ui->checkBoxAlongDirection->isChecked(); } -bool TaskExtrudeParameters::getCustom(void) const +bool TaskExtrudeParameters::getCustom(void) const { - // index 2 is hardcoded to custom vector - return ui->directionCB->currentIndex() == 2 ? true : false; + return (ui->directionCB->currentIndex() == DirectionModes::Custom); } std::string TaskExtrudeParameters::getReferenceAxis(void) const @@ -583,12 +658,12 @@ double TaskExtrudeParameters::getZDirection(void) const return ui->ZDirectionEdit->value(); } -bool TaskExtrudeParameters::getReversed(void) const +bool TaskExtrudeParameters::getReversed(void) const { return ui->checkBoxReversed->isChecked(); } -bool TaskExtrudeParameters::getMidplane(void) const +bool TaskExtrudeParameters::getMidplane(void) const { return ui->checkBoxMidplane->isChecked(); } @@ -600,14 +675,12 @@ int TaskExtrudeParameters::getMode(void) const QString TaskExtrudeParameters::getFaceName(void) const { - // 'Up to face' mode - if (getMode() == 3) { - QVariant featureName = ui->lineFaceName->property("FeatureName"); - if (featureName.isValid()) { - QString faceName = ui->lineFaceName->property("FaceName").toString(); - return getFaceReference(featureName.toString(), faceName); - } + QVariant featureName = ui->lineFaceName->property("FeatureName"); + if (featureName.isValid()) { + QString faceName = ui->lineFaceName->property("FaceName").toString(); + return getFaceReference(featureName.toString(), faceName); } + return QString::fromLatin1("None"); } @@ -615,77 +688,35 @@ void TaskExtrudeParameters::changeEvent(QEvent *e) { TaskBox::changeEvent(e); if (e->type() == QEvent::LanguageChange) { - ui->lengthEdit->blockSignals(true); - ui->lengthEdit2->blockSignals(true); - ui->offsetEdit->blockSignals(true); - ui->XDirectionEdit->blockSignals(true); - ui->YDirectionEdit->blockSignals(true); - ui->ZDirectionEdit->blockSignals(true); - ui->directionCB->blockSignals(true); + QSignalBlocker length(ui->lengthEdit); + QSignalBlocker length2(ui->lengthEdit2); + QSignalBlocker offset(ui->offsetEdit); + QSignalBlocker xdir(ui->XDirectionEdit); + QSignalBlocker ydir(ui->YDirectionEdit); + QSignalBlocker zdir(ui->ZDirectionEdit); + QSignalBlocker dir(ui->directionCB); + QSignalBlocker face(ui->lineFaceName); + QSignalBlocker mode(ui->changeMode); + + // Save all items + QStringList items; + for (int i = 0; i < ui->directionCB->count(); i++) + items << ui->directionCB->itemText(i); + + // Translate direction items int index = ui->directionCB->currentIndex(); - ui->directionCB->clear(); - ui->directionCB->addItem(tr("Sketch normal")); - ui->directionCB->addItem(tr("Select reference...")); - ui->directionCB->addItem(tr("Custom direction")); - ui->directionCB->setCurrentIndex(index); - ui->lineFaceName->blockSignals(true); - ui->changeMode->blockSignals(true); ui->retranslateUi(proxy); + + // Keep custom items + for (int i = 0; i < ui->directionCB->count(); i++) + items.pop_front(); + ui->directionCB->addItems(items); + ui->directionCB->setCurrentIndex(index); + + // Translate mode items translateModeList(ui->changeMode->currentIndex()); - ui->lineFaceName->setPlaceholderText(tr("No face selected")); - QVariant featureName = ui->lineFaceName->property("FeatureName"); - if (featureName.isValid()) { - QStringList parts = ui->lineFaceName->text().split(QChar::fromLatin1(':')); - QByteArray upToFace = ui->lineFaceName->property("FaceName").toByteArray(); - int faceId = -1; - bool ok = false; - if (upToFace.indexOf("Face") == 0) { - faceId = upToFace.remove(0,4).toInt(&ok); - } - - if (ok) { - ui->lineFaceName->setText(QString::fromLatin1("%1:%2%3") - .arg(parts[0]) - .arg(tr("Face")) - .arg(faceId)); - } - else { - ui->lineFaceName->setText(parts[0]); - } - } - - ui->lengthEdit->blockSignals(false); - ui->lengthEdit2->blockSignals(false); - ui->offsetEdit->blockSignals(false); - ui->XDirectionEdit->blockSignals(false); - ui->YDirectionEdit->blockSignals(false); - ui->ZDirectionEdit->blockSignals(false); - ui->directionCB->blockSignals(false); - ui->lineFaceName->blockSignals(false); - ui->changeMode->blockSignals(false); - } -} - -void TaskExtrudeParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const -{ - if (axesInList.empty()) - throw Base::RuntimeError("Not initialized!"); - - int num = ui->directionCB->currentIndex(); - const App::PropertyLinkSub& lnk = *(axesInList[num]); - if (lnk.getValue() == 0) { - // Note: It is possible that a face of an object is directly padded/pocketed without defining a profile shape - obj = nullptr; - sub.clear(); - } - else { - PartDesign::ProfileBased* pcDirection = static_cast(vp->getObject()); - if (!pcDirection->getDocument()->isIn(lnk.getValue())) - throw Base::RuntimeError("Object was deleted"); - - obj = lnk.getValue(); - sub = lnk.getSubValues(); + translateFaceName(); } } diff --git a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.h b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.h index 14ad607300..5c5a7e38a5 100644 --- a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.h +++ b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.h @@ -37,6 +37,10 @@ namespace App { class Property; } +namespace PartDesign { +class ProfileBased; +} + namespace PartDesignGui { @@ -44,6 +48,13 @@ class TaskExtrudeParameters : public TaskSketchBasedParameters { Q_OBJECT + enum DirectionModes { + Normal, + Select, + Custom, + Reference + }; + public: TaskExtrudeParameters(ViewProviderSketchBased *SketchBasedView, QWidget *parent, const std::string& pixmapname, const QString& parname); @@ -72,7 +83,8 @@ protected Q_SLOTS: virtual void onModeChanged(int); protected: - void setupDialog(bool); + void setupDialog(); + void readValuesFromHistory(); void changeEvent(QEvent *e) override; App::PropertyLinkSub* propReferenceAxis; void getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const; @@ -95,6 +107,14 @@ protected: virtual void updateUI(int index); void updateDirectionEdits(void); +private: + void tryRecomputeFeature(); + void translateFaceName(); + void connectSlots(); + bool hasProfileFace(PartDesign::ProfileBased*) const; + void selectedReferenceAxis(const Gui::SelectionChanges& msg); + void clearFaceName(); + protected: QWidget* proxy; std::unique_ptr ui; diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 9e7d902178..d3affd6c42 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -53,7 +53,12 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView, QWidget *parent, ui->lengthEdit2->setParamGrpPath(QByteArray("User parameter:BaseApp/History/PadLength2")); ui->offsetEdit->setParamGrpPath(QByteArray("User parameter:BaseApp/History/PadOffset")); - setupDialog(newObj); + setupDialog(); + + // if it is a newly created object use the last value of the history + if (newObj) { + readValuesFromHistory(); + } } TaskPadParameters::~TaskPadParameters() @@ -193,7 +198,10 @@ void TaskPadParameters::apply() FCMD_OBJ_CMD(obj, "ReferenceAxis = " << getReferenceAxis()); FCMD_OBJ_CMD(obj, "AlongSketchNormal = " << (getAlongSketchNormal() ? 1 : 0)); FCMD_OBJ_CMD(obj,"Type = " << getMode()); - QString facename = getFaceName(); + QString facename = QString::fromLatin1("None"); + if (static_cast(getMode()) == Modes::ToFace) { + facename = getFaceName(); + } FCMD_OBJ_CMD(obj,"UpToFace = " << facename.toLatin1().data()); FCMD_OBJ_CMD(obj,"Reversed = " << (getReversed()?1:0)); FCMD_OBJ_CMD(obj,"Midplane = " << (getMidplane()?1:0)); diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 086318c86f..c478ff5617 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -54,7 +54,12 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge ui->lengthEdit2->setParamGrpPath(QByteArray("User parameter:BaseApp/History/PocketLength2")); ui->offsetEdit->setParamGrpPath(QByteArray("User parameter:BaseApp/History/PocketOffset")); - setupDialog(newObj); + setupDialog(); + + // if it is a newly created object use the last value of the history + if (newObj) { + readValuesFromHistory(); + } } TaskPocketParameters::~TaskPocketParameters() @@ -199,7 +204,10 @@ void TaskPocketParameters::apply() ui->lengthEdit2->apply(); FCMD_OBJ_CMD(obj,"Type = " << getMode()); - QString facename = getFaceName(); + QString facename = QString::fromLatin1("None"); + if (static_cast(getMode()) == Modes::ToFace) { + facename = getFaceName(); + } FCMD_OBJ_CMD(obj,"UpToFace = " << facename.toLatin1().data()); FCMD_OBJ_CMD(obj,"Reversed = " << (getReversed()?1:0)); FCMD_OBJ_CMD(obj,"Midplane = " << (getMidplane()?1:0)); From 6c16094d5ac519cab9e53bb602bd1a19f568a095 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 27 Nov 2021 02:22:37 +0100 Subject: [PATCH 075/133] PD: fix bug in TaskExtrudeParameters When switching from Custom direction to Select reference mode do not jump back to Custom direction mode after selecting an edge --- .../PartDesign/Gui/TaskExtrudeParameters.cpp | 84 ++++++++++--------- .../PartDesign/Gui/TaskExtrudeParameters.h | 1 + 2 files changed, 47 insertions(+), 38 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp index 27c3ad9a00..7af1de6aa9 100644 --- a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp @@ -404,50 +404,26 @@ void TaskExtrudeParameters::onDirectionCBChanged(int num) this->blockConnection(false); // to distinguish that this is the direction selection selectionFace = false; + setDirectionMode(num); TaskSketchBasedParameters::onSelectReference(true, true, false, true, true); - return; } - else if (lnk.getValue()) { - if (!extrude->getDocument()->isIn(lnk.getValue())) { - Base::Console().Error("Object was deleted\n"); - return; + else { + if (lnk.getValue()) { + if (!extrude->getDocument()->isIn(lnk.getValue())) { + Base::Console().Error("Object was deleted\n"); + return; + } + propReferenceAxis->Paste(lnk); } - propReferenceAxis->Paste(lnk); - } - // in case the user is in selection mode, but changed his mind before selecting anything - exitSelectionMode(); + // in case the user is in selection mode, but changed his mind before selecting anything + exitSelectionMode(); - // disable AlongSketchNormal when the direction is already normal - if (num == DirectionModes::Normal) - ui->checkBoxAlongDirection->setEnabled(false); - else - ui->checkBoxAlongDirection->setEnabled(true); - - // if custom direction is used, show it - if (num == DirectionModes::Custom) { - ui->checkBoxDirection->setChecked(true); - extrude->UseCustomVector.setValue(true); + setDirectionMode(num); + extrude->ReferenceAxis.setValue(lnk.getValue(), lnk.getSubValues()); + tryRecomputeFeature(); + updateDirectionEdits(); } - else { - extrude->UseCustomVector.setValue(false); - } - - // if we dont use custom direction, only allow to show its direction - if (num != DirectionModes::Custom) { - ui->XDirectionEdit->setEnabled(false); - ui->YDirectionEdit->setEnabled(false); - ui->ZDirectionEdit->setEnabled(false); - } - else { - ui->XDirectionEdit->setEnabled(true); - ui->YDirectionEdit->setEnabled(true); - ui->ZDirectionEdit->setEnabled(true); - } - - extrude->ReferenceAxis.setValue(lnk.getValue(), lnk.getSubValues()); - tryRecomputeFeature(); - updateDirectionEdits(); } void TaskExtrudeParameters::onAlongSketchNormalChanged(bool on) @@ -504,6 +480,38 @@ void TaskExtrudeParameters::updateDirectionEdits() ui->ZDirectionEdit->setValue(extrude->Direction.getValue().z); } +void TaskExtrudeParameters::setDirectionMode(int index) +{ + PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); + // disable AlongSketchNormal when the direction is already normal + if (index == DirectionModes::Normal) + ui->checkBoxAlongDirection->setEnabled(false); + else + ui->checkBoxAlongDirection->setEnabled(true); + + // if custom direction is used, show it + if (index == DirectionModes::Custom) { + ui->checkBoxDirection->setChecked(true); + extrude->UseCustomVector.setValue(true); + } + else { + extrude->UseCustomVector.setValue(false); + } + + // if we dont use custom direction, only allow to show its direction + if (index != DirectionModes::Custom) { + ui->XDirectionEdit->setEnabled(false); + ui->YDirectionEdit->setEnabled(false); + ui->ZDirectionEdit->setEnabled(false); + } + else { + ui->XDirectionEdit->setEnabled(true); + ui->YDirectionEdit->setEnabled(true); + ui->ZDirectionEdit->setEnabled(true); + } + +} + void TaskExtrudeParameters::onMidplaneChanged(bool on) { PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); diff --git a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.h b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.h index 5c5a7e38a5..ae85079720 100644 --- a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.h +++ b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.h @@ -106,6 +106,7 @@ protected: virtual void translateModeList(int index); virtual void updateUI(int index); void updateDirectionEdits(void); + void setDirectionMode(int index); private: void tryRecomputeFeature(); From dc4a8e5beb3851ef8ee27a0df58b15f3d6b86812 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Thu, 25 Nov 2021 15:00:59 +0100 Subject: [PATCH 076/133] [Gui] Decimal separator substitution : add option in Preferences --- src/Gui/DlgGeneral.ui | 18 +++++++++++++++++- src/Gui/DlgGeneralImp.cpp | 2 ++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Gui/DlgGeneral.ui b/src/Gui/DlgGeneral.ui index 6e0f6c1fda..a48f1812f0 100644 --- a/src/Gui/DlgGeneral.ui +++ b/src/Gui/DlgGeneral.ui @@ -7,7 +7,7 @@ 0 0 425 - 578 + 767 @@ -89,6 +89,22 @@ + + + + If enabled, numerical keypad decimal separator will be substituted with locale separator + + + Substitute decimal separator (needs restart) + + + SubstituteDecimalSeparator + + + General + + + diff --git a/src/Gui/DlgGeneralImp.cpp b/src/Gui/DlgGeneralImp.cpp index a1053da4dd..5052ea1a4e 100644 --- a/src/Gui/DlgGeneralImp.cpp +++ b/src/Gui/DlgGeneralImp.cpp @@ -140,6 +140,7 @@ void DlgGeneralImp::saveSettings() App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")-> SetASCII("AutoloadModule", startWbName.toLatin1()); + ui->SubstituteDecimal->onSave(); ui->RecentFiles->onSave(); ui->SplashScreen->onSave(); ui->PythonWordWrap->onSave(); @@ -204,6 +205,7 @@ void DlgGeneralImp::loadSettings() QString startWbName = QLatin1String(start.c_str()); ui->AutoloadModuleCombo->setCurrentIndex(ui->AutoloadModuleCombo->findData(startWbName)); + ui->SubstituteDecimal->onRestore(); ui->RecentFiles->onRestore(); ui->SplashScreen->onRestore(); ui->PythonWordWrap->onRestore(); From 2650ef3b811606500fb77d63b031d2e053c71d0a Mon Sep 17 00:00:00 2001 From: Uwe Date: Sat, 27 Nov 2021 04:26:13 +0100 Subject: [PATCH 077/133] fix dialog height --- src/Gui/DlgGeneral.ui | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Gui/DlgGeneral.ui b/src/Gui/DlgGeneral.ui index a48f1812f0..4f58ad4fea 100644 --- a/src/Gui/DlgGeneral.ui +++ b/src/Gui/DlgGeneral.ui @@ -7,7 +7,7 @@ 0 0 425 - 767 + 598 @@ -593,13 +593,13 @@ horizontal space in Python console - Gui::PrefCheckBox - QCheckBox + Gui::PrefSpinBox + QSpinBox
Gui/PrefWidgets.h
- Gui::PrefSpinBox - QSpinBox + Gui::PrefCheckBox + QCheckBox
Gui/PrefWidgets.h
From 682cdb42efad52a7d94304406824b5e4d179f0a3 Mon Sep 17 00:00:00 2001 From: Uwe Date: Sat, 27 Nov 2021 05:38:16 +0100 Subject: [PATCH 078/133] [GUI] minor UI fix for a pref dialog - to keep the capitalization consistent in the dialog --- src/Gui/DlgGeneral.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gui/DlgGeneral.ui b/src/Gui/DlgGeneral.ui index 4f58ad4fea..58315e57a2 100644 --- a/src/Gui/DlgGeneral.ui +++ b/src/Gui/DlgGeneral.ui @@ -111,7 +111,7 @@ - Preference Packs + Preference packs From 0ccdf8b717f744090cc20acb43d7056a7a2d8a1e Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Wed, 24 Nov 2021 14:45:08 +0100 Subject: [PATCH 079/133] [Sketcher] Improve a bit XZ plane mapping by using quaternions directly --- src/Mod/Sketcher/Gui/SketchOrientationDialog.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mod/Sketcher/Gui/SketchOrientationDialog.cpp b/src/Mod/Sketcher/Gui/SketchOrientationDialog.cpp index 329ffe0276..f34091bfe7 100644 --- a/src/Mod/Sketcher/Gui/SketchOrientationDialog.cpp +++ b/src/Mod/Sketcher/Gui/SketchOrientationDialog.cpp @@ -60,7 +60,7 @@ void SketchOrientationDialog::accept() bool reverse = ui->Reverse_checkBox->isChecked(); if (ui->XY_radioButton->isChecked()) { if (reverse) { - Pos = Base::Placement(Base::Vector3d(0,0,offset),Base::Rotation(-1.0,0.0,0.0,0.0)); + Pos = Base::Placement(Base::Vector3d(0,0,offset),Base::Rotation(1.0,0.0,0.0,0.0)); DirType = 1; } else { @@ -70,21 +70,21 @@ void SketchOrientationDialog::accept() } else if (ui->XZ_radioButton->isChecked()) { if (reverse) { - Pos = Base::Placement(Base::Vector3d(0,offset,0),Base::Rotation(Base::Vector3d(0,sqrt(2.0)/2.0,sqrt(2.0)/2.0),M_PI)); + Pos = Base::Placement(Base::Vector3d(0,offset,0),Base::Rotation(0.0,1.0,1.0,0.0)); DirType = 3; } else { - Pos = Base::Placement(Base::Vector3d(0,offset,0),Base::Rotation(Base::Vector3d(-1,0,0),1.5*M_PI)); + Pos = Base::Placement(Base::Vector3d(0,offset,0),Base::Rotation(1.0,0.0,0.0,1.0)); DirType = 2; } } else if (ui->YZ_radioButton->isChecked()) { if (reverse) { - Pos = Base::Placement(Base::Vector3d(offset,0,0),Base::Rotation(-0.5,0.5,0.5,-0.5)); + Pos = Base::Placement(Base::Vector3d(offset,0,0),Base::Rotation(-1.0,1.0,1.0,-1.0)); DirType = 5; } else { - Pos = Base::Placement(Base::Vector3d(offset,0,0),Base::Rotation(0.5,0.5,0.5,0.5)); + Pos = Base::Placement(Base::Vector3d(offset,0,0),Base::Rotation(1.0,1.0,1.0,1.0)); DirType = 4; } } From 0ead26f5c278794eb09ae5ef867996f0ab5df89d Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Wed, 24 Nov 2021 14:52:45 +0100 Subject: [PATCH 080/133] [Sketcher] Floating point computation immunity for carbon copy parallel/aligned checks --- src/Mod/Sketcher/App/SketchObject.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index e737bf4925..91bef48921 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -3435,14 +3435,14 @@ bool SketchObject::isCarbonCopyAllowed(App::Document *pDoc, App::DocumentObject double doty = sy * ly; // the planes of the sketches must be parallel - if(!allowUnaligned && dot != 1.0 && dot != -1.0) { + if(!allowUnaligned && fabs(fabs(dot)-1) > Precision::Confusion()) { if (rsn) *rsn = rlNonParallel; return false; } // the axis must be aligned - if(!allowUnaligned && ((dotx != 1.0 && dotx != -1.0) || (doty != 1.0 && doty != -1.0))) { + if(!allowUnaligned && ((fabs(fabs(dotx)-1) > Precision::Confusion()) || (fabs(fabs(doty)-1) > Precision::Confusion()))) { if (rsn) *rsn = rlAxesMisaligned; return false; @@ -3454,14 +3454,14 @@ bool SketchObject::isCarbonCopyAllowed(App::Document *pDoc, App::DocumentObject double alignment = ddir * lnormal; - if(!allowUnaligned && (alignment != 1.0 && alignment != -1.0) && (psObj->Placement.getValue().getPosition() != this->Placement.getValue().getPosition()) ){ + if(!allowUnaligned && (fabs(fabs(alignment)-1) > Precision::Confusion()) && (psObj->Placement.getValue().getPosition() != this->Placement.getValue().getPosition()) ){ if (rsn) *rsn = rlOriginsMisaligned; return false; } - xinv = allowUnaligned?false:(dotx != 1.0); - yinv = allowUnaligned?false:(doty != 1.0); + xinv = allowUnaligned?false:(fabs(dotx-1) > Precision::Confusion()); + yinv = allowUnaligned?false:(fabs(doty-1) > Precision::Confusion()); return true; } From e2fec183db10030e9d858669d4401b9c8a4f8b2c Mon Sep 17 00:00:00 2001 From: Roy-043 <70520633+Roy-043@users.noreply.github.com> Date: Sun, 28 Nov 2021 11:50:49 +0100 Subject: [PATCH 081/133] Draft: fix style handling of PointColor and PointSize Draft_SetStyle did not handle PointColor and PointSize. --- src/Mod/Draft/draftguitools/gui_setstyle.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_setstyle.py b/src/Mod/Draft/draftguitools/gui_setstyle.py index 1d3046ea99..cce17d785e 100644 --- a/src/Mod/Draft/draftguitools/gui_setstyle.py +++ b/src/Mod/Draft/draftguitools/gui_setstyle.py @@ -123,7 +123,7 @@ class Draft_SetStyle_TaskPanel: return QtGui.QColor.fromRgbF(r,g,b) def getValues(self): - + preset = {} preset["LineColor"] = self.form.LineColor.property("color").rgb()<<8 preset["LineWidth"] = self.form.LineWidth.value() @@ -143,7 +143,7 @@ class Draft_SetStyle_TaskPanel: return preset def setValues(self,preset): - + from PySide import QtCore,QtGui self.form.LineColor.setProperty("color",self.getColor(preset.get("LineColor",255))) self.form.LineWidth.setValue(preset.get("LineWidth",1)) @@ -169,6 +169,8 @@ class Draft_SetStyle_TaskPanel: FreeCAD.ParamGet(self.p+"View").SetUnsigned("DefaultShapeLineColor",self.form.LineColor.property("color").rgb()<<8) FreeCAD.ParamGet(self.p+"View").SetInt("DefaultShapeLineWidth",self.form.LineWidth.value()) + FreeCAD.ParamGet(self.p+"View").SetUnsigned("DefaultShapeVertexColor",self.form.LineColor.property("color").rgb()<<8) + FreeCAD.ParamGet(self.p+"View").SetInt("DefaultShapePointSize",self.form.LineWidth.value()) FreeCAD.ParamGet(self.p+"Mod/Draft").SetInt("DefaultDrawStyle",self.form.DrawStyle.currentIndex()) FreeCAD.ParamGet(self.p+"Mod/Draft").SetInt("DefaultDisplayMode",self.form.DisplayMode.currentIndex()) FreeCAD.ParamGet(self.p+"View").SetUnsigned("DefaultShapeColor",self.form.ShapeColor.property("color").rgb()<<8) @@ -195,18 +197,17 @@ class Draft_SetStyle_TaskPanel: vobj.LineColor = self.form.LineColor.property("color").getRgbF() if "LineWidth" in vobj.PropertiesList: vobj.LineWidth = self.form.LineWidth.value() + if "PointColor" in vobj.PropertiesList: + vobj.PointColor = self.form.LineColor.property("color").getRgbF() + if "PointSize" in vobj.PropertiesList: + vobj.PointSize = self.form.LineWidth.value() if "DrawStyle" in vobj.PropertiesList: vobj.DrawStyle = ["Solid","Dashed","Dotted","Dashdot"][self.form.DrawStyle.currentIndex()] if "DisplayMode" in vobj.PropertiesList: dmodes = ["Flat Lines","Wireframe","Shaded","Points"] dm = dmodes[self.form.DisplayMode.currentIndex()] - if hasattr(vobj,"Proxy") and hasattr(vobj.Proxy,"getDisplayModes"): - dmodes = vobj.Proxy.getDisplayModes(vobj) - if dm in dmodes: - try: - vobj.DisplayMode = dm - except Exception: - pass + if dm in vobj.getEnumerationsOfProperty("DisplayMode"): + vobj.DisplayMode = dm if "ShapeColor" in vobj.PropertiesList: vobj.ShapeColor = self.form.ShapeColor.property("color").getRgbF() if "Transparency" in vobj.PropertiesList: @@ -233,7 +234,7 @@ class Draft_SetStyle_TaskPanel: vobj.LineSpacing = self.form.LineSpacing.value() def onApplyDim(self,index): - + import Draft objs = FreeCAD.ActiveDocument.Objects dims = Draft.getObjectsOfType(objs,"LinearDimension") From 5e0f8bf604fea3a9dcda515ad6df0e3db10e59b4 Mon Sep 17 00:00:00 2001 From: Roy-043 <70520633+Roy-043@users.noreply.github.com> Date: Sun, 28 Nov 2021 11:52:07 +0100 Subject: [PATCH 082/133] Draft: fix layer handling of PointColor and PointSize Draft_Layer did not handle PointColor and PointSize. --- .../Draft/draftviewproviders/view_layer.py | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/Mod/Draft/draftviewproviders/view_layer.py b/src/Mod/Draft/draftviewproviders/view_layer.py index 1f88700105..337a0e595a 100644 --- a/src/Mod/Draft/draftviewproviders/view_layer.py +++ b/src/Mod/Draft/draftviewproviders/view_layer.py @@ -38,7 +38,7 @@ import FreeCAD as App import FreeCADGui as Gui from draftutils.messages import _msg -from draftutils.translate import _tr +from draftutils.translate import translate from draftobjects.layer import Layer @@ -239,15 +239,17 @@ class ViewProviderLayer: # and then sets the target property accordingly if hasattr(target_vobj, prop): setattr(target_vobj, prop, getattr(vobj, prop)) - else: - continue - # Use the line color for the text color if it exists + # Use the line color for the point color and text color if prop == "LineColor": + if hasattr(target_vobj, "PointColor"): + target_vobj.PointColor = vobj.LineColor if hasattr(target_vobj, "TextColor"): target_vobj.TextColor = vobj.LineColor - if hasattr(target_vobj, "FontColor"): - target_vobj.FontColor = vobj.LineColor + # Use the line width for the point size + elif prop == "LineWidth": + if hasattr(target_vobj, "PointSize"): + target_vobj.PointSize = vobj.LineWidth def onChanged(self, vobj, prop): """Execute when a view property is changed.""" @@ -356,13 +358,13 @@ class ViewProviderLayer: def setupContextMenu(self, vobj, menu): """Set up actions to perform in the context menu.""" action1 = QtGui.QAction(QtGui.QIcon(":/icons/button_right.svg"), - _tr("Activate this layer"), + translate("draft", "Activate this layer"), menu) action1.triggered.connect(self.activate) menu.addAction(action1) action2 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_SelectGroup.svg"), - _tr("Select layer contents"), + translate("draft", "Select layer contents"), menu) action2.triggered.connect(self.select_contents) menu.addAction(action2) @@ -400,12 +402,12 @@ class ViewProviderLayerContainer: def setupContextMenu(self, vobj, menu): """Set up actions to perform in the context menu.""" action1 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_Layer.svg"), - _tr("Merge layer duplicates"), + translate("draft", "Merge layer duplicates"), menu) action1.triggered.connect(self.merge_by_name) menu.addAction(action1) action2 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_NewLayer.svg"), - _tr("Add new layer"), + translate("draft", "Add new layer"), menu) action2.triggered.connect(self.add_layer) menu.addAction(action2) @@ -416,7 +418,7 @@ class ViewProviderLayerContainer: return doc = App.ActiveDocument - doc.openTransaction(_tr("Merge layer duplicates")) + doc.openTransaction(translate("draft", "Merge layer duplicates")) layer_container = self.Object layers = [] @@ -448,12 +450,12 @@ class ViewProviderLayerContainer: base.Group = base_group to_delete.append(layer) elif layer.Label != base_label: - _msg(_tr("Relabeling layer:") + _msg(translate("draft", "Relabeling layer:") + " '{}' -> '{}'".format(layer.Label, base_label)) layer.Label = base_label for layer in to_delete: - _msg(_tr("Merging layer:") + " '{}'".format(layer.Label)) + _msg(translate("draft", "Merging layer:") + " '{}'".format(layer.Label)) doc.removeObject(layer.Name) doc.recompute() @@ -464,7 +466,7 @@ class ViewProviderLayerContainer: import Draft doc = App.ActiveDocument - doc.openTransaction(_tr("Add new layer")) + doc.openTransaction(translate("draft", "Add new layer")) Draft.make_layer() From 6d0c6b4119df48b65d1321f81ff399abee52f2d6 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Wed, 17 Nov 2021 22:20:35 -0500 Subject: [PATCH 083/133] [PD] Support "punctual" sections for PD Pipe Similar to PR #5170 for loft. This commit squashes the following commits. [PD] Refactor `Pipe::execute` and support point sections [PD] Allow point profile in selection-based pipe workflow [PD] Only add sketch subs if it is vertex [PD] Make both end faces of pipe regardless of point sections Earlier we were checking if these faces correspond to point sections, but apparently the end faces are independent of the order in which the sections are added, so the "front" may be the face closest to the last added section, rather than the "profile". Creating null faces and adding them for sewing together into a solid does not appear to have side-effects so far. --- src/Mod/PartDesign/App/FeaturePipe.cpp | 210 ++++++++++++++++--------- src/Mod/PartDesign/Gui/Command.cpp | 38 +++-- 2 files changed, 161 insertions(+), 87 deletions(-) diff --git a/src/Mod/PartDesign/App/FeaturePipe.cpp b/src/Mod/PartDesign/App/FeaturePipe.cpp index 77976627c3..f512f34b90 100644 --- a/src/Mod/PartDesign/App/FeaturePipe.cpp +++ b/src/Mod/PartDesign/App/FeaturePipe.cpp @@ -71,8 +71,8 @@ using namespace PartDesign; -const char* Pipe::TypeEnums[] = {"FullPath","UpToFace",NULL}; -const char* Pipe::TransitionEnums[] = {"Transformed","Right corner", "Round corner",NULL}; +const char* Pipe::TypeEnums[] = {"FullPath", "UpToFace", NULL}; +const char* Pipe::TransitionEnums[] = {"Transformed", "Right corner", "Round corner", NULL}; const char* Pipe::ModeEnums[] = {"Standard", "Fixed", "Frenet", "Auxiliary", "Binormal", NULL}; const char* Pipe::TransformEnums[] = {"Constant", "Multisection", "Linear", "S-shape", "Interpolation", NULL}; @@ -112,26 +112,54 @@ short Pipe::mustExecute() const App::DocumentObjectExecReturn *Pipe::execute(void) { - std::vector wires; - try { - wires = getProfileWires(); - } catch (const Base::Exception& e) { - return new App::DocumentObjectExecReturn(e.what()); - } + auto getSectionShape = + [](App::DocumentObject* feature, const std::vector &subs) -> TopoDS_Shape { + if (!feature || + !feature->isDerivedFrom(Part::Feature::getClassTypeId())) + throw Base::TypeError("Pipe: Invalid profile/section"); - TopoDS_Shape sketchshape = getVerifiedFace(); - if (sketchshape.IsNull()) - return new App::DocumentObjectExecReturn("Pipe: No valid sketch or face as first section"); - else { - //TODO: currently we only allow planar faces. the reason for this is that with other faces in front, we could - //not use the current simulate approach and build the start and end face from the wires. As the shell - //begins always at the spine and not the profile, the sketchshape cannot be used directly as front face. - //We would need a method to translate the front shape to match the shell starting position somehow... - TopoDS_Face face = TopoDS::Face(sketchshape); - BRepAdaptor_Surface adapt(face); - if (adapt.GetType() != GeomAbs_Plane) - return new App::DocumentObjectExecReturn("Pipe: Only planar faces supported"); - } + auto subName = subs.empty() ? "" : subs.front(); + + // only take the entire shape when we have a sketch selected, but + // not a point of the sketch + if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) && + !(subName.compare(0, 6, "Vertex") == 0)) + return static_cast(feature)->Shape.getValue(); + else { + if(subName.empty()) + throw Base::ValueError("Pipe: No valid subelement linked in Part::Feature"); + return static_cast(feature)->Shape.getShape().getSubShape(subName.c_str()); + } + }; + + auto addWiresToWireSections = + [](TopoDS_Shape& section, + std::vector>& wiresections) -> size_t { + TopExp_Explorer ex; + size_t i=0; + bool initialWireSectionsEmpty = wiresections.empty(); + for (ex.Init(section, TopAbs_WIRE); ex.More(); ex.Next(), ++i) { + // if profile was just a point then this is where we can first set our list + if (i>=wiresections.size()) { + if (initialWireSectionsEmpty) + wiresections.emplace_back(1, ex.Current()); + else + throw Base::ValueError("Pipe: Sections need to have the same amount of inner wires (except profile and last section, which can be points)"); + } + else + wiresections[i].push_back(TopoDS::Wire(ex.Current())); + } + return i; + }; + + // TODO: currently we can only allow planar faces, so add that check. + // The reason for this is that with other faces in front, we could not use the + // current simulate approach and build the start and end face from the wires. + // As the shell begins always at the spine and not the profile, the sketchshape + // cannot be used directly as front face. We would need a method to translate + // the front shape to match the shell starting position somehow... + std::vector wires; + TopoDS_Shape profilePoint; // if the Base property has a valid shape, fuse the pipe into it TopoDS_Shape base; @@ -142,16 +170,22 @@ App::DocumentObjectExecReturn *Pipe::execute(void) } try { - //setup the location + // setup the location this->positionByPrevious(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); if (!base.IsNull()) base.Move(invObjLoc); - //build the paths + // setup the profile section + TopoDS_Shape profileShape = getSectionShape(Profile.getValue(), + Profile.getSubValues()); + if (profileShape.IsNull()) + return new App::DocumentObjectExecReturn("Pipe: Could not obtain profile shape"); + + // build the paths App::DocumentObject* spine = Spine.getValue(); if (!(spine && spine->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) - return new App::DocumentObjectExecReturn("No spine linked."); + return new App::DocumentObjectExecReturn("No spine linked"); std::vector subedge = Spine.getSubValues(); TopoDS_Shape path; @@ -159,7 +193,6 @@ App::DocumentObjectExecReturn *Pipe::execute(void) buildPipePath(shape, subedge, path); path.Move(invObjLoc); - // auxiliary TopoDS_Shape auxpath; if (Mode.getValue()==3) { @@ -173,47 +206,57 @@ App::DocumentObjectExecReturn *Pipe::execute(void) auxpath.Move(invObjLoc); } - //build up multisections - auto multisections = Sections.getValues(); - std::vector> wiresections; - for (TopoDS_Wire& wire : wires) - wiresections.emplace_back(1, wire); - //maybe we need a sacling law + // build up multisections + auto multisections = Sections.getSubListValues(); + std::vector> wiresections; + + size_t numWires = addWiresToWireSections(profileShape, wiresections); + if (numWires == 0) { + // profileShape had no wires so only other valid option is single point section + TopExp_Explorer ex; + size_t i=0; + for (ex.Init(profileShape, TopAbs_VERTEX); ex.More(); ex.Next(), ++i) + profilePoint = ex.Current(); + if (i > 1) + return new App::DocumentObjectExecReturn("Pipe: Only one isolated point is needed if using a sketch with isolated points for section"); + } + + if (!profilePoint.IsNull() && + (Transformation.getValue() != 1 || multisections.empty())) + return new App::DocumentObjectExecReturn("Pipe: At least one section is needed when using a single point for profile"); + + // maybe we need a scaling law Handle(Law_Function) scalinglaw; - //see if we shall use multiple sections + bool isLastSectionVertex = false; + + // see if we shall use multiple sections if (Transformation.getValue() == 1) { - - //TODO: we need to order the sections to prevent occ from crahsing, as makepieshell connects - //the sections in the order of adding - - for (App::DocumentObject* obj : multisections) { - if (!obj->isDerivedFrom(Part::Feature::getClassTypeId())) - return new App::DocumentObjectExecReturn("All sections need to be part features"); + // TODO: we need to order the sections to prevent occ from crashing, + // as makepipeshell connects the sections in the order of adding + for (auto &subSet : multisections) { + if (!subSet.first->isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("Pipe: All sections need to be part features"); // if the section is an object's face then take just the face - TopoDS_Shape shape; - if (obj->isDerivedFrom(Part::Part2DObject::getClassTypeId())) - shape = static_cast(obj)->Shape.getValue(); - else { - auto subValues = Sections.getSubValues(obj); - if (subValues.empty()) - throw Base::ValueError("Pipe: No valid subelement in multisection"); + TopoDS_Shape shape = getSectionShape(subSet.first, subSet.second); + if (shape.IsNull()) + return new App::DocumentObjectExecReturn("Pipe: Could not obtain section shape"); - shape = static_cast(obj)->Shape.getShape(). getSubShape(subValues[0].c_str()); + size_t nWiresAdded = addWiresToWireSections(shape, wiresections); + if (nWiresAdded == 0) { + TopExp_Explorer ex; + size_t i=0; + for (ex.Init(shape, TopAbs_VERTEX); ex.More(); ex.Next(), ++i) { + if (isLastSectionVertex) + return new App::DocumentObjectExecReturn("Pipe: Only the profile and last section can be vertices"); + isLastSectionVertex = true; + for (auto &wires : wiresections) + wires.push_back(ex.Current()); + } } - TopExp_Explorer ex; - size_t i=0; - for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) { - if (i>=wiresections.size()) - return new App::DocumentObjectExecReturn("Multisections need to have the same amount of inner wires as the base section"); - wiresections[i].push_back(TopoDS::Wire(ex.Current())); - - ++i; - } - - if (iSet(0,1,1,ScalingData[0].x); + lin->Set(0, 1, 1, ScalingData[0].x); scalinglaw = lin; } @@ -232,7 +275,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void) return new App::DocumentObjectExecReturn("No valid data given for S-shape scaling mode"); Handle(Law_S) s = new Law_S(); - s->Set(0,1,ScalingData[0].y, 1, ScalingData[0].x, ScalingData[0].z); + s->Set(0, 1, ScalingData[0].y, 1, ScalingData[0].x, ScalingData[0].z); scalinglaw = s; }*/ @@ -243,20 +286,30 @@ App::DocumentObjectExecReturn *Pipe::execute(void) // build all shells std::vector shells; - std::vector frontwires, backwires; - for (std::vector& wires : wiresections) { + TopoDS_Shape copyProfilePoint(profilePoint); + if (!profilePoint.IsNull()) + copyProfilePoint.Move(invObjLoc); + + std::vector frontwires, backwires; + for (auto& wires : wiresections) { BRepOffsetAPI_MakePipeShell mkPS(TopoDS::Wire(path)); setupAlgorithm(mkPS, auxpath); if (!scalinglaw) { - for (TopoDS_Wire& wire : wires) { + if (!profilePoint.IsNull()) + mkPS.Add(copyProfilePoint); + + for (auto& wire : wires) { wire.Move(invObjLoc); mkPS.Add(wire); } } else { - for (TopoDS_Wire& wire : wires) { + if (!profilePoint.IsNull()) + mkPS.SetLaw(copyProfilePoint, scalinglaw); + + for (auto& wire : wires) { wire.Move(invObjLoc); mkPS.SetLaw(wire, scalinglaw); } @@ -272,6 +325,10 @@ App::DocumentObjectExecReturn *Pipe::execute(void) TopTools_ListOfShape sim; mkPS.Simulate(2, sim); + // Note that while we call them front and back, these sections + // appear to correspond to the front or back of the path. When one + // or both ends of the pipe are points, one or both of these wires + // (and eventually faces) will be null. frontwires.push_back(TopoDS::Wire(sim.First())); backwires.push_back(TopoDS::Wire(sim.Last())); } @@ -279,16 +336,19 @@ App::DocumentObjectExecReturn *Pipe::execute(void) BRepBuilderAPI_MakeSolid mkSolid; - if (!frontwires.empty()) { - // build the end faces, sew the shell and build the final solid - TopoDS_Shape front = Part::FaceMakerCheese::makeFace(frontwires); - TopoDS_Shape back = Part::FaceMakerCheese::makeFace(backwires); - + if (!frontwires.empty() || !backwires.empty()) { BRepBuilderAPI_Sewing sewer; sewer.SetTolerance(Precision::Confusion()); - sewer.Add(front); - sewer.Add(back); + // build the end faces, sew the shell and build the final solid + if (!frontwires.empty()) { + TopoDS_Shape front = Part::FaceMakerCheese::makeFace(frontwires); + sewer.Add(front); + } + if (!backwires.empty()) { + TopoDS_Shape back = Part::FaceMakerCheese::makeFace(backwires); + sewer.Add(back); + } for (TopoDS_Shape& s : shells) sewer.Add(s); @@ -393,7 +453,7 @@ void Pipe::setupAlgorithm(BRepOffsetAPI_MakePipeShell& mkPipeShell, TopoDS_Shape const Base::Vector3d& bVec = Binormal.getValue(); switch(Mode.getValue()) { case 1: - mkPipeShell.SetMode(gp_Ax2(gp_Pnt(0,0,0), gp_Dir(0,0,1), gp_Dir(1,0,0))); + mkPipeShell.SetMode(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1), gp_Dir(1, 0, 0))); break; case 2: mkPipeShell.SetMode(true); @@ -402,13 +462,13 @@ void Pipe::setupAlgorithm(BRepOffsetAPI_MakePipeShell& mkPipeShell, TopoDS_Shape auxiliary = true; break; case 4: - mkPipeShell.SetMode(gp_Dir(bVec.x,bVec.y,bVec.z)); + mkPipeShell.SetMode(gp_Dir(bVec.x, bVec.y, bVec.z)); break; } if (auxiliary) { mkPipeShell.SetMode(TopoDS::Wire(auxshape), AuxilleryCurvelinear.getValue()); - //mkPipeShell.SetMode(TopoDS::Wire(auxshape), AuxilleryCurvelinear.getValue(), BRepFill_ContactOnBorder); + // mkPipeShell.SetMode(TopoDS::Wire(auxshape), AuxilleryCurvelinear.getValue(), BRepFill_ContactOnBorder); } } @@ -430,7 +490,7 @@ void Pipe::getContinuousEdges(Part::TopoShape /*TopShape*/, std::vector< std::st { std::string aSubName = static_cast(SubNames.at(i)); - if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { + if (aSubName.size() > 4 && aSubName.substr(0, 4) == "Edge") { TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); const TopTools_ListOfShape& los = mapEdgeEdge.FindFromKey(edge); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 27a1b754a7..2518013471 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -996,7 +996,7 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons if (feature->isTouched()) feature->recomputeFeature(); - std::string FeatName = cmd->getUniqueObjectName(which.c_str(),pcActiveBody); + std::string FeatName = cmd->getUniqueObjectName(which.c_str(), pcActiveBody); Gui::Command::openCommand((std::string("Make ") + which).c_str()); @@ -1021,7 +1021,8 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons FCMD_OBJ_CMD(Feat,"Profile = (" << objCmd << ", [" << ss.str() << "])"); }; - if (which.compare("AdditiveLoft") == 0 || which.compare("SubtractiveLoft") == 0) { + if (which.compare("AdditiveLoft") == 0 || + which.compare("SubtractiveLoft") == 0) { // for additive and subtractive lofts set subvalues even for sketches // when a vertex is first selected auto subName = subs.empty() ? "" : subs.front(); @@ -1030,7 +1031,7 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons // just the sub-shapes if they are set. So when whole sketches are // desired, don not set sub-values. if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) && - !(subName.size() > 6 && subName.substr(0,6) == "Vertex")) + !(subName.size() > 6 && subName.substr(0, 6) == "Vertex")) runProfileCmd(); else runProfileCmdWithSubs(); @@ -1048,15 +1049,22 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons } } } - else { - if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) || subs.empty()) + else if (which.compare("AdditivePipe") == 0 || + which.compare("SubtractivePipe") == 0) { + // for additive and subtractive pipes set subvalues even for sketches + // to support point sections + auto subName = subs.empty() ? "" : subs.front(); + + // `ProfileBased::getProfileShape()` and other methods will return + // just the sub-shapes if they are set. So when whole sketches are + // desired, don not set sub-values. + if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) && + !(subName.size() > 6 && subName.substr(0, 6) == "Vertex")) runProfileCmd(); else runProfileCmdWithSubs(); - } - // for additive and subtractive pipes allow the user to preselect the spines - if (which.compare("AdditivePipe") == 0 || which.compare("SubtractivePipe") == 0) { + // for additive and subtractive pipes allow the user to preselect the spines std::vector selection = cmd->getSelection().getSelectionEx(); if (selection.size() == 2) { //treat additional selected object as spine std::vector subnames = selection[1].getSubNames(); @@ -1074,6 +1082,12 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons } } } + else { + if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) || subs.empty()) + runProfileCmd(); + else + runProfileCmdWithSubs(); + } func(static_cast(feature), Feat); }; @@ -1909,15 +1923,15 @@ void finishDressupFeature(const Gui::Command* cmd, const std::string& which, } str << "])"; - std::string FeatName = cmd->getUniqueObjectName(which.c_str(),base); + std::string FeatName = cmd->getUniqueObjectName(which.c_str(), base); - auto body = PartDesignGui::getBodyFor(base,false); + auto body = PartDesignGui::getBodyFor(base, false); if (!body) return; cmd->openCommand((std::string("Make ") + which).c_str()); FCMD_OBJ_CMD(body,"newObject('PartDesign::"<getDocument()->getObject(FeatName.c_str()); FCMD_OBJ_CMD(Feat,"Base = " << str.str()); - cmd->doCommand(cmd->Gui,"Gui.Selection.clearSelection()"); + cmd->doCommand(cmd->Gui, "Gui.Selection.clearSelection()"); finishFeature(cmd, Feat, base); App::DocumentObject* baseFeature = static_cast(Feat)->Base.getValue(); @@ -2090,7 +2104,7 @@ void CmdPartDesignThickness::activated(int iMsg) { std::string aSubName = static_cast(SubNames.at(i)); - if (aSubName.size() > 4 && aSubName.substr(0,4) != "Face") { + if (aSubName.size() > 4 && aSubName.substr(0, 4) != "Face") { // empty name or any other sub-element SubNames.erase(SubNames.begin()+i); } From bc90f4480b16eae1de05ea6d7e6ec322553684a8 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Sun, 28 Nov 2021 15:30:41 -0500 Subject: [PATCH 084/133] [PD] Use `compare` to compare strings instead of `substr` Used when finding subelements of a feature. Many of the comparisons used to also check for string lengths, but as far as I can tell they are not strictly necessary (see https://www.cplusplus.com/reference/string/string/substr/) and just `substr` can be used without them. However, `compare` explicitly is for comparing, and does not make a new object that `substr` does. --- src/Mod/PartDesign/App/FeatureDressUp.cpp | 4 ++-- src/Mod/PartDesign/App/FeatureLinearPattern.cpp | 4 ++-- src/Mod/PartDesign/App/FeatureLoft.cpp | 2 +- src/Mod/PartDesign/App/FeatureMirrored.cpp | 2 +- src/Mod/PartDesign/App/FeaturePipe.cpp | 4 ++-- src/Mod/PartDesign/App/FeaturePolarPattern.cpp | 2 +- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 8 ++++---- src/Mod/PartDesign/Gui/Command.cpp | 10 +++++----- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 8 ++++---- src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp | 2 +- src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp | 4 ++-- 11 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureDressUp.cpp b/src/Mod/PartDesign/App/FeatureDressUp.cpp index 430eac64ba..6068f48df4 100644 --- a/src/Mod/PartDesign/App/FeatureDressUp.cpp +++ b/src/Mod/PartDesign/App/FeatureDressUp.cpp @@ -116,7 +116,7 @@ void DressUp::getContinuousEdges(Part::TopoShape TopShape, std::vector< std::str { std::string aSubName = static_cast(SubNames.at(i)); - if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { + if (aSubName.compare(0, 4, "Edge") == 0) { TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); @@ -138,7 +138,7 @@ void DressUp::getContinuousEdges(Part::TopoShape TopShape, std::vector< std::str i++; } - else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { + else if(aSubName.compare(0, 4, "Face") == 0) { TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); TopTools_IndexedMapOfShape mapOfFaces; diff --git a/src/Mod/PartDesign/App/FeatureLinearPattern.cpp b/src/Mod/PartDesign/App/FeatureLinearPattern.cpp index 08ffa89d5b..7d571d66cf 100644 --- a/src/Mod/PartDesign/App/FeatureLinearPattern.cpp +++ b/src/Mod/PartDesign/App/FeatureLinearPattern.cpp @@ -98,12 +98,12 @@ const std::list LinearPattern::getTransformations(const std::vectorgetAxis(Part::Part2DObject::V_Axis); else if (subStrings[0] == "N_Axis") axis = refSketch->getAxis(Part::Part2DObject::N_Axis); - else if (subStrings[0].size() > 4 && subStrings[0].substr(0,4) == "Axis") { + else if (subStrings[0].compare(0, 4, "Axis") == 0) { int AxId = std::atoi(subStrings[0].substr(4,4000).c_str()); if (AxId >= 0 && AxId < refSketch->getAxisCount()) axis = refSketch->getAxis(AxId); } - else if (subStrings[0].substr(0,4) == "Edge") { + else if (subStrings[0].compare(0, 4, "Edge") == 0) { Part::TopoShape refShape = refSketch->Shape.getShape(); TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); TopoDS_Edge refEdge = TopoDS::Edge(ref); diff --git a/src/Mod/PartDesign/App/FeatureLoft.cpp b/src/Mod/PartDesign/App/FeatureLoft.cpp index 8a62a80774..20fd6c23ec 100644 --- a/src/Mod/PartDesign/App/FeatureLoft.cpp +++ b/src/Mod/PartDesign/App/FeatureLoft.cpp @@ -85,7 +85,7 @@ App::DocumentObjectExecReturn *Loft::execute(void) // only take the entire shape when we have a sketch selected, but // not a point of the sketch if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) && - !(subName.size() > 6 && subName.substr(0,6) == "Vertex")) + subName.compare(0, 6, "Vertex") != 0) return static_cast(feature)->Shape.getValue(); else { if(subName.empty()) diff --git a/src/Mod/PartDesign/App/FeatureMirrored.cpp b/src/Mod/PartDesign/App/FeatureMirrored.cpp index 5aa3e76495..b6e9d43694 100644 --- a/src/Mod/PartDesign/App/FeatureMirrored.cpp +++ b/src/Mod/PartDesign/App/FeatureMirrored.cpp @@ -77,7 +77,7 @@ const std::list Mirrored::getTransformations(const std::vectorgetAxis(Part::Part2DObject::H_Axis); else if (subStrings[0] == "") axis = refSketch->getAxis(Part::Part2DObject::N_Axis); - else if (subStrings[0].size() > 4 && subStrings[0].substr(0,4) == "Axis") { + else if (subStrings[0].compare(0, 4, "Axis") == 0) { int AxId = std::atoi(subStrings[0].substr(4,4000).c_str()); if (AxId >= 0 && AxId < refSketch->getAxisCount()) { axis = refSketch->getAxis(AxId); diff --git a/src/Mod/PartDesign/App/FeaturePipe.cpp b/src/Mod/PartDesign/App/FeaturePipe.cpp index f512f34b90..023a8d10bc 100644 --- a/src/Mod/PartDesign/App/FeaturePipe.cpp +++ b/src/Mod/PartDesign/App/FeaturePipe.cpp @@ -123,7 +123,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void) // only take the entire shape when we have a sketch selected, but // not a point of the sketch if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) && - !(subName.compare(0, 6, "Vertex") == 0)) + subName.compare(0, 6, "Vertex") != 0) return static_cast(feature)->Shape.getValue(); else { if(subName.empty()) @@ -490,7 +490,7 @@ void Pipe::getContinuousEdges(Part::TopoShape /*TopShape*/, std::vector< std::st { std::string aSubName = static_cast(SubNames.at(i)); - if (aSubName.size() > 4 && aSubName.substr(0, 4) == "Edge") { + if (aSubName.compare(0, 4, "Edge") == 0) { TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); const TopTools_ListOfShape& los = mapEdgeEdge.FindFromKey(edge); diff --git a/src/Mod/PartDesign/App/FeaturePolarPattern.cpp b/src/Mod/PartDesign/App/FeaturePolarPattern.cpp index 646216564a..5da35a4ee2 100644 --- a/src/Mod/PartDesign/App/FeaturePolarPattern.cpp +++ b/src/Mod/PartDesign/App/FeaturePolarPattern.cpp @@ -115,7 +115,7 @@ const std::list PolarPattern::getTransformations(const std::vectorgetAxis(Part::Part2DObject::V_Axis); else if (subStrings[0] == "N_Axis") axis = refSketch->getAxis(Part::Part2DObject::N_Axis); - else if (subStrings[0].size() > 4 && subStrings[0].substr(0,4) == "Axis") { + else if (subStrings[0].compare(0, 4, "Axis") == 0) { int AxId = std::atoi(subStrings[0].substr(4,4000).c_str()); if (AxId >= 0 && AxId < refSketch->getAxisCount()) axis = refSketch->getAxis(AxId); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 61642fa42c..9fd240f5e8 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -842,13 +842,13 @@ void ProfileBased::remapSupportShape(const TopoDS_Shape& newShape) for (std::vector::iterator it = subValues.begin(); it != subValues.end(); ++it) { std::string shapetype; - if (it->size() > 4 && it->substr(0,4) == "Face") { + if (it->compare(0, 4, "Face") == 0) { shapetype = "Face"; } - else if (it->size() > 4 && it->substr(0,4) == "Edge") { + else if (it->compare(0, 4, "Edge") == 0) { shapetype = "Edge"; } - else if (it->size() > 6 && it->substr(0,6) == "Vertex") { + else if (it->compare(0, 6, "Vertex") == 0) { shapetype = "Vertex"; } else { @@ -1073,7 +1073,7 @@ void ProfileBased::getAxis(const App::DocumentObject *pcReferenceAxis, const std hasValidAxis = true; axis = sketch->getAxis(Part::Part2DObject::N_Axis); } - else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0, 4) == "Axis") { + else if (subReferenceAxis[0].compare(0, 4, "Axis") == 0) { int AxId = std::atoi(subReferenceAxis[0].substr(4, 4000).c_str()); if (AxId >= 0 && AxId < sketch->getAxisCount()) { hasValidAxis = true; diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 2518013471..cfc3a655dc 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -1029,9 +1029,9 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons // `ProfileBased::getProfileShape()` and other methods will return // just the sub-shapes if they are set. So when whole sketches are - // desired, don not set sub-values. + // desired, do not set sub-values. if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) && - !(subName.size() > 6 && subName.substr(0, 6) == "Vertex")) + subName.compare(0, 6, "Vertex") != 0) runProfileCmd(); else runProfileCmdWithSubs(); @@ -1059,7 +1059,7 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons // just the sub-shapes if they are set. So when whole sketches are // desired, don not set sub-values. if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) && - !(subName.size() > 6 && subName.substr(0, 6) == "Vertex")) + subName.compare(0, 6, "Vertex") != 0) runProfileCmd(); else runProfileCmdWithSubs(); @@ -2048,7 +2048,7 @@ void CmdPartDesignDraft::activated(int iMsg) { std::string aSubName = static_cast(SubNames.at(i)); - if (aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { + if (aSubName.compare(0, 4, "Face") == 0) { // Check for valid face types TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); BRepAdaptor_Surface sf(face); @@ -2104,7 +2104,7 @@ void CmdPartDesignThickness::activated(int iMsg) { std::string aSubName = static_cast(SubNames.at(i)); - if (aSubName.size() > 4 && aSubName.substr(0, 4) != "Face") { + if (aSubName.compare(0, 4, "Face") != 0) { // empty name or any other sub-element SubNames.erase(SubNames.begin()+i); } diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index 920ef2bdbb..c3528aa0c5 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -148,7 +148,7 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c if (pObj && pObj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { std::string subName(sSubName); - if (edge && subName.size() > 4 && subName.substr(0,4) == "Edge") { + if (edge && subName.compare(0, 4, "Edge") == 0) { const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(subName.c_str()); const TopoDS_Edge& edgeShape = TopoDS::Edge(sh); @@ -162,7 +162,7 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c } } } - if (plane && subName.size() > 4 && subName.substr(0,4) == "Face") { + if (plane && subName.compare(0, 4, "Face") == 0) { const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(subName.c_str()); const TopoDS_Face& face = TopoDS::Face(sh); @@ -176,10 +176,10 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c } } } - if (point && subName.size() > 6 && subName.substr(0,6) == "Vertex") { + if (point && subName.compare(0, 6, "Vertex") == 0) { return true; } - if (circle && subName.size() > 4 && subName.substr(0,4) == "Edge") { + if (circle && subName.compare(0, 4, "Edge") == 0) { const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(subName.c_str()); const TopoDS_Edge& edgeShape = TopoDS::Edge(sh); diff --git a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp index 7af1de6aa9..2d66e23cec 100644 --- a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp @@ -84,7 +84,7 @@ void TaskExtrudeParameters::setupDialog() int faceId = -1; if (obj && !subStrings.empty()) { upToFace = subStrings.front(); - if (upToFace.substr(0,4) == "Face") + if (upToFace.compare(0, 4, "Face") == 0) faceId = std::atoi(&upToFace[4]); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp index 47bddf8086..31e7113fad 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp @@ -159,13 +159,13 @@ void ViewProviderShapeBinder::highlightReferences(const bool on, bool /*auxiliar for (std::string e : subs) { // Note: stoi may throw, but it strictly shouldn't happen - if(e.substr(4) == "Edge") { + if(e.compare(0, 4, "Edge") == 0) { int idx = std::stoi(e.substr(4)) - 1; assert ( idx>=0 ); if ( idx < (ssize_t) lcolors.size() ) lcolors[idx] = App::Color(1.0,0.0,1.0); // magenta } - else if(e.substr(4) == "Face") { + else if(e.compare(0, 4, "Face") == 0) { int idx = std::stoi(e.substr(4)) - 1; assert ( idx>=0 ); if ( idx < (ssize_t) fcolors.size() ) From 169c38622c1f6358e4f8303a5b8a569fbd0d3faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=A4hr?= Date: Wed, 24 Nov 2021 22:29:36 +0100 Subject: [PATCH 085/133] [PD] Helix: Offer profile's normal as axis Previously, only the vertical and horizontal axis of the profile was selectable in the task panel of the additive/subtractive helix. Now the profile's normal axis can be selected, too. This now allows to create helical extrusions or "twisted pockets". The order of the GUI entries was chosen to be in line with the order of axis selection of the multi-transform parameters. The actual feature's implementation needed adaption for this special case as in some places a unit vector (`gp_Dir`) was derived from the cross- product of axis and profile normal -- a null-vector when the axis *is* the normal. This caused the gp_Dir's ctor to throw. --- src/Mod/PartDesign/App/FeatureHelix.cpp | 23 ++++++++++++++++--- .../PartDesign/Gui/TaskHelixParameters.cpp | 1 + src/Mod/PartDesign/Gui/TaskHelixParameters.ui | 5 ++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureHelix.cpp b/src/Mod/PartDesign/App/FeatureHelix.cpp index a6fdedac22..5d6b6c8c54 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.cpp +++ b/src/Mod/PartDesign/App/FeatureHelix.cpp @@ -371,6 +371,20 @@ TopoDS_Shape Helix::generateHelixPath(void) Base::Vector3d normal = getProfileNormal(); Base::Vector3d start = v.Cross(normal); // pointing towards the desired helix start point. + + // if our axis is (nearly) aligned with the profile's normal, we're only interested in the "twist" + // of the helix. The actual starting point, and thus the radius, isn't important as long as it's + // somewhere in the profile's plane: an arbitrary vector perpendicular to the normal. + if (start.IsNull()) { + auto hopefullyNotParallel = Base::Vector3d(1.0, 2.0, 3.0); + start = normal.Cross(hopefullyNotParallel); + if (start.IsNull()) { + // bad luck + hopefullyNotParallel = Base::Vector3d(3.0, 2.0, 1.0); + start = normal.Cross(hopefullyNotParallel); + } + } + gp_Dir dir_start(start.x, start.y, start.z); // Find out in what quadrant relative to the axis the profile is located, and the exact position. @@ -447,6 +461,12 @@ TopoDS_Shape Helix::generateHelixPath(void) // this function calculates self intersection safe pitch based on the profile bounding box. double Helix::safePitch() { + Base::Vector3d v = Axis.getValue(); + Base::Vector3d n = getProfileNormal(); + Base::Vector3d s = v.Cross(n); // pointing towards the desired helix start point. + if (s.IsNull()) + return Precision::Confusion(); // if the axis orthogonal to the profile, any pitch >0 is safe + // Below is an approximation. It is possible to do the general way by solving for the pitch // where the helix is self intersecting. @@ -461,14 +481,11 @@ double Helix::safePitch() double X = Xmax - Xmin, Y = Ymax - Ymin, Z = Zmax - Zmin; - Base::Vector3d v = Axis.getValue(); gp_Dir dir(v.x,v.y,v.z); gp_Vec bbvec(X, Y, Z); double p0 = bbvec*dir; // safe pitch if angle=0 - Base::Vector3d n = getProfileNormal(); - Base::Vector3d s = v.Cross(n); // pointing towards the desired helix start point. gp_Dir dir_s(s.x, s.y, s.z); if (tan(abs(angle))*p0 > abs(bbvec*dir_s)) diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp index 029a63c661..85df9c4c39 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp @@ -202,6 +202,7 @@ void TaskHelixParameters::fillAxisCombo(bool forceRefill) PartDesign::ProfileBased* pcFeat = static_cast(vp->getObject()); Part::Part2DObject* pcSketch = dynamic_cast(pcFeat->Profile.getValue()); if (pcSketch){ + addAxisToCombo(pcSketch,"N_Axis",QObject::tr("Normal sketch axis")); addAxisToCombo(pcSketch,"V_Axis",QObject::tr("Vertical sketch axis")); addAxisToCombo(pcSketch,"H_Axis",QObject::tr("Horizontal sketch axis")); for (int i=0; i < pcSketch->getAxisCount(); i++) { diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.ui b/src/Mod/PartDesign/Gui/TaskHelixParameters.ui index 6d57f9d6a4..ae8efc5c19 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.ui @@ -70,6 +70,11 @@ Vertical sketch axis
+ + + Normal sketch axis + + Select reference... From 90f204038677edd84724d9157d29f23e98f7cc72 Mon Sep 17 00:00:00 2001 From: Uwe Date: Mon, 29 Nov 2021 00:11:40 +0100 Subject: [PATCH 086/133] [PD] fix increment of helix growth - it is not sensible that all helix geometries use 1 as increment in the dialog but the growth uses 5. Looking at the PR that introduced this feature it seems that this was just a copy issue from the angle edit since this uses 5 as increment. - the other changes are from Qt's Designer --- src/Mod/PartDesign/Gui/TaskHelixParameters.ui | 48 +++---------------- 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.ui b/src/Mod/PartDesign/Gui/TaskHelixParameters.ui index ae8efc5c19..4dc02dbf7d 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.ui @@ -7,15 +7,14 @@ 0 0 278 - 193 + 330 Form - - + @@ -31,10 +30,9 @@ - + - - + @@ -84,8 +82,7 @@ - - + @@ -116,11 +113,10 @@ Height-Turns-Growth - + - @@ -141,9 +137,6 @@ 0.000000000000000 - - 1.000000000000000 - 10.000000000000000 @@ -151,7 +144,6 @@ - @@ -172,9 +164,6 @@ 0.000000000000000 - - 1.000000000000000 - 30.000000000000000 @@ -182,7 +171,6 @@ - @@ -200,17 +188,13 @@ 0.000000000000000 - - 1.000000000000000 - - 3.0000000000000 + 3.000000000000000 - @@ -237,14 +221,10 @@ 5.000000000000000 - - 0.000000000000000 - - @@ -262,17 +242,10 @@ mm - - 5.000000000000000 - - - 0.000000000000000 - - @@ -283,7 +256,6 @@ - @@ -294,7 +266,6 @@ - @@ -305,7 +276,6 @@ - @@ -313,7 +283,6 @@ - @@ -324,9 +293,6 @@ - - - From 625c84e34a86cb2f176bcf9ded0abc408c2de066 Mon Sep 17 00:00:00 2001 From: Uwe Date: Sun, 28 Nov 2021 21:50:33 +0100 Subject: [PATCH 087/133] [PD] allow to move sweep sections Now that we have the feature that sweeps can have vertices as end or begin of a sweep, there is the need for the feature to move sections. For example vertices may only be the last section. --- src/Mod/PartDesign/Gui/TaskPipeParameters.cpp | 24 +++++++++++++++++++ src/Mod/PartDesign/Gui/TaskPipeParameters.h | 1 + src/Mod/PartDesign/Gui/TaskPipeScaling.ui | 13 +++++++--- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp b/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp index d7d1796ce0..ba80f2bd9e 100644 --- a/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp @@ -938,6 +938,9 @@ TaskPipeScaling::TaskPipeScaling(ViewProviderPipe* PipeView, bool /*newObj*/, QW ui->listWidgetReferences->setContextMenuPolicy(Qt::ActionsContextMenu); connect(remove, SIGNAL(triggered()), this, SLOT(onDeleteSection())); + connect(ui->listWidgetReferences->model(), + SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), this, SLOT(indexesMoved())); + this->groupLayout()->addWidget(proxy); PartDesign::Pipe* pipe = static_cast(PipeView->getObject()); @@ -964,6 +967,27 @@ TaskPipeScaling::~TaskPipeScaling() } } +void TaskPipeScaling::indexesMoved() +{ + QAbstractItemModel* model = qobject_cast(sender()); + if (!model) + return; + + PartDesign::Pipe* pipe = static_cast(vp->getObject()); + auto originals = pipe->Sections.getSubListValues(); + + QByteArray name; + int rows = model->rowCount(); + for (int i = 0; i < rows; i++) { + QModelIndex index = model->index(i, 0); + originals[i] = index.data(Qt::UserRole).value(); + } + + pipe->Sections.setSubListValues(originals); + recomputeFeature(); + updateUI(ui->stackedWidget->currentIndex()); +} + void TaskPipeScaling::clearButtons(const selectionModes notThis) { // TODO: Clear buttons in the other pipe taskboxes as well diff --git a/src/Mod/PartDesign/Gui/TaskPipeParameters.h b/src/Mod/PartDesign/Gui/TaskPipeParameters.h index 8c534f135e..f080561792 100644 --- a/src/Mod/PartDesign/Gui/TaskPipeParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPipeParameters.h @@ -145,6 +145,7 @@ private Q_SLOTS: void onButtonRefRemove(bool checked); void updateUI(int idx); void onDeleteSection(); + void indexesMoved(); protected: enum selectionModes { none, refAdd, refRemove }; diff --git a/src/Mod/PartDesign/Gui/TaskPipeScaling.ui b/src/Mod/PartDesign/Gui/TaskPipeScaling.ui index d06cbe8bc9..c3d535007b 100644 --- a/src/Mod/PartDesign/Gui/TaskPipeScaling.ui +++ b/src/Mod/PartDesign/Gui/TaskPipeScaling.ui @@ -6,8 +6,8 @@ 0 0 - 353 - 407 + 262 + 270 @@ -97,7 +97,14 @@ - + + + List can be reordered by dragging + + + QAbstractItemView::InternalMove + + From 1358cd021fe3338296337eb308f8c37d560478c5 Mon Sep 17 00:00:00 2001 From: Uwe Date: Mon, 29 Nov 2021 01:34:03 +0100 Subject: [PATCH 088/133] [PD] prevent invalid helix geometry in the height-turns-growth model height and growth must not be equally zero --- src/Mod/PartDesign/App/FeatureHelix.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureHelix.cpp b/src/Mod/PartDesign/App/FeatureHelix.cpp index 5d6b6c8c54..d10c1bd01c 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.cpp +++ b/src/Mod/PartDesign/App/FeatureHelix.cpp @@ -128,11 +128,14 @@ App::DocumentObjectExecReturn *Helix::execute(void) if (Height.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Error: height too small!"); if (Turns.getValue() < Precision::Confusion()) - return new App::DocumentObjectExecReturn("Error turns too small!"); + return new App::DocumentObjectExecReturn("Error: turns too small!"); Pitch.setValue(Height.getValue()/Turns.getValue()); } else if (mode == HelixMode::height_turns_growth) { if (Turns.getValue() < Precision::Confusion()) - return new App::DocumentObjectExecReturn("Error turns too small!"); + return new App::DocumentObjectExecReturn("Error: turns too small!"); + if ((Height.getValue() < Precision::Confusion()) + && (Growth.getValue() < Precision::Confusion())) + return new App::DocumentObjectExecReturn("Error: either height or growth must not be zero!"); Pitch.setValue(Height.getValue()/Turns.getValue()); } else { return new App::DocumentObjectExecReturn("Error: unsupported mode"); From 35683883cbd2def30aed25864ed0cbe59ae0d96b Mon Sep 17 00:00:00 2001 From: Uwe Date: Mon, 29 Nov 2021 00:53:19 +0100 Subject: [PATCH 089/133] [PD] allow negative helix growth Helices that become smaller with every turn are geometrically perfectly valid. Therefore we cannot forbid this. (For example when creating a helix from a face you often cannot move it so that you can apply a positive growth.) --- src/Mod/PartDesign/App/FeatureHelix.cpp | 12 +++++++++--- src/Mod/PartDesign/App/FeatureHelix.h | 2 +- src/Mod/PartDesign/Gui/TaskHelixParameters.h | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureHelix.cpp b/src/Mod/PartDesign/App/FeatureHelix.cpp index d10c1bd01c..11de1bf859 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.cpp +++ b/src/Mod/PartDesign/App/FeatureHelix.cpp @@ -134,14 +134,13 @@ App::DocumentObjectExecReturn *Helix::execute(void) if (Turns.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Error: turns too small!"); if ((Height.getValue() < Precision::Confusion()) - && (Growth.getValue() < Precision::Confusion())) + && (abs(Growth.getValue()) < Precision::Confusion())) return new App::DocumentObjectExecReturn("Error: either height or growth must not be zero!"); Pitch.setValue(Height.getValue()/Turns.getValue()); } else { return new App::DocumentObjectExecReturn("Error: unsupported mode"); } - TopoDS_Shape sketchshape; try { sketchshape = getVerifiedFace(); @@ -407,7 +406,7 @@ TopoDS_Shape Helix::generateHelixPath(void) bool growthMode = std::string(Mode.getValueAsString()).find("growth") != std::string::npos; double radiusTop; if (growthMode) - radiusTop = radius + turns*growth; + radiusTop = radius + turns * growth; else radiusTop = radius + height * tan(Base::toRadians(angle)); @@ -534,6 +533,13 @@ void Helix::handleChangedPropertyType(Base::XMLReader& reader, const char* TypeN TurnsProperty.Restore(reader); Turns.setValue(TurnsProperty.getValue()); } + // property Growth had the App::PropertyLength and was changed to App::PropertyDistance + else if (prop == &Growth && strcmp(TypeName, "App::PropertyLength") == 0) { + App::PropertyLength GrowthProperty; + // restore the PropertyLength to be able to set its value + GrowthProperty.Restore(reader); + Growth.setValue(GrowthProperty.getValue()); + } else { ProfileBased::handleChangedPropertyType(reader, TypeName, prop); } diff --git a/src/Mod/PartDesign/App/FeatureHelix.h b/src/Mod/PartDesign/App/FeatureHelix.h index 7e9823a0ef..f834f08be0 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.h +++ b/src/Mod/PartDesign/App/FeatureHelix.h @@ -52,7 +52,7 @@ public: App::PropertyFloatConstraint Turns; App::PropertyBool LeftHanded; App::PropertyAngle Angle; - App::PropertyLength Growth; + App::PropertyDistance Growth; App::PropertyEnumeration Mode; App::PropertyBool Outside; App::PropertyBool HasBeenEdited; diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.h b/src/Mod/PartDesign/Gui/TaskHelixParameters.h index 8b9b017299..110cad5444 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.h +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.h @@ -95,7 +95,7 @@ protected: App::PropertyBool* propReversed; App::PropertyLinkSub* propReferenceAxis; App::PropertyAngle* propAngle; - App::PropertyLength* propGrowth; + App::PropertyDistance* propGrowth; App::PropertyEnumeration* propMode; App::PropertyBool* propOutside; From 955af2fa8d7db1692ccfbe20bee5556e9b2a2ea9 Mon Sep 17 00:00:00 2001 From: Uwe Date: Mon, 29 Nov 2021 12:05:10 +0100 Subject: [PATCH 090/133] [PD] use existing definition for PI in Helix - also a lot of style fixes kindly done by MSVC --- src/Mod/PartDesign/App/FeatureHelix.cpp | 96 ++++++----- src/Mod/PartDesign/App/FeatureHelix.h | 2 +- .../PartDesign/Gui/TaskHelixParameters.cpp | 163 +++++++++--------- src/Mod/PartDesign/Gui/TaskHelixParameters.h | 10 +- 4 files changed, 144 insertions(+), 127 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureHelix.cpp b/src/Mod/PartDesign/App/FeatureHelix.cpp index 11de1bf859..1ab173895c 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.cpp +++ b/src/Mod/PartDesign/App/FeatureHelix.cpp @@ -63,11 +63,9 @@ # include "FeatureHelix.h" -const double PI = 3.14159265359; - using namespace PartDesign; -const char* Helix::ModeEnums[] = {"pitch-height-angle", "pitch-turns-angle", "height-turns-angle", "height-turns-growth", NULL}; +const char* Helix::ModeEnums[] = { "pitch-height-angle", "pitch-turns-angle", "height-turns-angle", "height-turns-growth", NULL }; PROPERTY_SOURCE(PartDesign::Helix, PartDesign::ProfileBased) @@ -108,43 +106,48 @@ short Helix::mustExecute() const return ProfileBased::mustExecute(); } -App::DocumentObjectExecReturn *Helix::execute(void) +App::DocumentObjectExecReturn* Helix::execute(void) { - // Validate and normalize parameters + // Validate and normalize parameters HelixMode mode = static_cast(Mode.getValue()); if (mode == HelixMode::pitch_height_angle) { if (Pitch.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Error: Pitch too small"); if (Height.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Error: height too small!"); - Turns.setValue(Height.getValue()/Pitch.getValue()); - } else if (mode == HelixMode::pitch_turns_angle) { + Turns.setValue(Height.getValue() / Pitch.getValue()); + } + else if (mode == HelixMode::pitch_turns_angle) { if (Pitch.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Error: pitch too small!"); if (Turns.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Error: turns too small!"); - Height.setValue(Turns.getValue()*Pitch.getValue()); - } else if (mode == HelixMode::height_turns_angle) { + Height.setValue(Turns.getValue() * Pitch.getValue()); + } + else if (mode == HelixMode::height_turns_angle) { if (Height.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Error: height too small!"); if (Turns.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Error: turns too small!"); - Pitch.setValue(Height.getValue()/Turns.getValue()); - } else if (mode == HelixMode::height_turns_growth) { + Pitch.setValue(Height.getValue() / Turns.getValue()); + } + else if (mode == HelixMode::height_turns_growth) { if (Turns.getValue() < Precision::Confusion()) return new App::DocumentObjectExecReturn("Error: turns too small!"); if ((Height.getValue() < Precision::Confusion()) && (abs(Growth.getValue()) < Precision::Confusion())) return new App::DocumentObjectExecReturn("Error: either height or growth must not be zero!"); - Pitch.setValue(Height.getValue()/Turns.getValue()); - } else { + Pitch.setValue(Height.getValue() / Turns.getValue()); + } + else { return new App::DocumentObjectExecReturn("Error: unsupported mode"); } TopoDS_Shape sketchshape; try { sketchshape = getVerifiedFace(); - } catch (const Base::Exception& e) { + } + catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } @@ -165,7 +168,8 @@ App::DocumentObjectExecReturn *Helix::execute(void) TopoDS_Shape base; try { base = getBaseShape(); - } catch (const Base::Exception&) { + } + catch (const Base::Exception&) { // fall back to support (for legacy features) base = TopoDS_Shape(); } @@ -173,7 +177,8 @@ App::DocumentObjectExecReturn *Helix::execute(void) // update Axis from ReferenceAxis try { updateAxis(); - } catch (const Base::Exception& e) { + } + catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } @@ -189,18 +194,19 @@ App::DocumentObjectExecReturn *Helix::execute(void) std::vector wires; try { wires = getProfileWires(); - } catch (const Base::Exception& e) { + } + catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } std::vector> wiresections; - for(TopoDS_Wire& wire : wires) + for (TopoDS_Wire& wire : wires) wiresections.emplace_back(1, wire); //build all shells std::vector shells; std::vector frontwires, backwires; - for(std::vector& wires : wiresections) { + for (std::vector& wires : wiresections) { BRepOffsetAPI_MakePipeShell mkPS(TopoDS::Wire(path)); @@ -208,7 +214,7 @@ App::DocumentObjectExecReturn *Helix::execute(void) mkPS.SetTransitionMode(BRepBuilderAPI_Transformed); mkPS.SetMode(true); //This is for frenet - for(TopoDS_Wire& wire : wires) { + for (TopoDS_Wire& wire : wires) { wire.Move(invObjLoc); mkPS.Add(wire); } @@ -233,19 +239,20 @@ App::DocumentObjectExecReturn *Helix::execute(void) if (!frontwires.empty()) { // build the end faces, sew the shell and build the final solid TopoDS_Shape front = Part::FaceMakerCheese::makeFace(frontwires); - TopoDS_Shape back = Part::FaceMakerCheese::makeFace(backwires); + TopoDS_Shape back = Part::FaceMakerCheese::makeFace(backwires); BRepBuilderAPI_Sewing sewer; sewer.SetTolerance(Precision::Confusion()); sewer.Add(front); sewer.Add(back); - for(TopoDS_Shape& s : shells) + for (TopoDS_Shape& s : shells) sewer.Add(s); sewer.Perform(); mkSolid.Add(TopoDS::Shell(sewer.SewedShape())); - } else { + } + else { // shells are already closed - add them directly for (TopoDS_Shape& s : shells) { mkSolid.Add(TopoDS::Shell(s)); @@ -307,7 +314,8 @@ App::DocumentObjectExecReturn *Helix::execute(void) return new App::DocumentObjectExecReturn("Error: Intersecting the helix failed"); boolOp = this->getSolid(mkCom.Shape()); - } else { + } + else { BRepAlgoAPI_Cut mkCut(base, result); if (!mkCut.IsDone()) return new App::DocumentObjectExecReturn("Error: Subtracting the helix failed"); @@ -343,14 +351,14 @@ App::DocumentObjectExecReturn *Helix::execute(void) void Helix::updateAxis(void) { - App::DocumentObject *pcReferenceAxis = ReferenceAxis.getValue(); - const std::vector &subReferenceAxis = ReferenceAxis.getSubValues(); + App::DocumentObject* pcReferenceAxis = ReferenceAxis.getValue(); + const std::vector& subReferenceAxis = ReferenceAxis.getSubValues(); Base::Vector3d base; Base::Vector3d dir; getAxis(pcReferenceAxis, subReferenceAxis, base, dir, false); - Base.setValue(base.x,base.y,base.z); - Axis.setValue(dir.x,dir.y,dir.z); + Base.setValue(base.x, base.y, base.z); + Axis.setValue(dir.x, dir.y, dir.z); } TopoDS_Shape Helix::generateHelixPath(void) @@ -367,9 +375,9 @@ TopoDS_Shape Helix::generateHelixPath(void) // get revolve axis Base::Vector3d b = Base.getValue(); - gp_Pnt pnt(b.x,b.y,b.z); + gp_Pnt pnt(b.x, b.y, b.z); Base::Vector3d v = Axis.getValue(); - gp_Dir dir(v.x,v.y,v.z); + gp_Dir dir(v.x, v.y, v.z); Base::Vector3d normal = getProfileNormal(); Base::Vector3d start = v.Cross(normal); // pointing towards the desired helix start point. @@ -391,14 +399,14 @@ TopoDS_Shape Helix::generateHelixPath(void) // Find out in what quadrant relative to the axis the profile is located, and the exact position. Base::Vector3d profileCenter = getProfileCenterPoint(); - double axisOffset = profileCenter*start - b*start; - double startOffset = profileCenter*v - b*v; + double axisOffset = profileCenter * start - b * start; + double startOffset = profileCenter * v - b * v; double radius = std::fabs(axisOffset); bool turned = axisOffset < 0; - if (radius < Precision::Confusion()) { + if (radius < Precision::Confusion()) { // in this case ensure that axis is not in the sketch plane - if (std::fabs(v*normal) < Precision::Confusion()) + if (std::fabs(v * normal) < Precision::Confusion()) throw Base::ValueError("Error: Result is self intersecting"); radius = 1.0; //fallback to radius 1 } @@ -430,19 +438,19 @@ TopoDS_Shape Helix::generateHelixPath(void) if (reversed) { - mov.SetRotation(gp_Ax1(origo, dir_axis2), PI); + mov.SetRotation(gp_Ax1(origo, dir_axis2), M_PI); TopLoc_Location loc(mov); path.Move(loc); } if (abs(startOffset) > 0) { // translate the helix so that the starting point aligns with the profile - mov.SetTranslation(startOffset*gp_Vec(dir_axis1)); + mov.SetTranslation(startOffset * gp_Vec(dir_axis1)); TopLoc_Location loc(mov); path.Move(loc); } if (turned) { // turn the helix so that the starting point aligns with the profile - mov.SetRotation(gp_Ax1(origo, dir_axis1), PI); + mov.SetRotation(gp_Ax1(origo, dir_axis1), M_PI); TopLoc_Location loc(mov); path.Move(loc); } @@ -472,7 +480,7 @@ double Helix::safePitch() // Below is an approximation. It is possible to do the general way by solving for the pitch // where the helix is self intersecting. - double angle = Angle.getValue()/180.0*PI; + double angle = Angle.getValue() / 180.0 * M_PI; TopoDS_Shape sketchshape = getVerifiedFace(); Bnd_Box bb; @@ -483,15 +491,15 @@ double Helix::safePitch() double X = Xmax - Xmin, Y = Ymax - Ymin, Z = Zmax - Zmin; - gp_Dir dir(v.x,v.y,v.z); + gp_Dir dir(v.x, v.y, v.z); gp_Vec bbvec(X, Y, Z); - double p0 = bbvec*dir; // safe pitch if angle=0 + double p0 = bbvec * dir; // safe pitch if angle=0 gp_Dir dir_s(s.x, s.y, s.z); - if (tan(abs(angle))*p0 > abs(bbvec*dir_s)) - return abs(bbvec*dir_s)/tan(abs(angle)); + if (tan(abs(angle)) * p0 > abs(bbvec * dir_s)) + return abs(bbvec * dir_s) / tan(abs(angle)); else return p0; } @@ -507,7 +515,7 @@ void Helix::proposeParameters(bool force) double pitch = 1.1 * sqrt(bb.SquareExtent()); Pitch.setValue(pitch); - Height.setValue(pitch*3.0); + Height.setValue(pitch * 3.0); HasBeenEdited.setValue(1); } } @@ -521,7 +529,7 @@ Base::Vector3d Helix::getProfileCenterPoint() box.SetGap(0.0); double xmin, ymin, zmin, xmax, ymax, zmax; box.Get(xmin, ymin, zmin, xmax, ymax, zmax); - return Base::Vector3d(0.5*(xmin+xmax), 0.5*(ymin+ymax), 0.5*(zmin+zmax)); + return Base::Vector3d(0.5 * (xmin + xmax), 0.5 * (ymin + ymax), 0.5 * (zmin + zmax)); } void Helix::handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName, App::Property* prop) diff --git a/src/Mod/PartDesign/App/FeatureHelix.h b/src/Mod/PartDesign/App/FeatureHelix.h index f834f08be0..904caf96cc 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.h +++ b/src/Mod/PartDesign/App/FeatureHelix.h @@ -64,7 +64,7 @@ public: /** @name methods override feature */ //@{ - App::DocumentObjectExecReturn *execute(void); + App::DocumentObjectExecReturn* execute(void); short mustExecute() const; /// returns the type name of the view provider const char* getViewProviderName(void) const { diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp index 85df9c4c39..bc9e878ce6 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp @@ -61,9 +61,9 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskHelixParameters */ -TaskHelixParameters::TaskHelixParameters(PartDesignGui::ViewProviderHelix *HelixView, QWidget *parent) +TaskHelixParameters::TaskHelixParameters(PartDesignGui::ViewProviderHelix* HelixView, QWidget* parent) : TaskSketchBasedParameters(HelixView, parent, "PartDesign_AdditiveHelix", tr("Helix parameters")), - ui (new Ui_TaskHelixParameters) + ui(new Ui_TaskHelixParameters) { // we need a separate container widget to add all controls to proxy = new QWidget(this); @@ -71,27 +71,27 @@ TaskHelixParameters::TaskHelixParameters(PartDesignGui::ViewProviderHelix *Helix QMetaObject::connectSlotsByName(this); connect(ui->pitch, SIGNAL(valueChanged(double)), - this, SLOT(onPitchChanged(double))); + this, SLOT(onPitchChanged(double))); connect(ui->height, SIGNAL(valueChanged(double)), - this, SLOT(onHeightChanged(double))); + this, SLOT(onHeightChanged(double))); connect(ui->turns, SIGNAL(valueChanged(double)), - this, SLOT(onTurnsChanged(double))); + this, SLOT(onTurnsChanged(double))); connect(ui->coneAngle, SIGNAL(valueChanged(double)), - this, SLOT(onAngleChanged(double))); + this, SLOT(onAngleChanged(double))); connect(ui->growth, SIGNAL(valueChanged(double)), - this, SLOT(onGrowthChanged(double))); + this, SLOT(onGrowthChanged(double))); connect(ui->axis, SIGNAL(activated(int)), - this, SLOT(onAxisChanged(int))); + this, SLOT(onAxisChanged(int))); connect(ui->checkBoxLeftHanded, SIGNAL(toggled(bool)), - this, SLOT(onLeftHandedChanged(bool))); + this, SLOT(onLeftHandedChanged(bool))); connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), - this, SLOT(onReversedChanged(bool))); + this, SLOT(onReversedChanged(bool))); connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), - this, SLOT(onUpdateView(bool))); + this, SLOT(onUpdateView(bool))); connect(ui->inputMode, SIGNAL(activated(int)), - this, SLOT(onModeChanged(int))); + this, SLOT(onModeChanged(int))); connect(ui->checkBoxOutside, SIGNAL(toggled(bool)), - this, SLOT(onOutsideChanged(bool))); + this, SLOT(onOutsideChanged(bool))); this->groupLayout()->addWidget(proxy); @@ -153,11 +153,11 @@ TaskHelixParameters::TaskHelixParameters(PartDesignGui::ViewProviderHelix *Helix updateUI(); // enable use of parametric expressions for the numerical fields - ui->pitch->bind(static_cast(pcFeat)->Pitch); - ui->height->bind(static_cast(pcFeat)->Height); - ui->turns->bind(static_cast(pcFeat)->Turns); - ui->coneAngle->bind(static_cast(pcFeat)->Angle); - ui->growth->bind(static_cast(pcFeat)->Growth); + ui->pitch->bind(static_cast(pcFeat)->Pitch); + ui->height->bind(static_cast(pcFeat)->Height); + ui->turns->bind(static_cast(pcFeat)->Turns); + ui->coneAngle->bind(static_cast(pcFeat)->Angle); + ui->growth->bind(static_cast(pcFeat)->Growth); ui->axis->blockSignals(false); ui->pitch->blockSignals(false); @@ -169,20 +169,21 @@ TaskHelixParameters::TaskHelixParameters(PartDesignGui::ViewProviderHelix *Helix ui->checkBoxReversed->blockSignals(false); ui->checkBoxOutside->blockSignals(false); - setFocus (); + setFocus(); //show the parts coordinate system axis for selection - PartDesign::Body * body = PartDesign::Body::findBodyOf ( vp->getObject () ); - if(body) { + PartDesign::Body* body = PartDesign::Body::findBodyOf(vp->getObject()); + if (body) { try { - App::Origin *origin = body->getOrigin(); + App::Origin* origin = body->getOrigin(); ViewProviderOrigin* vpOrigin; vpOrigin = static_cast(Gui::Application::Instance->getViewProvider(origin)); vpOrigin->setTemporaryVisibility(true, false); - } catch (const Base::Exception &ex) { + } + catch (const Base::Exception& ex) { ex.ReportException(); } - } + } } void TaskHelixParameters::fillAxisCombo(bool forceRefill) @@ -193,7 +194,7 @@ void TaskHelixParameters::fillAxisCombo(bool forceRefill) if (axesInList.empty()) forceRefill = true;//not filled yet, full refill - if (forceRefill){ + if (forceRefill) { ui->axis->clear(); this->axesInList.clear(); @@ -201,53 +202,54 @@ void TaskHelixParameters::fillAxisCombo(bool forceRefill) //add sketch axes PartDesign::ProfileBased* pcFeat = static_cast(vp->getObject()); Part::Part2DObject* pcSketch = dynamic_cast(pcFeat->Profile.getValue()); - if (pcSketch){ - addAxisToCombo(pcSketch,"N_Axis",QObject::tr("Normal sketch axis")); - addAxisToCombo(pcSketch,"V_Axis",QObject::tr("Vertical sketch axis")); - addAxisToCombo(pcSketch,"H_Axis",QObject::tr("Horizontal sketch axis")); - for (int i=0; i < pcSketch->getAxisCount(); i++) { - QString itemText = QObject::tr("Construction line %1").arg(i+1); + if (pcSketch) { + addAxisToCombo(pcSketch, "N_Axis", QObject::tr("Normal sketch axis")); + addAxisToCombo(pcSketch, "V_Axis", QObject::tr("Vertical sketch axis")); + addAxisToCombo(pcSketch, "H_Axis", QObject::tr("Horizontal sketch axis")); + for (int i = 0; i < pcSketch->getAxisCount(); i++) { + QString itemText = QObject::tr("Construction line %1").arg(i + 1); std::stringstream sub; sub << "Axis" << i; - addAxisToCombo(pcSketch,sub.str(),itemText); + addAxisToCombo(pcSketch, sub.str(), itemText); } } //add part axes - PartDesign::Body * body = PartDesign::Body::findBodyOf ( pcFeat ); + PartDesign::Body* body = PartDesign::Body::findBodyOf(pcFeat); if (body) { try { App::Origin* orig = body->getOrigin(); - addAxisToCombo(orig->getX(),"",tr("Base X axis")); - addAxisToCombo(orig->getY(),"",tr("Base Y axis")); - addAxisToCombo(orig->getZ(),"",tr("Base Z axis")); - } catch (const Base::Exception &ex) { + addAxisToCombo(orig->getX(), "", tr("Base X axis")); + addAxisToCombo(orig->getY(), "", tr("Base Y axis")); + addAxisToCombo(orig->getZ(), "", tr("Base Z axis")); + } + catch (const Base::Exception& ex) { ex.ReportException(); } } //add "Select reference" - addAxisToCombo(0,std::string(),tr("Select reference...")); + addAxisToCombo(0, std::string(), tr("Select reference...")); }//endif forceRefill //add current link, if not in list //first, figure out the item number for current axis int indexOfCurrent = -1; App::DocumentObject* ax = propReferenceAxis->getValue(); - const std::vector &subList = propReferenceAxis->getSubValues(); + const std::vector& subList = propReferenceAxis->getSubValues(); for (size_t i = 0; i < axesInList.size(); i++) { if (ax == axesInList[i]->getValue() && subList == axesInList[i]->getSubValues()) { indexOfCurrent = i; break; } } - if (indexOfCurrent == -1 && ax) { + if (indexOfCurrent == -1 && ax) { assert(subList.size() <= 1); std::string sub; if (!subList.empty()) sub = subList[0]; addAxisToCombo(ax, sub, getRefStr(ax, subList)); - indexOfCurrent = axesInList.size()-1; + indexOfCurrent = axesInList.size() - 1; } //highlight current. @@ -258,13 +260,13 @@ void TaskHelixParameters::fillAxisCombo(bool forceRefill) } void TaskHelixParameters::addAxisToCombo(App::DocumentObject* linkObj, - std::string linkSubname, - QString itemText) + std::string linkSubname, + QString itemText) { this->ui->axis->addItem(itemText); this->axesInList.emplace_back(new App::PropertyLinkSub); - App::PropertyLinkSub &lnk = *(axesInList.back()); - lnk.setValue(linkObj,std::vector(1,linkSubname)); + App::PropertyLinkSub& lnk = *(axesInList.back()); + lnk.setValue(linkObj, std::vector(1, linkSubname)); } void TaskHelixParameters::updateUI() @@ -273,7 +275,7 @@ void TaskHelixParameters::updateUI() auto pcHelix = static_cast(vp->getObject()); auto status = std::string(pcHelix->getStatusString()); - if (status.compare("Valid")==0 || status.compare("Touched")==0) { + if (status.compare("Valid") == 0 || status.compare("Touched") == 0) { if (pcHelix->safePitch() > propPitch->getValue()) status = "Warning: helix might be self intersecting"; else @@ -281,14 +283,14 @@ void TaskHelixParameters::updateUI() } ui->labelMessage->setText(QString::fromUtf8(status.c_str())); - bool isPitchVisible = false; + bool isPitchVisible = false; bool isHeightVisible = false; - bool isTurnsVisible = false; + bool isTurnsVisible = false; bool isOutsideVisible = false; bool isAngleVisible = false; bool isGrowthVisible = false; - if(pcHelix->getAddSubType() == PartDesign::FeatureAddSub::Subtractive) + if (pcHelix->getAddSubType() == PartDesign::FeatureAddSub::Subtractive) isOutsideVisible = true; HelixMode mode = static_cast(propMode->getValue()); @@ -296,19 +298,23 @@ void TaskHelixParameters::updateUI() isPitchVisible = true; isHeightVisible = true; isAngleVisible = true; - } else if (mode == HelixMode::pitch_turns_angle) { + } + else if (mode == HelixMode::pitch_turns_angle) { isPitchVisible = true; isTurnsVisible = true; isAngleVisible = true; - } else if (mode == HelixMode::height_turns_angle) { + } + else if (mode == HelixMode::height_turns_angle) { isHeightVisible = true; isTurnsVisible = true; isAngleVisible = true; - } else if (mode == HelixMode::height_turns_growth) { + } + else if (mode == HelixMode::height_turns_growth) { isHeightVisible = true; isTurnsVisible = true; isGrowthVisible = true; - } else { + } + else { status = "Error: unsupported mode"; ui->labelMessage->setText(QString::fromUtf8(status.c_str())); } @@ -389,19 +395,20 @@ void TaskHelixParameters::onAxisChanged(int num) if (axesInList.empty()) return; - App::DocumentObject *oldRefAxis = propReferenceAxis->getValue(); + App::DocumentObject* oldRefAxis = propReferenceAxis->getValue(); std::vector oldSubRefAxis = propReferenceAxis->getSubValues(); std::string oldRefName; if (!oldSubRefAxis.empty()) oldRefName = oldSubRefAxis.front(); - App::PropertyLinkSub &lnk = *(axesInList[num]); + App::PropertyLinkSub& lnk = *(axesInList[num]); if (lnk.getValue() == 0) { // enter reference selection mode TaskSketchBasedParameters::onSelectReference(true, true, false, true, true); return; - } else { - if (!pcHelix->getDocument()->isIn(lnk.getValue())){ + } + else { + if (!pcHelix->getDocument()->isIn(lnk.getValue())) { Base::Console().Error("Object was deleted\n"); return; } @@ -412,8 +419,8 @@ void TaskHelixParameters::onAxisChanged(int num) } try { - App::DocumentObject *newRefAxis = propReferenceAxis->getValue(); - const std::vector &newSubRefAxis = propReferenceAxis->getSubValues(); + App::DocumentObject* newRefAxis = propReferenceAxis->getValue(); + const std::vector& newSubRefAxis = propReferenceAxis->getSubValues(); std::string newRefName; if (!newSubRefAxis.empty()) newRefName = newSubRefAxis.front(); @@ -444,7 +451,7 @@ void TaskHelixParameters::onModeChanged(int index) ui->pitch->setValue(propPitch->getValue()); ui->height->setValue(propHeight->getValue()); - ui->turns->setValue((propHeight->getValue())/(propPitch->getValue())); + ui->turns->setValue((propHeight->getValue()) / (propPitch->getValue())); recomputeFeature(); updateUI(); @@ -475,20 +482,21 @@ TaskHelixParameters::~TaskHelixParameters() { try { //hide the parts coordinate system axis for selection - PartDesign::Body * body = vp ? PartDesign::Body::findBodyOf(vp->getObject()) : 0; + PartDesign::Body* body = vp ? PartDesign::Body::findBodyOf(vp->getObject()) : 0; if (body) { - App::Origin *origin = body->getOrigin(); + App::Origin* origin = body->getOrigin(); ViewProviderOrigin* vpOrigin; vpOrigin = static_cast(Gui::Application::Instance->getViewProvider(origin)); vpOrigin->resetTemporaryVisibility(); } - } catch (const Base::Exception &ex) { + } + catch (const Base::Exception& ex) { ex.ReportException(); } } -void TaskHelixParameters::changeEvent(QEvent *e) +void TaskHelixParameters::changeEvent(QEvent* e) { TaskBox::changeEvent(e); if (e->type() == QEvent::LanguageChange) { @@ -502,12 +510,13 @@ void TaskHelixParameters::getReferenceAxis(App::DocumentObject*& obj, std::vecto throw Base::RuntimeError("Not initialized!"); int num = ui->axis->currentIndex(); - const App::PropertyLinkSub &lnk = *(axesInList[num]); + const App::PropertyLinkSub& lnk = *(axesInList[num]); if (lnk.getValue() == 0) { throw Base::RuntimeError("Still in reference selection mode; reference wasn't selected yet"); - } else { + } + else { PartDesign::ProfileBased* pcRevolution = static_cast(vp->getObject()); - if (!pcRevolution->getDocument()->isIn(lnk.getValue())){ + if (!pcRevolution->getDocument()->isIn(lnk.getValue())) { throw Base::RuntimeError("Object was deleted"); } @@ -563,15 +572,15 @@ void TaskHelixParameters::apply() getReferenceAxis(obj, sub); std::string axis = buildLinkSingleSubPythonStr(obj, sub); auto tobj = vp->getObject(); - FCMD_OBJ_CMD(tobj,"ReferenceAxis = " << axis); - FCMD_OBJ_CMD(tobj,"Mode = " << propMode->getValue()); - FCMD_OBJ_CMD(tobj,"Pitch = " << propPitch->getValue()); - FCMD_OBJ_CMD(tobj,"Height = " << propHeight->getValue()); - FCMD_OBJ_CMD(tobj,"Turns = " << propTurns->getValue()); - FCMD_OBJ_CMD(tobj,"Angle = " << propAngle->getValue()); - FCMD_OBJ_CMD(tobj,"Growth = " << propGrowth->getValue()); - FCMD_OBJ_CMD(tobj,"LeftHanded = " << (propLeftHanded->getValue() ? 1 : 0)); - FCMD_OBJ_CMD(tobj,"Reversed = " << (propReversed->getValue() ? 1 : 0)); + FCMD_OBJ_CMD(tobj, "ReferenceAxis = " << axis); + FCMD_OBJ_CMD(tobj, "Mode = " << propMode->getValue()); + FCMD_OBJ_CMD(tobj, "Pitch = " << propPitch->getValue()); + FCMD_OBJ_CMD(tobj, "Height = " << propHeight->getValue()); + FCMD_OBJ_CMD(tobj, "Turns = " << propTurns->getValue()); + FCMD_OBJ_CMD(tobj, "Angle = " << propAngle->getValue()); + FCMD_OBJ_CMD(tobj, "Growth = " << propGrowth->getValue()); + FCMD_OBJ_CMD(tobj, "LeftHanded = " << (propLeftHanded->getValue() ? 1 : 0)); + FCMD_OBJ_CMD(tobj, "Reversed = " << (propReversed->getValue() ? 1 : 0)); } @@ -579,7 +588,7 @@ void TaskHelixParameters::apply() //************************************************************************** // TaskDialog //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -TaskDlgHelixParameters::TaskDlgHelixParameters(ViewProviderHelix *HelixView) +TaskDlgHelixParameters::TaskDlgHelixParameters(ViewProviderHelix* HelixView) : TaskDlgSketchBasedParameters(HelixView) { assert(HelixView); diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.h b/src/Mod/PartDesign/Gui/TaskHelixParameters.h index 110cad5444..e45847afb9 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.h +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.h @@ -49,7 +49,7 @@ class TaskHelixParameters : public TaskSketchBasedParameters Q_OBJECT public: - TaskHelixParameters(ViewProviderHelix *HelixView,QWidget *parent = 0); + TaskHelixParameters(ViewProviderHelix* HelixView, QWidget* parent = 0); ~TaskHelixParameters(); virtual void apply() override; @@ -64,7 +64,7 @@ public: * list (if necessary), and selected. If the list is empty, it will be refilled anyway. */ void fillAxisCombo(bool forceRefill = false); - void addAxisToCombo(App::DocumentObject *linkObj, std::string linkSubname, QString itemText); + void addAxisToCombo(App::DocumentObject* linkObj, std::string linkSubname, QString itemText); private Q_SLOTS: void onPitchChanged(double); @@ -81,9 +81,9 @@ private Q_SLOTS: protected: void onSelectionChanged(const Gui::SelectionChanges& msg) override; - void changeEvent(QEvent *e) override; + void changeEvent(QEvent* e) override; bool updateView() const; - void getReferenceAxis(App::DocumentObject *&obj, std::vector &sub) const; + void getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const; void startReferenceSelection(App::DocumentObject* profile, App::DocumentObject* base) override; void finishReferenceSelection(App::DocumentObject* profile, App::DocumentObject* base) override; @@ -124,7 +124,7 @@ class TaskDlgHelixParameters : public TaskDlgSketchBasedParameters Q_OBJECT public: - TaskDlgHelixParameters(ViewProviderHelix *HelixView); + TaskDlgHelixParameters(ViewProviderHelix* HelixView); ViewProviderHelix* getHelixView() const { return static_cast(vp); } From 9d70589d6c2f08f3339c40e9b990fde5863b45b7 Mon Sep 17 00:00:00 2001 From: Uwe Date: Mon, 29 Nov 2021 12:54:21 +0100 Subject: [PATCH 091/133] [GUI] set dialog width to the one of the other preferences ones --- src/Gui/DlgSettingsCacheDirectory.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gui/DlgSettingsCacheDirectory.ui b/src/Gui/DlgSettingsCacheDirectory.ui index 8cd6560015..34052b94a3 100644 --- a/src/Gui/DlgSettingsCacheDirectory.ui +++ b/src/Gui/DlgSettingsCacheDirectory.ui @@ -6,7 +6,7 @@ 0 0 - 488 + 425 360 From 7c0c6bf67182455262bee1a3b75a85d7c933ef7e Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Thu, 25 Nov 2021 11:04:19 +0100 Subject: [PATCH 092/133] [Sketcher] Ability to snap slot horizontal/vertical Triggered by pressing Ctrl key when creating the slot Extra constraint is added in case snapping is enabled --- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 39 +++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index ba1496e225..c064f96b42 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -6997,6 +6997,8 @@ class DrawSketchHandlerSlot : public DrawSketchHandler public: DrawSketchHandlerSlot() : Mode(STATUS_SEEK_First) + , SnapMode(SNAP_MODE_Free) + , SnapDir(SNAP_DIR_Horz) , dx(0), dy(0), r(0) , EditCurve(35) { @@ -7009,6 +7011,18 @@ public: STATUS_End }; + enum SNAP_MODE + { + SNAP_MODE_Free, + SNAP_MODE_Straight + }; + + enum SNAP_DIR + { + SNAP_DIR_Horz, + SNAP_DIR_Vert + }; + virtual void activated(ViewProviderSketch*) { setCrosshairCursor("Sketcher_Pointer_Slot"); @@ -7028,16 +7042,25 @@ public: dx = onSketchPos.x - StartPos.x; dy = onSketchPos.y - StartPos.y; + if(QApplication::keyboardModifiers() == Qt::ControlModifier) + SnapMode = SNAP_MODE_Straight; + else + SnapMode = SNAP_MODE_Free; + double a = 0; double rev = 0; if (fabs(dx) > fabs(dy)) { r = fabs(dx) / 4; rev = Base::sgn(dx); + SnapDir = SNAP_DIR_Horz; + if (SnapMode == SNAP_MODE_Straight) dy = 0; } else { r = fabs(dy) / 4; a = 8; rev = Base::sgn(dy); + SnapDir = SNAP_DIR_Vert; + if (SnapMode == SNAP_MODE_Straight) dx = 0; } // draw the arcs with each 16 segments @@ -7121,6 +7144,17 @@ public: try { Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add slot")); + ostringstream snapCon = ostringstream(""); + if (SnapMode == SNAP_MODE_Straight) { + snapCon << "conList.append(Sketcher.Constraint('"; + if (SnapDir == SNAP_DIR_Horz) { + snapCon << "Horizontal"; + } + else { + snapCon << "Vertical"; + } + snapCon << "'," << firstCurve + 2 << "))\n"; + } Gui::Command::doCommand(Gui::Command::Doc, "geoList = []\n" "geoList.append(Part.ArcOfCircle(Part.Circle(App.Vector(%f, %f, 0), App.Vector(0, 0, 1), %f), %f, %f))\n" @@ -7134,6 +7168,7 @@ public: "conList.append(Sketcher.Constraint('Tangent', %i, 2, %i, 1))\n" "conList.append(Sketcher.Constraint('Tangent', %i, 2, %i, 1))\n" "conList.append(Sketcher.Constraint('Equal', %i, %i))\n" + "%s" "%s.addConstraint(conList)\n" "del geoList, conList\n", StartPos.x, StartPos.y, // center of the arc1 @@ -7151,6 +7186,7 @@ public: firstCurve + 1, firstCurve + 3, // tangent3 firstCurve + 3, firstCurve, // tangent4 firstCurve, firstCurve + 1, // equal constraint + snapCon.str().c_str(), // horizontal/vertical constraint if snapping Gui::Command::getObjectCmd(sketchgui->getObject()).c_str()); // the sketch Gui::Command::commitCommand(); @@ -7193,11 +7229,14 @@ public: else { sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider } + SnapMode = SNAP_MODE_Straight; } return true; } protected: BoxMode Mode; + SNAP_MODE SnapMode; + SNAP_DIR SnapDir; Base::Vector2d StartPos; double dx, dy, r; std::vector EditCurve; From abe4babd135ffb1f468505326cf64333180b34a2 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Fri, 26 Nov 2021 15:19:35 +0100 Subject: [PATCH 093/133] [Sketcher] Introduce hack to be able to vertically/horizontally auto-constrain primitives Adds a new type "VERTEX_FOR_PRIMITIVE" that will analyze the direction for vertical/horizontal but not for tangent If defined, makes use of GeoId item of AutoConstraint struct (instead of last geometry) to apply the horizontal/vertical constraint. This allow this constraint to be applied on an arbitrary geometry. --- src/Mod/Sketcher/Gui/DrawSketchHandler.cpp | 21 ++++++++++++++------- src/Mod/Sketcher/Gui/DrawSketchHandler.h | 3 ++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp index dc571a673d..2f4ea5e379 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp @@ -354,11 +354,11 @@ int DrawSketchHandler::seekAutoConstraint(std::vector &suggested constr.Type = Sketcher::None; constr.GeoId = GeoId; constr.PosId = PosId; - if (type == AutoConstraint::VERTEX && PosId != Sketcher::none) + if ((type == AutoConstraint::VERTEX || type == AutoConstraint::VERTEX_NO_TANGENCY) && PosId != Sketcher::none) constr.Type = Sketcher::Coincident; else if (type == AutoConstraint::CURVE && PosId != Sketcher::none) constr.Type = Sketcher::PointOnObject; - else if (type == AutoConstraint::VERTEX && PosId == Sketcher::none && hitobject->getTypeId() != Part::GeomBSplineCurve::getClassTypeId()) + else if ((type == AutoConstraint::VERTEX || type == AutoConstraint::VERTEX_NO_TANGENCY) && PosId == Sketcher::none && hitobject->getTypeId() != Part::GeomBSplineCurve::getClassTypeId()) constr.Type = Sketcher::PointOnObject; else if (type == AutoConstraint::CURVE && PosId == Sketcher::none) constr.Type = Sketcher::Tangent; @@ -405,6 +405,9 @@ int DrawSketchHandler::seekAutoConstraint(std::vector &suggested if (constr.Type != Sketcher::None) suggestedConstraints.push_back(constr); + // Do not seek for tangent if we are actually building a primitive + if (type == AutoConstraint::VERTEX_NO_TANGENCY) return suggestedConstraints.size(); + // Find if there are tangent constraints (currently arcs and circles) int tangId = Constraint::GeoUndef; @@ -578,6 +581,8 @@ void DrawSketchHandler::createAutoConstraints(const std::vector // Iterate through constraints std::vector::const_iterator it = autoConstrs.begin(); for (; it != autoConstrs.end(); ++it) { + int geoId2 = it->GeoId; + switch (it->Type) { case Sketcher::Coincident: { @@ -588,7 +593,6 @@ void DrawSketchHandler::createAutoConstraints(const std::vector , geoId1, posId1, it->GeoId, it->PosId); } break; case Sketcher::PointOnObject: { - int geoId2 = it->GeoId; Sketcher::PointPos posId2 = it->PosId; if (posId1 == Sketcher::none) { // Auto constraining an edge so swap parameters @@ -599,11 +603,16 @@ void DrawSketchHandler::createAutoConstraints(const std::vector Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('PointOnObject',%i,%i,%i)) " , geoId1, posId1, geoId2); } break; + // In special case of Horizontal/Vertical constraint, geoId2 is normally unused and should be 'Constraint::GeoUndef' + // However it can be used as a way to require the function to apply these constraints on another geometry + // In this case the caller as to set geoId2, then it will be used as target instead of geoId2 case Sketcher::Horizontal: { - Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Horizontal',%i)) ", geoId1); + Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Horizontal',%i)) ", + geoId2 != Constraint::GeoUndef ? geoId2 : geoId1); } break; case Sketcher::Vertical: { - Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Vertical',%i)) ", geoId1); + Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Vertical',%i)) ", + geoId2 != Constraint::GeoUndef ? geoId2 : geoId1); } break; case Sketcher::Tangent: { Sketcher::SketchObject* Obj = static_cast(sketchgui->getObject()); @@ -611,8 +620,6 @@ void DrawSketchHandler::createAutoConstraints(const std::vector const Part::Geometry *geom1 = Obj->getGeometry(geoId1); const Part::Geometry *geom2 = Obj->getGeometry(it->GeoId); - int geoId2 = it->GeoId; - // ellipse tangency support using construction elements (lines) if( geom1 && geom2 && ( geom1->getTypeId() == Part::GeomEllipse::getClassTypeId() || diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.h b/src/Mod/Sketcher/Gui/DrawSketchHandler.h index b7cc951ccc..572a1cbe4c 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.h @@ -45,7 +45,8 @@ struct AutoConstraint enum TargetType { VERTEX, - CURVE + CURVE, + VERTEX_NO_TANGENCY }; Sketcher::ConstraintType Type; int GeoId; From 834ae29ad00b25f14996c62757afacf3267a9b13 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Fri, 26 Nov 2021 15:26:02 +0100 Subject: [PATCH 094/133] [Sketcher] Allow to autoconstraint slot horizontal/vertical --- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index c064f96b42..26bb0f6ebe 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -7090,7 +7090,7 @@ public: setPositionText(onSketchPos, text); sketchgui->drawEdit(EditCurve); - if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2d(0.f, 0.f))) { + if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2d(dx, dy), AutoConstraint::VERTEX_NO_TANGENCY)) { renderSuggestConstraintsCursor(sugConstr2); return; } @@ -7144,6 +7144,9 @@ public: try { Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add slot")); + + AutoConstraint lastCons = sugConstr2.back(); + ostringstream snapCon = ostringstream(""); if (SnapMode == SNAP_MODE_Straight) { snapCon << "conList.append(Sketcher.Constraint('"; @@ -7154,7 +7157,17 @@ public: snapCon << "Vertical"; } snapCon << "'," << firstCurve + 2 << "))\n"; + + // If horizontal/vertical already applied because of snap, do not duplicate with Autocontraint + if (lastCons.Type == Sketcher::Horizontal || lastCons.Type == Sketcher::Vertical) + sugConstr2.pop_back(); } + else { + // If horizontal/vertical Autoconstraint suggested, applied it on first line (rather than last arc) + if (lastCons.Type == Sketcher::Horizontal || lastCons.Type == Sketcher::Vertical) + sugConstr2.back().GeoId = firstCurve + 2; + } + Gui::Command::doCommand(Gui::Command::Doc, "geoList = []\n" "geoList.append(Part.ArcOfCircle(Part.Circle(App.Vector(%f, %f, 0), App.Vector(0, 0, 1), %f), %f, %f))\n" From 41efee1b4c5fb449790c1c6a78a5310794c6fc57 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 29 Nov 2021 20:14:29 +0100 Subject: [PATCH 095/133] PD: handle language change in TaskHelixParameters --- .../PartDesign/Gui/TaskHelixParameters.cpp | 100 +++++++++++------- src/Mod/PartDesign/Gui/TaskHelixParameters.h | 4 + 2 files changed, 67 insertions(+), 37 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp index bc9e878ce6..4cc7f3e1c8 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp @@ -196,44 +196,62 @@ void TaskHelixParameters::fillAxisCombo(bool forceRefill) if (forceRefill) { ui->axis->clear(); - this->axesInList.clear(); //add sketch axes - PartDesign::ProfileBased* pcFeat = static_cast(vp->getObject()); - Part::Part2DObject* pcSketch = dynamic_cast(pcFeat->Profile.getValue()); - if (pcSketch) { - addAxisToCombo(pcSketch, "N_Axis", QObject::tr("Normal sketch axis")); - addAxisToCombo(pcSketch, "V_Axis", QObject::tr("Vertical sketch axis")); - addAxisToCombo(pcSketch, "H_Axis", QObject::tr("Horizontal sketch axis")); - for (int i = 0; i < pcSketch->getAxisCount(); i++) { - QString itemText = QObject::tr("Construction line %1").arg(i + 1); - std::stringstream sub; - sub << "Axis" << i; - addAxisToCombo(pcSketch, sub.str(), itemText); - } - } + addSketchAxes(); //add part axes - PartDesign::Body* body = PartDesign::Body::findBodyOf(pcFeat); - if (body) { - try { - App::Origin* orig = body->getOrigin(); - addAxisToCombo(orig->getX(), "", tr("Base X axis")); - addAxisToCombo(orig->getY(), "", tr("Base Y axis")); - addAxisToCombo(orig->getZ(), "", tr("Base Z axis")); - } - catch (const Base::Exception& ex) { - ex.ReportException(); - } - } + addPartAxes(); //add "Select reference" addAxisToCombo(0, std::string(), tr("Select reference...")); - }//endif forceRefill + } - //add current link, if not in list - //first, figure out the item number for current axis + //add current link, if not in list and highlight it + int indexOfCurrent = addCurrentLink(); + if (indexOfCurrent != -1) + ui->axis->setCurrentIndex(indexOfCurrent); + + blockUpdate = oldVal_blockUpdate; +} + +void TaskHelixParameters::addSketchAxes() +{ + PartDesign::ProfileBased* pcFeat = static_cast(vp->getObject()); + Part::Part2DObject* pcSketch = dynamic_cast(pcFeat->Profile.getValue()); + if (pcSketch) { + addAxisToCombo(pcSketch, "N_Axis", tr("Normal sketch axis")); + addAxisToCombo(pcSketch, "V_Axis", tr("Vertical sketch axis")); + addAxisToCombo(pcSketch, "H_Axis", tr("Horizontal sketch axis")); + for (int i = 0; i < pcSketch->getAxisCount(); i++) { + QString itemText = tr("Construction line %1").arg(i + 1); + std::stringstream sub; + sub << "Axis" << i; + addAxisToCombo(pcSketch, sub.str(), itemText); + } + } +} + +void TaskHelixParameters::addPartAxes() +{ + PartDesign::ProfileBased* pcFeat = static_cast(vp->getObject()); + PartDesign::Body* body = PartDesign::Body::findBodyOf(pcFeat); + if (body) { + try { + App::Origin* orig = body->getOrigin(); + addAxisToCombo(orig->getX(), "", tr("Base X axis")); + addAxisToCombo(orig->getY(), "", tr("Base Y axis")); + addAxisToCombo(orig->getZ(), "", tr("Base Z axis")); + } + catch (const Base::Exception& ex) { + ex.ReportException(); + } + } +} + +int TaskHelixParameters::addCurrentLink() +{ int indexOfCurrent = -1; App::DocumentObject* ax = propReferenceAxis->getValue(); const std::vector& subList = propReferenceAxis->getSubValues(); @@ -243,6 +261,7 @@ void TaskHelixParameters::fillAxisCombo(bool forceRefill) break; } } + if (indexOfCurrent == -1 && ax) { assert(subList.size() <= 1); std::string sub; @@ -252,16 +271,12 @@ void TaskHelixParameters::fillAxisCombo(bool forceRefill) indexOfCurrent = axesInList.size() - 1; } - //highlight current. - if (indexOfCurrent != -1) - ui->axis->setCurrentIndex(indexOfCurrent); - - blockUpdate = oldVal_blockUpdate; + return indexOfCurrent; } void TaskHelixParameters::addAxisToCombo(App::DocumentObject* linkObj, - std::string linkSubname, - QString itemText) + std::string linkSubname, + QString itemText) { this->ui->axis->addItem(itemText); this->axesInList.emplace_back(new App::PropertyLinkSub); @@ -500,7 +515,18 @@ void TaskHelixParameters::changeEvent(QEvent* e) { TaskBox::changeEvent(e); if (e->type() == QEvent::LanguageChange) { + // save current indexes + int axis = ui->axis->currentIndex(); + int mode = ui->inputMode->currentIndex(); ui->retranslateUi(proxy); + + // Axes added by the user cannot be restored + fillAxisCombo(true); + + // restore the indexes + if (axis < ui->axis->count()) + ui->axis->setCurrentIndex(axis); + ui->inputMode->setCurrentIndex(mode); } } @@ -510,7 +536,7 @@ void TaskHelixParameters::getReferenceAxis(App::DocumentObject*& obj, std::vecto throw Base::RuntimeError("Not initialized!"); int num = ui->axis->currentIndex(); - const App::PropertyLinkSub& lnk = *(axesInList[num]); + const App::PropertyLinkSub& lnk = *(axesInList.at(num)); if (lnk.getValue() == 0) { throw Base::RuntimeError("Still in reference selection mode; reference wasn't selected yet"); } diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.h b/src/Mod/PartDesign/Gui/TaskHelixParameters.h index e45847afb9..135b9000ed 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.h +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.h @@ -56,6 +56,7 @@ public: static bool showPreview(PartDesign::Helix*); +private: /** * @brief fillAxisCombo fills the combo and selects the item according to * current value of revolution object's axis reference. @@ -65,6 +66,9 @@ public: */ void fillAxisCombo(bool forceRefill = false); void addAxisToCombo(App::DocumentObject* linkObj, std::string linkSubname, QString itemText); + void addSketchAxes(); + void addPartAxes(); + int addCurrentLink(); private Q_SLOTS: void onPitchChanged(double); From ffe240a539a5780ccb48130b9c504ee7f8298223 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 29 Nov 2021 22:14:14 +0100 Subject: [PATCH 096/133] PD: refactoring of TaskHelixParameters, update status after each recompute --- .../PartDesign/Gui/TaskHelixParameters.cpp | 73 +++++++++++-------- src/Mod/PartDesign/Gui/TaskHelixParameters.h | 2 + 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp index 4cc7f3e1c8..c59b928fdb 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp @@ -68,30 +68,7 @@ TaskHelixParameters::TaskHelixParameters(PartDesignGui::ViewProviderHelix* Helix // we need a separate container widget to add all controls to proxy = new QWidget(this); ui->setupUi(proxy); - QMetaObject::connectSlotsByName(this); - - connect(ui->pitch, SIGNAL(valueChanged(double)), - this, SLOT(onPitchChanged(double))); - connect(ui->height, SIGNAL(valueChanged(double)), - this, SLOT(onHeightChanged(double))); - connect(ui->turns, SIGNAL(valueChanged(double)), - this, SLOT(onTurnsChanged(double))); - connect(ui->coneAngle, SIGNAL(valueChanged(double)), - this, SLOT(onAngleChanged(double))); - connect(ui->growth, SIGNAL(valueChanged(double)), - this, SLOT(onGrowthChanged(double))); - connect(ui->axis, SIGNAL(activated(int)), - this, SLOT(onAxisChanged(int))); - connect(ui->checkBoxLeftHanded, SIGNAL(toggled(bool)), - this, SLOT(onLeftHandedChanged(bool))); - connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), - this, SLOT(onReversedChanged(bool))); - connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), - this, SLOT(onUpdateView(bool))); - connect(ui->inputMode, SIGNAL(activated(int)), - this, SLOT(onModeChanged(int))); - connect(ui->checkBoxOutside, SIGNAL(toggled(bool)), - this, SLOT(onOutsideChanged(bool))); + connectSlots(); this->groupLayout()->addWidget(proxy); @@ -114,6 +91,7 @@ TaskHelixParameters::TaskHelixParameters(PartDesignGui::ViewProviderHelix* Helix if (!(rev->HasBeenEdited).getValue()) { rev->proposeParameters(); recomputeFeature(); + updateStatus(); } this->propAngle = &(rev->Angle); @@ -186,6 +164,34 @@ TaskHelixParameters::TaskHelixParameters(PartDesignGui::ViewProviderHelix* Helix } } +void TaskHelixParameters::connectSlots() +{ + QMetaObject::connectSlotsByName(this); + + connect(ui->pitch, SIGNAL(valueChanged(double)), + this, SLOT(onPitchChanged(double))); + connect(ui->height, SIGNAL(valueChanged(double)), + this, SLOT(onHeightChanged(double))); + connect(ui->turns, SIGNAL(valueChanged(double)), + this, SLOT(onTurnsChanged(double))); + connect(ui->coneAngle, SIGNAL(valueChanged(double)), + this, SLOT(onAngleChanged(double))); + connect(ui->growth, SIGNAL(valueChanged(double)), + this, SLOT(onGrowthChanged(double))); + connect(ui->axis, SIGNAL(activated(int)), + this, SLOT(onAxisChanged(int))); + connect(ui->checkBoxLeftHanded, SIGNAL(toggled(bool)), + this, SLOT(onLeftHandedChanged(bool))); + connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), + this, SLOT(onReversedChanged(bool))); + connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), + this, SLOT(onUpdateView(bool))); + connect(ui->inputMode, SIGNAL(activated(int)), + this, SLOT(onModeChanged(int))); + connect(ui->checkBoxOutside, SIGNAL(toggled(bool)), + this, SLOT(onOutsideChanged(bool))); +} + void TaskHelixParameters::fillAxisCombo(bool forceRefill) { bool oldVal_blockUpdate = blockUpdate; @@ -284,10 +290,8 @@ void TaskHelixParameters::addAxisToCombo(App::DocumentObject* linkObj, lnk.setValue(linkObj, std::vector(1, linkSubname)); } -void TaskHelixParameters::updateUI() +void TaskHelixParameters::updateStatus() { - fillAxisCombo(); - auto pcHelix = static_cast(vp->getObject()); auto status = std::string(pcHelix->getStatusString()); if (status.compare("Valid") == 0 || status.compare("Touched") == 0) { @@ -297,6 +301,13 @@ void TaskHelixParameters::updateUI() status = ""; } ui->labelMessage->setText(QString::fromUtf8(status.c_str())); +} + +void TaskHelixParameters::updateUI() +{ + fillAxisCombo(); + + updateStatus(); bool isPitchVisible = false; bool isHeightVisible = false; @@ -305,6 +316,7 @@ void TaskHelixParameters::updateUI() bool isAngleVisible = false; bool isGrowthVisible = false; + auto pcHelix = static_cast(vp->getObject()); if (pcHelix->getAddSubType() == PartDesign::FeatureAddSub::Subtractive) isOutsideVisible = true; @@ -330,8 +342,7 @@ void TaskHelixParameters::updateUI() isGrowthVisible = true; } else { - status = "Error: unsupported mode"; - ui->labelMessage->setText(QString::fromUtf8(status.c_str())); + ui->labelMessage->setText(tr("Error: unsupported mode")); } ui->pitch->setVisible(isPitchVisible); @@ -350,7 +361,6 @@ void TaskHelixParameters::updateUI() ui->labelGrowth->setVisible(isGrowthVisible); ui->checkBoxOutside->setVisible(isOutsideVisible); - } void TaskHelixParameters::onSelectionChanged(const Gui::SelectionChanges& msg) @@ -453,6 +463,7 @@ void TaskHelixParameters::onAxisChanged(int num) } recomputeFeature(); + updateStatus(); } catch (const Base::Exception& e) { e.ReportException(); @@ -461,7 +472,6 @@ void TaskHelixParameters::onAxisChanged(int num) void TaskHelixParameters::onModeChanged(int index) { - propMode->setValue(index); ui->pitch->setValue(propPitch->getValue()); @@ -476,6 +486,7 @@ void TaskHelixParameters::onLeftHandedChanged(bool on) { propLeftHanded->setValue(on); recomputeFeature(); + updateUI(); } void TaskHelixParameters::onReversedChanged(bool on) diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.h b/src/Mod/PartDesign/Gui/TaskHelixParameters.h index 135b9000ed..8caf74c37b 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.h +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.h @@ -105,7 +105,9 @@ protected: private: + void connectSlots(); void updateUI(); + void updateStatus(); private: QWidget* proxy; From 46e516f5d3d4e4f5b1d0756764d468f4fd72a2d3 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 30 Nov 2021 10:36:36 +0100 Subject: [PATCH 097/133] PD: fix crash in TaskHelixParameters::updateStatus() --- src/Mod/PartDesign/Gui/TaskHelixParameters.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp index c59b928fdb..092022105a 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp @@ -91,7 +91,6 @@ TaskHelixParameters::TaskHelixParameters(PartDesignGui::ViewProviderHelix* Helix if (!(rev->HasBeenEdited).getValue()) { rev->proposeParameters(); recomputeFeature(); - updateStatus(); } this->propAngle = &(rev->Angle); From 3cddf78b5ec958018e67da931d0c6dcc33d2a563 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 30 Nov 2021 11:47:06 +0100 Subject: [PATCH 098/133] PD: refactoring of TaskHelixParameters --- .../PartDesign/Gui/TaskHelixParameters.cpp | 128 +++++++++--------- src/Mod/PartDesign/Gui/TaskHelixParameters.h | 5 + 2 files changed, 68 insertions(+), 65 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp index 092022105a..9452720094 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp @@ -62,48 +62,55 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskHelixParameters */ TaskHelixParameters::TaskHelixParameters(PartDesignGui::ViewProviderHelix* HelixView, QWidget* parent) - : TaskSketchBasedParameters(HelixView, parent, "PartDesign_AdditiveHelix", tr("Helix parameters")), - ui(new Ui_TaskHelixParameters) + : TaskSketchBasedParameters(HelixView, parent, "PartDesign_AdditiveHelix", tr("Helix parameters")) + , ui(new Ui_TaskHelixParameters) { // we need a separate container widget to add all controls to proxy = new QWidget(this); ui->setupUi(proxy); - connectSlots(); - this->groupLayout()->addWidget(proxy); - // Temporarily prevent unnecessary feature recomputes - ui->axis->blockSignals(true); - ui->pitch->blockSignals(true); - ui->height->blockSignals(true); - ui->turns->blockSignals(true); - ui->coneAngle->blockSignals(true); - ui->growth->blockSignals(true); - ui->checkBoxLeftHanded->blockSignals(true); - ui->checkBoxReversed->blockSignals(true); - ui->checkBoxOutside->blockSignals(true); + initializeHelix(); - //bind property mirrors - PartDesign::ProfileBased* pcFeat = static_cast(vp->getObject()); + assignProperties(); + setValuesFromProperties(); - PartDesign::Helix* rev = static_cast(vp->getObject()); + updateUI(); - if (!(rev->HasBeenEdited).getValue()) { - rev->proposeParameters(); + // enable use of parametric expressions for the numerical fields + bindProperties(); + + connectSlots(); + setFocus(); + showCoordinateAxes(); +} + +void TaskHelixParameters::initializeHelix() +{ + PartDesign::Helix* helix = static_cast(vp->getObject()); + if (!(helix->HasBeenEdited).getValue()) { + helix->proposeParameters(); recomputeFeature(); } +} - this->propAngle = &(rev->Angle); - this->propGrowth = &(rev->Growth); - this->propPitch = &(rev->Pitch); - this->propHeight = &(rev->Height); - this->propTurns = &(rev->Turns); - this->propReferenceAxis = &(rev->ReferenceAxis); - this->propLeftHanded = &(rev->LeftHanded); - this->propReversed = &(rev->Reversed); - this->propMode = &(rev->Mode); - this->propOutside = &(rev->Outside); +void TaskHelixParameters::assignProperties() +{ + PartDesign::Helix* helix = static_cast(vp->getObject()); + propAngle = &(helix->Angle); + propGrowth = &(helix->Growth); + propPitch = &(helix->Pitch); + propHeight = &(helix->Height); + propTurns = &(helix->Turns); + propReferenceAxis = &(helix->ReferenceAxis); + propLeftHanded = &(helix->LeftHanded); + propReversed = &(helix->Reversed); + propMode = &(helix->Mode); + propOutside = &(helix->Outside); +} +void TaskHelixParameters::setValuesFromProperties() +{ double pitch = propPitch->getValue(); double height = propHeight->getValue(); double turns = propTurns->getValue(); @@ -125,42 +132,16 @@ TaskHelixParameters::TaskHelixParameters(PartDesignGui::ViewProviderHelix* Helix ui->checkBoxReversed->setChecked(reversed); ui->inputMode->setCurrentIndex(index); ui->checkBoxOutside->setChecked(outside); +} - blockUpdate = false; - updateUI(); - - // enable use of parametric expressions for the numerical fields - ui->pitch->bind(static_cast(pcFeat)->Pitch); - ui->height->bind(static_cast(pcFeat)->Height); - ui->turns->bind(static_cast(pcFeat)->Turns); - ui->coneAngle->bind(static_cast(pcFeat)->Angle); - ui->growth->bind(static_cast(pcFeat)->Growth); - - ui->axis->blockSignals(false); - ui->pitch->blockSignals(false); - ui->height->blockSignals(false); - ui->turns->blockSignals(false); - ui->coneAngle->blockSignals(false); - ui->growth->blockSignals(false); - ui->checkBoxLeftHanded->blockSignals(false); - ui->checkBoxReversed->blockSignals(false); - ui->checkBoxOutside->blockSignals(false); - - setFocus(); - - //show the parts coordinate system axis for selection - PartDesign::Body* body = PartDesign::Body::findBodyOf(vp->getObject()); - if (body) { - try { - App::Origin* origin = body->getOrigin(); - ViewProviderOrigin* vpOrigin; - vpOrigin = static_cast(Gui::Application::Instance->getViewProvider(origin)); - vpOrigin->setTemporaryVisibility(true, false); - } - catch (const Base::Exception& ex) { - ex.ReportException(); - } - } +void TaskHelixParameters::bindProperties() +{ + PartDesign::Helix* helix = static_cast(vp->getObject()); + ui->pitch->bind(helix->Pitch); + ui->height->bind(helix->Height); + ui->turns->bind(helix->Turns); + ui->coneAngle->bind(helix->Angle); + ui->growth->bind(helix->Growth); } void TaskHelixParameters::connectSlots() @@ -191,6 +172,23 @@ void TaskHelixParameters::connectSlots() this, SLOT(onOutsideChanged(bool))); } +void TaskHelixParameters::showCoordinateAxes() +{ + //show the parts coordinate system axis for selection + PartDesign::Body* body = PartDesign::Body::findBodyOf(vp->getObject()); + if (body) { + try { + App::Origin* origin = body->getOrigin(); + ViewProviderOrigin* vpOrigin; + vpOrigin = static_cast(Gui::Application::Instance->getViewProvider(origin)); + vpOrigin->setTemporaryVisibility(true, false); + } + catch (const Base::Exception& ex) { + ex.ReportException(); + } + } +} + void TaskHelixParameters::fillAxisCombo(bool forceRefill) { bool oldVal_blockUpdate = blockUpdate; @@ -294,7 +292,7 @@ void TaskHelixParameters::updateStatus() auto pcHelix = static_cast(vp->getObject()); auto status = std::string(pcHelix->getStatusString()); if (status.compare("Valid") == 0 || status.compare("Touched") == 0) { - if (pcHelix->safePitch() > propPitch->getValue()) + if (pcHelix->safePitch() > pcHelix->Pitch.getValue()) status = "Warning: helix might be self intersecting"; else status = ""; diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.h b/src/Mod/PartDesign/Gui/TaskHelixParameters.h index 8caf74c37b..02b9cdddd0 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.h +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.h @@ -105,9 +105,14 @@ protected: private: + void initializeHelix(); void connectSlots(); void updateUI(); void updateStatus(); + void assignProperties(); + void setValuesFromProperties(); + void bindProperties(); + void showCoordinateAxes(); private: QWidget* proxy; From 5018af974cb92f7e683c98de09429e90b29b19ce Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 30 Nov 2021 18:17:29 +0100 Subject: [PATCH 099/133] Part: implement Part.Wire.makeEvolved and Part.Face.makeEvolved --- src/Mod/Part/App/TopoShapeFacePy.xml | 5 +++ src/Mod/Part/App/TopoShapeFacePyImp.cpp | 58 +++++++++++++++++++++++++ src/Mod/Part/App/TopoShapeWirePy.xml | 5 +++ src/Mod/Part/App/TopoShapeWirePyImp.cpp | 54 +++++++++++++++++++++++ 4 files changed, 122 insertions(+) diff --git a/src/Mod/Part/App/TopoShapeFacePy.xml b/src/Mod/Part/App/TopoShapeFacePy.xml index c3809f047f..cc6c1655f6 100644 --- a/src/Mod/Part/App/TopoShapeFacePy.xml +++ b/src/Mod/Part/App/TopoShapeFacePy.xml @@ -30,6 +30,11 @@ Returns Compound of Wires. Deprecated - use makeOffset2D instead. + + + Profile along the spine + + Get the list of (u,v) nodes of the tessellation diff --git a/src/Mod/Part/App/TopoShapeFacePyImp.cpp b/src/Mod/Part/App/TopoShapeFacePyImp.cpp index 63e8bead74..fba5f73879 100644 --- a/src/Mod/Part/App/TopoShapeFacePyImp.cpp +++ b/src/Mod/Part/App/TopoShapeFacePyImp.cpp @@ -70,6 +70,7 @@ # include # include #endif // _PreComp +#include #include #include @@ -99,6 +100,10 @@ using namespace Part; +namespace Part { + extern Py::Object shape2pyshape(const TopoDS_Shape &shape); +} + // returns a string which represent the object e.g. when printed in python std::string TopoShapeFacePy::representation(void) const { @@ -438,6 +443,59 @@ PyObject* TopoShapeFacePy::makeOffset(PyObject *args) return new TopoShapePy(new TopoShape(mkOffset.Shape())); } +/* +v = App.Vector +profile = Part.makePolygon([v(0.,0.,0.), v(-60.,-60.,-100.), v(-60.,-60.,-140.)]) +spine = Part.Face(Part.makePolygon([v(0.,0.,0.), v(100.,0.,0.), v(100.,100.,0.), v(0.,100.,0.), v(0.,0.,0.)])) +evolve = spine.makeEvolved(profile) +*/ +PyObject* TopoShapeFacePy::makeEvolved(PyObject *args, PyObject *kwds) +{ + PyObject* Profile; + PyObject* AxeProf = Py_True; + PyObject* Solid = Py_False; + PyObject* ProfOnSpine = Py_False; + int JoinType = int(GeomAbs_Arc); + double Tolerance = 0.0000001; + + static char* kwds_evolve[] = {"Profile", "Join", "AxeProf", "Solid", "ProfOnSpine", "Tolerance", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|iO!O!O!d", kwds_evolve, + &TopoShapeWirePy::Type, &Profile, &JoinType, + &PyBool_Type, &AxeProf, &PyBool_Type, &Solid, + &PyBool_Type, &ProfOnSpine, &Tolerance)) + return nullptr; + + const TopoDS_Face& spine = TopoDS::Face(getTopoShapePtr()->getShape()); + BRepBuilderAPI_FindPlane findPlane(spine); + if (!findPlane.Found()) { + PyErr_SetString(PartExceptionOCCError, "No planar face"); + return nullptr; + } + + const TopoDS_Wire& profile = TopoDS::Wire(static_cast(Profile)->getTopoShapePtr()->getShape()); + + GeomAbs_JoinType joinType; + switch (JoinType) { + case GeomAbs_Tangent: + joinType = GeomAbs_Tangent; + break; + case GeomAbs_Intersection: + joinType = GeomAbs_Intersection; + break; + default: + joinType = GeomAbs_Arc; + break; + } + + BRepOffsetAPI_MakeEvolved evolved(spine, profile, joinType, + PyObject_IsTrue(AxeProf) ? Standard_True : Standard_False, + PyObject_IsTrue(Solid) ? Standard_True : Standard_False, + PyObject_IsTrue(ProfOnSpine) ? Standard_True : Standard_False, + Tolerance); + TopoDS_Shape shape = evolved.Shape(); + return Py::new_reference_to(shape2pyshape(shape)); +} + PyObject* TopoShapeFacePy::valueAt(PyObject *args) { double u,v; diff --git a/src/Mod/Part/App/TopoShapeWirePy.xml b/src/Mod/Part/App/TopoShapeWirePy.xml index ab033e2064..04959c1d03 100644 --- a/src/Mod/Part/App/TopoShapeWirePy.xml +++ b/src/Mod/Part/App/TopoShapeWirePy.xml @@ -58,6 +58,11 @@ Transition can be 0 (default), 1 (right corners) or 2 (rounded corners). + + + Profile along the spine + + Approximate B-Spline-curve from this wire diff --git a/src/Mod/Part/App/TopoShapeWirePyImp.cpp b/src/Mod/Part/App/TopoShapeWirePyImp.cpp index a1f32d6d03..f00f3e2e7c 100644 --- a/src/Mod/Part/App/TopoShapeWirePyImp.cpp +++ b/src/Mod/Part/App/TopoShapeWirePyImp.cpp @@ -45,6 +45,7 @@ # include # include #endif +#include #include #include @@ -307,6 +308,59 @@ PyObject* TopoShapeWirePy::makePipeShell(PyObject *args) return 0; } +/* +v = App.Vector +profile = Part.makePolygon([v(0.,0.,0.), v(-60.,-60.,-100.), v(-60.,-60.,-140.)]) +spine = Part.makePolygon([v(0.,0.,0.), v(100.,0.,0.), v(100.,100.,0.), v(0.,100.,0.), v(0.,0.,0.)]) +evolve = spine.makeEvolved(profile) +*/ +PyObject* TopoShapeWirePy::makeEvolved(PyObject *args, PyObject *kwds) +{ + PyObject* Profile; + PyObject* AxeProf = Py_True; + PyObject* Solid = Py_False; + PyObject* ProfOnSpine = Py_False; + int JoinType = int(GeomAbs_Arc); + double Tolerance = 0.0000001; + + static char* kwds_evolve[] = {"Profile", "Join", "AxeProf", "Solid", "ProfOnSpine", "Tolerance", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|iO!O!O!d", kwds_evolve, + &TopoShapeWirePy::Type, &Profile, &JoinType, + &PyBool_Type, &AxeProf, &PyBool_Type, &Solid, + &PyBool_Type, &ProfOnSpine, &Tolerance)) + return nullptr; + + const TopoDS_Wire& spine = TopoDS::Wire(getTopoShapePtr()->getShape()); + BRepBuilderAPI_FindPlane findPlane(spine); + if (!findPlane.Found()) { + PyErr_SetString(PartExceptionOCCError, "No planar wire"); + return nullptr; + } + + const TopoDS_Wire& profile = TopoDS::Wire(static_cast(Profile)->getTopoShapePtr()->getShape()); + + GeomAbs_JoinType joinType; + switch (JoinType) { + case GeomAbs_Tangent: + joinType = GeomAbs_Tangent; + break; + case GeomAbs_Intersection: + joinType = GeomAbs_Intersection; + break; + default: + joinType = GeomAbs_Arc; + break; + } + + BRepOffsetAPI_MakeEvolved evolved(spine, profile, joinType, + PyObject_IsTrue(AxeProf) ? Standard_True : Standard_False, + PyObject_IsTrue(Solid) ? Standard_True : Standard_False, + PyObject_IsTrue(ProfOnSpine) ? Standard_True : Standard_False, + Tolerance); + TopoDS_Shape shape = evolved.Shape(); + return Py::new_reference_to(shape2pyshape(shape)); +} + PyObject* TopoShapeWirePy::makeHomogenousWires(PyObject *args) { PyObject* wire; From edf5d13de6da0c38fc369495d871f471ca069711 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 30 Nov 2021 20:03:26 +0100 Subject: [PATCH 100/133] Part: add module with enums --- src/Mod/Part/CMakeLists.txt | 1 + src/Mod/Part/PartEnums.py | 65 +++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 src/Mod/Part/PartEnums.py diff --git a/src/Mod/Part/CMakeLists.txt b/src/Mod/Part/CMakeLists.txt index e231288c21..8497099ca8 100644 --- a/src/Mod/Part/CMakeLists.txt +++ b/src/Mod/Part/CMakeLists.txt @@ -8,6 +8,7 @@ set(Part_Scripts Init.py JoinFeatures.py MakeBottle.py + PartEnums.py TestPartApp.py ) diff --git a/src/Mod/Part/PartEnums.py b/src/Mod/Part/PartEnums.py new file mode 100644 index 0000000000..dbd983c908 --- /dev/null +++ b/src/Mod/Part/PartEnums.py @@ -0,0 +1,65 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2021 Werner Mayer * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "PartEnums module" +__author__ = "Werner Mayer" +__url__ = "http://www.freecadweb.org" +__doc__ = "Enum types" + +from enum import IntEnum + +class JoinType(IntEnum): + Arc = 0 + Tangent = 1 + Intersection = 2 + +class Shape(IntEnum): + C0 = 0 + G1 = 1 + C1 = 2 + G2 = 3 + C2 = 4 + C3 = 5 + CN = 6 + +class FillingStyle(IntEnum): + StretchStyle = 0 + CoonsStyle = 1 + CurvedStyle = 2 + +class Orientation(IntEnum): + FORWARD = 0 + REVERSED = 1 + INTERNAL = 2 + EXTERNAL = 3 + +class ShapeEnum(IntEnum): + COMPOUND = 0 + COMPSOLID = 1 + SOLID = 2 + SHELL= 3 + FACE = 4 + WIRE = 5 + EDGE = 6 + VERTEX = 7 + SHAPE = 8 + From a05cd50fa5a2a9363ef4f4d4b83b71e2ae061888 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 30 Nov 2021 20:04:31 +0100 Subject: [PATCH 101/133] Part: add exception handling to Face.makeEvolved/Wire.makeEvolved --- src/Mod/Part/App/TopoShapeFacePyImp.cpp | 23 +++++++++++++++-------- src/Mod/Part/App/TopoShapeWirePyImp.cpp | 23 +++++++++++++++-------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/Mod/Part/App/TopoShapeFacePyImp.cpp b/src/Mod/Part/App/TopoShapeFacePyImp.cpp index fba5f73879..089857d117 100644 --- a/src/Mod/Part/App/TopoShapeFacePyImp.cpp +++ b/src/Mod/Part/App/TopoShapeFacePyImp.cpp @@ -444,10 +444,11 @@ PyObject* TopoShapeFacePy::makeOffset(PyObject *args) } /* +import PartEnums v = App.Vector profile = Part.makePolygon([v(0.,0.,0.), v(-60.,-60.,-100.), v(-60.,-60.,-140.)]) spine = Part.Face(Part.makePolygon([v(0.,0.,0.), v(100.,0.,0.), v(100.,100.,0.), v(0.,100.,0.), v(0.,0.,0.)])) -evolve = spine.makeEvolved(profile) +evolve = spine.makeEvolved(Profile=profile, Join=PartEnums.JoinType.Arc) */ PyObject* TopoShapeFacePy::makeEvolved(PyObject *args, PyObject *kwds) { @@ -487,13 +488,19 @@ PyObject* TopoShapeFacePy::makeEvolved(PyObject *args, PyObject *kwds) break; } - BRepOffsetAPI_MakeEvolved evolved(spine, profile, joinType, - PyObject_IsTrue(AxeProf) ? Standard_True : Standard_False, - PyObject_IsTrue(Solid) ? Standard_True : Standard_False, - PyObject_IsTrue(ProfOnSpine) ? Standard_True : Standard_False, - Tolerance); - TopoDS_Shape shape = evolved.Shape(); - return Py::new_reference_to(shape2pyshape(shape)); + try { + BRepOffsetAPI_MakeEvolved evolved(spine, profile, joinType, + PyObject_IsTrue(AxeProf) ? Standard_True : Standard_False, + PyObject_IsTrue(Solid) ? Standard_True : Standard_False, + PyObject_IsTrue(ProfOnSpine) ? Standard_True : Standard_False, + Tolerance); + TopoDS_Shape shape = evolved.Shape(); + return Py::new_reference_to(shape2pyshape(shape)); + } + catch (Standard_Failure& e) { + PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); + return nullptr; + } } PyObject* TopoShapeFacePy::valueAt(PyObject *args) diff --git a/src/Mod/Part/App/TopoShapeWirePyImp.cpp b/src/Mod/Part/App/TopoShapeWirePyImp.cpp index f00f3e2e7c..c48b6046b0 100644 --- a/src/Mod/Part/App/TopoShapeWirePyImp.cpp +++ b/src/Mod/Part/App/TopoShapeWirePyImp.cpp @@ -309,10 +309,11 @@ PyObject* TopoShapeWirePy::makePipeShell(PyObject *args) } /* +import PartEnums v = App.Vector profile = Part.makePolygon([v(0.,0.,0.), v(-60.,-60.,-100.), v(-60.,-60.,-140.)]) spine = Part.makePolygon([v(0.,0.,0.), v(100.,0.,0.), v(100.,100.,0.), v(0.,100.,0.), v(0.,0.,0.)]) -evolve = spine.makeEvolved(profile) +evolve = spine.makeEvolved(Profile=profile, Join=PartEnums.JoinType.Arc) */ PyObject* TopoShapeWirePy::makeEvolved(PyObject *args, PyObject *kwds) { @@ -352,13 +353,19 @@ PyObject* TopoShapeWirePy::makeEvolved(PyObject *args, PyObject *kwds) break; } - BRepOffsetAPI_MakeEvolved evolved(spine, profile, joinType, - PyObject_IsTrue(AxeProf) ? Standard_True : Standard_False, - PyObject_IsTrue(Solid) ? Standard_True : Standard_False, - PyObject_IsTrue(ProfOnSpine) ? Standard_True : Standard_False, - Tolerance); - TopoDS_Shape shape = evolved.Shape(); - return Py::new_reference_to(shape2pyshape(shape)); + try { + BRepOffsetAPI_MakeEvolved evolved(spine, profile, joinType, + PyObject_IsTrue(AxeProf) ? Standard_True : Standard_False, + PyObject_IsTrue(Solid) ? Standard_True : Standard_False, + PyObject_IsTrue(ProfOnSpine) ? Standard_True : Standard_False, + Tolerance); + TopoDS_Shape shape = evolved.Shape(); + return Py::new_reference_to(shape2pyshape(shape)); + } + catch (Standard_Failure& e) { + PyErr_SetString(PartExceptionOCCError, e.GetMessageString()); + return nullptr; + } } PyObject* TopoShapeWirePy::makeHomogenousWires(PyObject *args) From 770c7f6330403fb6d2882ea41e22940d6ffdfc6b Mon Sep 17 00:00:00 2001 From: Mark O'Donovan Date: Wed, 1 Dec 2021 03:31:34 +0000 Subject: [PATCH 102/133] Replace deprecated qt functions toList() & toSet() (#5213) * Replace deprecated qt functions toList() & toSet() QSet::toList() and QStringList::toSet() are both deprecated. * Add back support for qt < 5.14 --- src/Gui/DocumentRecovery.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Gui/DocumentRecovery.cpp b/src/Gui/DocumentRecovery.cpp index aea8bee3c4..9b3186733a 100644 --- a/src/Gui/DocumentRecovery.cpp +++ b/src/Gui/DocumentRecovery.cpp @@ -706,10 +706,17 @@ void DocumentRecoveryCleaner::clearDirectory(const QFileInfo& dir) void DocumentRecoveryCleaner::subtractFiles(QStringList& files) { if (!ignoreFiles.isEmpty() && !files.isEmpty()) { +#if QT_VERSION >= QT_VERSION_CHECK(5,14,0) + auto set1 = QSet(files.begin(), files.end()); + auto set2 = QSet(ignoreFiles.begin(), ignoreFiles.end()); + set1.subtract(set2); + files = QList(set1.begin(), set1.end()); +#else QSet set1 = files.toSet(); QSet set2 = ignoreFiles.toSet(); set1.subtract(set2); files = set1.toList(); +#endif } } From 569f61b19a28c02dfa1aae14b5e573a2b05aae42 Mon Sep 17 00:00:00 2001 From: mdkus Date: Wed, 1 Dec 2021 09:20:36 +0100 Subject: [PATCH 103/133] Update CreatePyModule.py Small bug fix: in comparison to CreateModule.py this codeline is missing in CreatePyModule.py, so CreatePyModule.py doesn't work,fine without it (tested under Win 7 and Win11) --- src/Tools/fcbt/CreatePyModule.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tools/fcbt/CreatePyModule.py b/src/Tools/fcbt/CreatePyModule.py index ab5e31ee27..25f8e45a36 100644 --- a/src/Tools/fcbt/CreatePyModule.py +++ b/src/Tools/fcbt/CreatePyModule.py @@ -115,6 +115,7 @@ def validateApp(AppName): sys.exit() sys.stdout.write("Please enter a name for your application:") +sys.stdout.flush() AppName = sys.stdin.readline()[:-1] validateApp(AppName) createApp(AppName) From 5e16fffc20860e971c3467f350d53c5b71646e61 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 1 Dec 2021 13:34:24 +0100 Subject: [PATCH 104/133] App: [skip ci] improve importing a Python module when passed as program argument --- src/App/Application.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 714bd83af9..67aa53a8d2 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -2631,11 +2631,12 @@ std::list Application::processFiles(const std::list& f processed.push_back(*it); } else if (file.hasExtension("py")) { - try{ + try { + Base::Interpreter().addPythonPath(file.dirPath().c_str()); Base::Interpreter().loadModule(file.fileNamePure().c_str()); processed.push_back(*it); } - catch(const PyException&) { + catch (const PyException&) { // if loading the module does not work, try just running the script (run in __main__) Base::Interpreter().runFile(file.filePath().c_str(),true); processed.push_back(*it); From be88e838c1eeb2ec70b9b66780a63ee0008240e5 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Mon, 29 Nov 2021 21:40:20 +0100 Subject: [PATCH 105/133] [Sketcher][Bugfix] Slot: fix segfault accessing empty vector --- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 26bb0f6ebe..ac64ff6663 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -7145,7 +7145,8 @@ public: try { Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add slot")); - AutoConstraint lastCons = sugConstr2.back(); + AutoConstraint lastCons = {Sketcher::None, Sketcher::Constraint::GeoUndef, Sketcher::none}; + if (!sugConstr2.empty()) lastCons = sugConstr2.back(); ostringstream snapCon = ostringstream(""); if (SnapMode == SNAP_MODE_Straight) { From b2800dfbb8a5db9041ca62cd5ad23565ab247dc8 Mon Sep 17 00:00:00 2001 From: sliptonic Date: Thu, 18 Nov 2021 09:37:53 -0600 Subject: [PATCH 106/133] draft generator and tests --- src/Mod/Path/Generators/rotation_generator.py | 205 ++++++++++++++++++ .../PathTests/TestPathRotationGenerator.py | 169 +++++++++++++++ 2 files changed, 374 insertions(+) create mode 100644 src/Mod/Path/Generators/rotation_generator.py create mode 100644 src/Mod/Path/PathTests/TestPathRotationGenerator.py diff --git a/src/Mod/Path/Generators/rotation_generator.py b/src/Mod/Path/Generators/rotation_generator.py new file mode 100644 index 0000000000..47749b49a5 --- /dev/null +++ b/src/Mod/Path/Generators/rotation_generator.py @@ -0,0 +1,205 @@ +# -*- coding: utf-8 -*- +# *************************************************************************** +# * Copyright (c) 2021 sliptonic * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + + +# Technical Debt. This generator currently assumes 3+2 axis rotation of CA. +# The main generator function should be extended to include other flavors of 3+2 + + +import PathScripts.PathLog as PathLog +import math +import Path +import FreeCAD +from enum import Enum + +__title__ = "Rotation Path Generator" +__author__ = "sliptonic (Brad Collette)" +__url__ = "https://www.freecadweb.org" +__doc__ = "Generates the rotation toolpath" + + +if False: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) + + +class refAxis(Enum): + x = FreeCAD.Vector(1, 0, 0) + y = FreeCAD.Vector(0, 1, 0) + z = FreeCAD.Vector(0, 0, 1) + + +def relAngle(vec, ref): + """ + Takes a vector and a reference axis (refAxis) vector. Calculates the + relative angle. The result is returned in degrees (plus or minus) + """ + + PathLog.debug("vec: {} ref: {}".format(vec, ref)) + norm = vec * 1 # copy vec so we don't alter original + + if ref == refAxis.x: + plane = refAxis.y.value + elif ref == refAxis.y: + plane = refAxis.z.value + else: + plane = refAxis.x.value + + norm.projectToPlane(FreeCAD.Vector(0, 0, 0), plane) + + ref = ref.value + rot = FreeCAD.Rotation(norm, ref) + ang = math.degrees(rot.Angle) + angle = ang * plane.dot(rot.Axis) + PathLog.debug("relative ang: {}".format(angle)) + + return angle + + +def __getCRotation(normalVector, cMin=-360, cMax=360): + """ + Calculate the valid C axis rotations component to align the normalVector + with either the +y or -y axis. + multiple poses may be possible. Returns a list of all valid poses + """ + PathLog.debug("normalVector: {} cMin: {} cMax: {}".format(normalVector, cMin, cMax)) + + angle = relAngle(normalVector, refAxis.y) + + # Given an angle, there are four possibilities; rotating +- to each of the + # two axes +y and -y + candidates = [angle] + if angle == 0: + candidates.append(180) + elif angle == 180: + candidates.append(0) + elif angle >= 0: + candidates.append(angle - 180) + candidates.append(180 + angle) + candidates.append(angle - 360) + else: + candidates.append(angle + 180) + candidates.append(-180 + angle) + candidates.append(angle + 360) + + # final results are candidates that don't violate rotation limits + results = [c for c in candidates if c >= cMin and c <= cMax] + + return results + + +def __getARotation(normalVector, aMin=-360, aMax=360): + """ + Calculate the A axis rotation component. + Final rotation is always assumed to be around +X. The sign of the returned + value indicates direction of rotation. + + Returns None if rotation violates min/max constraints + """ + + angle = relAngle(normalVector, refAxis.z) + + # only return a result if it doesn't violate rotation constraints + if angle > aMin and angle <= aMax: + return angle + else: + return None + + +def generate(normalVector, aMin=-360, aMax=360, cMin=-360, cMax=360, compound=False): + """ + Generates Gcode rotation to align a vector (alignVector) with the positive Z axis. + + It first rotates around the Z axis (C rotation) + to align the vector the positive Y axis. Then around the X axis + (A rotation). + + The min and max arguments dictate the range of motion allowed rotation in the respective + axis. + Default assumes continous rotation. + + returns a list of path commands for the shortest valid solution + + if compound is False, axis moves will be broken out to individual commands + + The normalVector input from a typical face (f) can be obtained like this: + + u, v = f.ParameterRange[:2] + n = f.normalAt(u,v) + plm = obj.getGlobalPlacement() + rot = plm.Rotation + normalVector = rot.multVec(n + """ + + PathLog.track( + "\n=============\n normalVector: {}\n aMin: {}\n aMax: {}\n cMin: {}\n cMax: {}".format( + normalVector, aMin, aMax, cMin, cMax + ) + ) + + # Calculate C rotation + cResults = __getCRotation(normalVector, cMin, cMax) + PathLog.debug("C Rotation results {}".format(cResults)) + + solutions = [] + for result in cResults: + + # calculate a new vector based on the result + rot = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), result) + newvec = rot.multVec(normalVector) + + # Get the candidate A rotation for the new vector + aResult = __getARotation(newvec, aMin, aMax) + + PathLog.debug( + "\n=====\nFor C Rotation: {}\n Calculated A {}\n".format(result, aResult) + ) + + if aResult is not None: + solutions.append({"A": aResult, "C": result}) + + if len(solutions) == 0: # No valid solution found + raise ValueError("No valid rotation solution found") + + # find pose with the shortest transit length + best = solutions[0] + curlen = math.fabs(best["A"]) + math.fabs(best["C"]) + for solution in solutions[1:]: + testlen = math.fabs(solution["A"]) + math.fabs(solution["C"]) + if testlen < curlen: + best = solution + curlen = testlen + + PathLog.debug("best result: {}".format(best)) + + # format and return rotation commands + commands = [] + if compound: + commands.append(Path.Command("G0", best)) + else: + for key, val in best.items(): + print(key, val) + commands.append(Path.Command("G0", {key: val})) + + return commands diff --git a/src/Mod/Path/PathTests/TestPathRotationGenerator.py b/src/Mod/Path/PathTests/TestPathRotationGenerator.py new file mode 100644 index 0000000000..c9a3065d58 --- /dev/null +++ b/src/Mod/Path/PathTests/TestPathRotationGenerator.py @@ -0,0 +1,169 @@ +# -*- coding: utf-8 -*- +# *************************************************************************** +# * Copyright (c) 2021 sliptonic * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import Path +import FreeCAD +import Generators.rotation_generator as generator +import PathScripts.PathLog as PathLog +import PathTests.PathTestUtils as PathTestUtils +import numpy as np + +PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) +PathLog.trackModule(PathLog.thisModule()) + + +class TestPathRotationGenerator(PathTestUtils.PathTestBase): + def test00(self): + """Test relAngle function""" + v = FreeCAD.Vector(0.5, 0.5, 0.5) + self.assertTrue(np.isclose(generator.relAngle(v, generator.refAxis.x), 45)) + self.assertTrue(np.isclose(generator.relAngle(v, generator.refAxis.y), 45)) + self.assertTrue(np.isclose(generator.relAngle(v, generator.refAxis.z), 45)) + + v = FreeCAD.Vector(-0.5, 0.5, 0.5) + self.assertTrue(np.isclose(generator.relAngle(v, generator.refAxis.x), 135)) + self.assertTrue(np.isclose(generator.relAngle(v, generator.refAxis.y), -45)) + self.assertTrue(np.isclose(generator.relAngle(v, generator.refAxis.z), 45)) + + v = FreeCAD.Vector(-0.5, -0.5, -0.5) + self.assertTrue(np.isclose(generator.relAngle(v, generator.refAxis.x), -135)) + self.assertTrue(np.isclose(generator.relAngle(v, generator.refAxis.y), -135)) + self.assertTrue(np.isclose(generator.relAngle(v, generator.refAxis.z), -135)) + + def test10(self): + """Test Basic Rotation Generator Return""" + v1 = FreeCAD.Vector(0.0, 0.0, 1.0) + args = { + "normalVector": v1, + "aMin": -360, + "aMax": 360, + "cMin": -360, + "cMax": 360, + "compound": True, + } + + result = generator.generate(**args) + + self.assertTrue(type(result) is list) + self.assertTrue(len(result) == 1) + self.assertTrue(type(result[0]) is Path.Command) + + command = result[0] + self.assertTrue(np.isclose(command.Parameters["A"], 0)) + self.assertTrue(np.isclose(command.Parameters["C"], 0)) + + args["compound"] = False + result = generator.generate(**args) + self.assertTrue(len(result) == 2) + + PathLog.debug(result) + + def test20(self): + """Test non-zero rotation""" + v1 = FreeCAD.Vector(0.5, 0.5, 0.5) + args = { + "normalVector": v1, + "aMin": -360, + "aMax": 360, + "cMin": -360, + "cMax": 360, + "compound": True, + } + + result = generator.generate(**args) + + command = result[0] + PathLog.debug(command.Parameters) + self.assertTrue(np.isclose(command.Parameters["A"], 54.736)) + self.assertTrue(np.isclose(command.Parameters["C"], 45)) + + PathLog.track(result) + + def test30(self): + """Test A limits""" + v1 = FreeCAD.Vector(0.5, 0.5, 0.5) + + args = {"normalVector": v1, "cMin": -360, "cMax": 360, "compound": True} + + # Constrain a axis rotation negative + args["aMin"] = -90 + args["aMax"] = 0 + + result = generator.generate(**args) + PathLog.debug(result) + + command = result[0] + self.assertTrue(np.isclose(command.Parameters["A"], -54.736)) + self.assertTrue(np.isclose(command.Parameters["C"], -135)) + + # Constrain a axis rotation positive + args["aMin"] = 0 + args["aMax"] = 90 + + result = generator.generate(**args) + PathLog.debug(result) + + command = result[0] + self.assertTrue(np.isclose(command.Parameters["A"], 54.736)) + self.assertTrue(np.isclose(command.Parameters["C"], 45)) + + def test40(self): + """Test C limits""" + v1 = FreeCAD.Vector(0.5, 0.5, 0.5) + + args = {"normalVector": v1, "aMin": -360, "aMax": 360, "compound": True} + + # Constrain a axis rotation negative + args["cMin"] = -180 + args["cMax"] = 0 + + result = generator.generate(**args) + PathLog.debug(result) + + command = result[0] + self.assertTrue(np.isclose(command.Parameters["A"], -54.736)) + self.assertTrue(np.isclose(command.Parameters["C"], -135)) + + # Constrain a axis rotation positive + args["cMin"] = 0 + args["cMax"] = 180 + + result = generator.generate(**args) + PathLog.debug(result) + + command = result[0] + self.assertTrue(np.isclose(command.Parameters["A"], 54.736)) + self.assertTrue(np.isclose(command.Parameters["C"], 45)) + + def test50(self): + """Test handling of no valid solution""" + v1 = FreeCAD.Vector(0.5, 0.5, 0.5) + args = { + "normalVector": v1, + "aMin": 0, + "aMax": 10, + "cMin": 0, + "cMax": 10, + "compound": True, + } + + self.assertRaises(ValueError, generator.generate, **args) From 58f33f350d81ec708c8888edfd4963497ef75fa5 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 1 Dec 2021 21:50:00 +0100 Subject: [PATCH 107/133] Gui: fix build failure with C++20 --- src/Gui/DAGView/DAGView.cpp | 6 ++---- src/Gui/DAGView/DAGView.h | 5 ++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Gui/DAGView/DAGView.cpp b/src/Gui/DAGView/DAGView.cpp index d026e245f5..a69eec18a7 100644 --- a/src/Gui/DAGView/DAGView.cpp +++ b/src/Gui/DAGView/DAGView.cpp @@ -56,8 +56,8 @@ View::View(QWidget* parentIn): QGraphicsView(parentIn) { this->setRenderHint(QPainter::Antialiasing, true); this->setRenderHint(QPainter::TextAntialiasing, true); - Application::Instance->signalActiveDocument.connect(boost::bind(&View::slotActiveDocument, this, bp::_1)); - Application::Instance->signalDeleteDocument.connect(boost::bind(&View::slotDeleteDocument, this, bp::_1)); + conActive = Application::Instance->signalActiveDocument.connect(boost::bind(&View::slotActiveDocument, this, bp::_1)); + conDelete = Application::Instance->signalDeleteDocument.connect(boost::bind(&View::slotDeleteDocument, this, bp::_1)); //just update the dagview when the gui process is idle. connect(QAbstractEventDispatcher::instance(), SIGNAL(awake()), this, SLOT(awakeSlot())); @@ -65,8 +65,6 @@ View::View(QWidget* parentIn): QGraphicsView(parentIn) View::~View() { - Application::Instance->signalActiveDocument.disconnect(boost::bind(&View::slotActiveDocument, this, bp::_1)); - Application::Instance->signalDeleteDocument.disconnect(boost::bind(&View::slotDeleteDocument, this, bp::_1)); } void View::slotActiveDocument(const Document &documentIn) diff --git a/src/Gui/DAGView/DAGView.h b/src/Gui/DAGView/DAGView.h index 610bedf4c7..7a82dbe415 100644 --- a/src/Gui/DAGView/DAGView.h +++ b/src/Gui/DAGView/DAGView.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -56,6 +57,8 @@ namespace Gui typedef std::map > ModelMap; ModelMap modelMap; + boost::signals2::scoped_connection conActive; + boost::signals2::scoped_connection conDelete; }; //! @brief dock window for DAG viewer @@ -64,7 +67,7 @@ namespace Gui Q_OBJECT public: DockWindow(Gui::Document* gDocumentIn = 0, QWidget *parent = 0); - ~DockWindow(){}; + ~DockWindow(){} private: View *dagView; From 2fd81006ea5fc0365e5f83f23034249d75be7a9d Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 1 Dec 2021 23:24:16 +0100 Subject: [PATCH 108/133] PD: fix build failure with C++20 --- src/Mod/PartDesign/Gui/Workbench.cpp | 19 ++++++++----------- src/Mod/PartDesign/Gui/Workbench.h | 13 +++++++------ 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 4ae7939dda..76f8cc1eda 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -452,22 +452,19 @@ void Workbench::activated() Gui::Control().showTaskView(); // Let us be notified when a document is activated, so that we can update the ActivePartObject - Gui::Application::Instance->signalActiveDocument.connect(boost::bind(&Workbench::slotActiveDocument, this, bp::_1)); - App::GetApplication().signalNewDocument.connect(boost::bind(&Workbench::slotNewDocument, this, bp::_1)); - App::GetApplication().signalFinishRestoreDocument.connect(boost::bind(&Workbench::slotFinishRestoreDocument, this, bp::_1)); - App::GetApplication().signalDeleteDocument.connect(boost::bind(&Workbench::slotDeleteDocument, this, bp::_1)); - // Watch out for objects being added to the active document, so that we can add them to the body - //App::GetApplication().signalNewObject.connect(boost::bind(&Workbench::slotNewObject, this, bp::_1)); + activeDoc = Gui::Application::Instance->signalActiveDocument.connect(boost::bind(&Workbench::slotActiveDocument, this, bp::_1)); + createDoc = App::GetApplication().signalNewDocument.connect(boost::bind(&Workbench::slotNewDocument, this, bp::_1)); + finishDoc = App::GetApplication().signalFinishRestoreDocument.connect(boost::bind(&Workbench::slotFinishRestoreDocument, this, bp::_1)); + deleteDoc = App::GetApplication().signalDeleteDocument.connect(boost::bind(&Workbench::slotDeleteDocument, this, bp::_1)); } void Workbench::deactivated() { // Let us be notified when a document is activated, so that we can update the ActivePartObject - Gui::Application::Instance->signalActiveDocument.disconnect(boost::bind(&Workbench::slotActiveDocument, this, bp::_1)); - App::GetApplication().signalNewDocument.disconnect(boost::bind(&Workbench::slotNewDocument, this, bp::_1)); - App::GetApplication().signalFinishRestoreDocument.disconnect(boost::bind(&Workbench::slotFinishRestoreDocument, this, bp::_1)); - App::GetApplication().signalDeleteDocument.disconnect(boost::bind(&Workbench::slotDeleteDocument, this, bp::_1)); - //App::GetApplication().signalNewObject.disconnect(boost::bind(&Workbench::slotNewObject, this, bp::_1)); + activeDoc.disconnect(); + createDoc.disconnect(); + finishDoc.disconnect(); + deleteDoc.disconnect(); removeTaskWatcher(); // reset the active Body diff --git a/src/Mod/PartDesign/Gui/Workbench.h b/src/Mod/PartDesign/Gui/Workbench.h index 382fab4e95..647bd6c54a 100644 --- a/src/Mod/PartDesign/Gui/Workbench.h +++ b/src/Mod/PartDesign/Gui/Workbench.h @@ -24,7 +24,9 @@ #ifndef PARTDESIGN_WORKBENCH_H #define PARTDESIGN_WORKBENCH_H +#include #include +#include namespace Gui { @@ -36,12 +38,6 @@ class ViewProviderDocumentObject; namespace PartDesignGui { -// pointer to the active assembly object -//extern PartDesign::Body *ActivePartObject; -//extern Gui::Document *ActiveGuiDoc; -//extern App::Document *ActiveAppDoc; -//extern Gui::ViewProviderDocumentObject *ActiveVp; - /** * @author Werner Mayer */ @@ -80,6 +76,11 @@ private: void _switchToDocument(const App::Document* doc); +private: + boost::signals2::connection activeDoc; + boost::signals2::connection createDoc; + boost::signals2::connection finishDoc; + boost::signals2::connection deleteDoc; }; } // namespace PartDesignGui From bbacecb3975dad2cd1bf6a34f7291cf2543be178 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 1 Dec 2021 23:45:26 +0100 Subject: [PATCH 109/133] Gui: fix C++20 warning: bitwise operation between different enumeration types [-Wdeprecated-enum-enum-conversion] --- src/Gui/EditorView.cpp | 3 ++- src/Gui/PythonConsole.cpp | 3 ++- src/Gui/TextEdit.cpp | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Gui/EditorView.cpp b/src/Gui/EditorView.cpp index 9f41a88e60..8180a66253 100644 --- a/src/Gui/EditorView.cpp +++ b/src/Gui/EditorView.cpp @@ -116,7 +116,8 @@ EditorView::EditorView(QPlainTextEdit* editor, QWidget* parent) // Create the layout containing the workspace and a tab bar QFrame* hbox = new QFrame(this); - hbox->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + hbox->setFrameShape(QFrame::StyledPanel); + hbox->setFrameShadow(QFrame::Sunken); QVBoxLayout* layout = new QVBoxLayout(); layout->setMargin(1); layout->addWidget(d->textEdit); diff --git a/src/Gui/PythonConsole.cpp b/src/Gui/PythonConsole.cpp index 3eacfdacfa..1173484427 100644 --- a/src/Gui/PythonConsole.cpp +++ b/src/Gui/PythonConsole.cpp @@ -431,7 +431,8 @@ PythonConsole::PythonConsole(QWidget *parent) // create the window for call tips d->callTipsList = new CallTipsList(this); - d->callTipsList->setFrameStyle(QFrame::Box|QFrame::Raised); + d->callTipsList->setFrameStyle(QFrame::Box); + d->callTipsList->setFrameShadow(QFrame::Raised); d->callTipsList->setLineWidth(2); installEventFilter(d->callTipsList); viewport()->installEventFilter(d->callTipsList); diff --git a/src/Gui/TextEdit.cpp b/src/Gui/TextEdit.cpp index 219a3d72fc..e3dea6ae07 100644 --- a/src/Gui/TextEdit.cpp +++ b/src/Gui/TextEdit.cpp @@ -178,7 +178,8 @@ void TextEdit::complete() void TextEdit::createListBox() { listBox = new CompletionList(this); - listBox->setFrameStyle(QFrame::Box|QFrame::Raised); + listBox->setFrameStyle(QFrame::Box); + listBox->setFrameShadow(QFrame::Raised); listBox->setLineWidth(2); installEventFilter(listBox); viewport()->installEventFilter(listBox); From 2e5bcae6b8d5d3dc6452db4b53da0a327ac2cf1d Mon Sep 17 00:00:00 2001 From: Syres916 <46537884+Syres916@users.noreply.github.com> Date: Wed, 1 Dec 2021 09:35:00 +0000 Subject: [PATCH 110/133] Change macro path selection from File to Folder --- src/Gui/DlgSettingsMacro.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Gui/DlgSettingsMacro.ui b/src/Gui/DlgSettingsMacro.ui index 7840a14aad..7ec3cebad1 100644 --- a/src/Gui/DlgSettingsMacro.ui +++ b/src/Gui/DlgSettingsMacro.ui @@ -220,6 +220,9 @@ The directory in which the application will search for macros + + Gui::FileChooser::Directory + MacroPath From 4f12416fa0672327ea542b111bf4b223b9d54ab3 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 2 Dec 2021 09:59:31 +0100 Subject: [PATCH 111/133] Gui: fix C++20 warning: bitwise operation between different enumeration types [-Wdeprecated-enum-enum-conversion] --- src/Gui/CommandView.cpp | 14 ++++++-------- src/Gui/PythonConsole.cpp | 6 +++--- src/Gui/PythonEditor.cpp | 8 ++++---- src/Gui/TextEdit.cpp | 2 +- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index 8b725210fb..ca75721871 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -352,17 +352,16 @@ void StdCmdFreezeViews::activated(int iMsg) getGuiApplication()->sendMsgToActiveView("GetCamera",&ppReturn); QList acts = pcAction->actions(); - int index = 0; + int index = 1; for (QList::ConstIterator it = acts.begin()+offset; it != acts.end(); ++it, index++) { if (!(*it)->isVisible()) { savedViews++; - QString viewnr = QString(QObject::tr("Restore view &%1")).arg(index+1); + QString viewnr = QString(QObject::tr("Restore view &%1")).arg(index); (*it)->setText(viewnr); (*it)->setToolTip(QString::fromLatin1(ppReturn)); (*it)->setVisible(true); - if (index < 9) { - int accel = Qt::CTRL+Qt::Key_1; - (*it)->setShortcut(accel+index); + if (index < 10) { + (*it)->setShortcut(QKeySequence(QString::fromLatin1("CTRL+%1").arg(index))); } break; } @@ -499,9 +498,8 @@ void StdCmdFreezeViews::onRestoreViews() acts[i+offset]->setText(viewnr); acts[i+offset]->setToolTip(setting); acts[i+offset]->setVisible(true); - if ( i < 9 ) { - int accel = Qt::CTRL+Qt::Key_1; - acts[i+offset]->setShortcut(accel+i); + if (i < 9) { + acts[i+offset]->setShortcut(QKeySequence(QString::fromLatin1("CTRL+%1").arg(i+1))); } } diff --git a/src/Gui/PythonConsole.cpp b/src/Gui/PythonConsole.cpp index 1173484427..7fd9cbf6cf 100644 --- a/src/Gui/PythonConsole.cpp +++ b/src/Gui/PythonConsole.cpp @@ -1255,7 +1255,7 @@ void PythonConsole::contextMenuEvent ( QContextMenuEvent * e ) ParameterGrp::handle hGrp = App::GetApplication().GetUserParameter(). GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("General"); - a = menu.addAction(tr("&Copy"), this, SLOT(copy()), Qt::CTRL+Qt::Key_C); + a = menu.addAction(tr("&Copy"), this, SLOT(copy()), QKeySequence(QString::fromLatin1("CTRL+C"))); a->setEnabled(textCursor().hasSelection()); a = menu.addAction(tr("&Copy command"), this, SLOT(onCopyCommand())); @@ -1274,11 +1274,11 @@ void PythonConsole::contextMenuEvent ( QContextMenuEvent * e ) menu.addSeparator(); - a = menu.addAction(tr("&Paste"), this, SLOT(paste()), Qt::CTRL+Qt::Key_V); + a = menu.addAction(tr("&Paste"), this, SLOT(paste()), QKeySequence(QString::fromLatin1("CTRL+V"))); const QMimeData *md = QApplication::clipboard()->mimeData(); a->setEnabled( mayPasteHere && md && canInsertFromMimeData(md)); - a = menu.addAction(tr("Select All"), this, SLOT(selectAll()), Qt::CTRL+Qt::Key_A); + a = menu.addAction(tr("Select All"), this, SLOT(selectAll()), QKeySequence(QString::fromLatin1("CTRL+A"))); a->setEnabled(!document()->isEmpty()); a = menu.addAction(tr("Clear console"), this, SLOT(onClearConsole())); diff --git a/src/Gui/PythonEditor.cpp b/src/Gui/PythonEditor.cpp index c4c5c0ac14..808ec5c6d0 100644 --- a/src/Gui/PythonEditor.cpp +++ b/src/Gui/PythonEditor.cpp @@ -77,10 +77,10 @@ PythonEditor::PythonEditor(QWidget* parent) // set acelerators QShortcut* comment = new QShortcut(this); - comment->setKey(Qt::ALT + Qt::Key_C); + comment->setKey(QKeySequence(QString::fromLatin1("ALT+C"))); QShortcut* uncomment = new QShortcut(this); - uncomment->setKey(Qt::ALT + Qt::Key_U); + uncomment->setKey(QKeySequence(QString::fromLatin1("ALT+U"))); connect(comment, SIGNAL(activated()), this, SLOT(onComment())); @@ -157,8 +157,8 @@ void PythonEditor::contextMenuEvent ( QContextMenuEvent * e ) QMenu* menu = createStandardContextMenu(); if (!isReadOnly()) { menu->addSeparator(); - menu->addAction( tr("Comment"), this, SLOT( onComment() ), Qt::ALT + Qt::Key_C ); - menu->addAction( tr("Uncomment"), this, SLOT( onUncomment() ), Qt::ALT + Qt::Key_U ); + menu->addAction( tr("Comment"), this, SLOT( onComment() ), QKeySequence(QString::fromLatin1("ALT+C"))); + menu->addAction( tr("Uncomment"), this, SLOT( onUncomment() ), QKeySequence(QString::fromLatin1("ALT+U"))); } menu->exec(e->globalPos()); diff --git a/src/Gui/TextEdit.cpp b/src/Gui/TextEdit.cpp index e3dea6ae07..a694c57c66 100644 --- a/src/Gui/TextEdit.cpp +++ b/src/Gui/TextEdit.cpp @@ -45,7 +45,7 @@ TextEdit::TextEdit(QWidget* parent) //Note: Set the correct context to this shortcut as we may use several instances of this //class at a time QShortcut* shortcut = new QShortcut(this); - shortcut->setKey(Qt::CTRL+Qt::Key_Space); + shortcut->setKey(QKeySequence(QString::fromLatin1("CTRL+Space"))); shortcut->setContext(Qt::WidgetShortcut); connect(shortcut, SIGNAL(activated()), this, SLOT(complete())); From 96cbb3d2c0d0ceb0d02252d48c4dab46dab2c17f Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 2 Dec 2021 10:12:35 +0100 Subject: [PATCH 112/133] TD: fix C++20 warning: bitwise operation between different enumeration types [-Wdeprecated-enum-enum-conversion] --- src/Mod/TechDraw/Gui/mrichtextedit.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Mod/TechDraw/Gui/mrichtextedit.cpp b/src/Mod/TechDraw/Gui/mrichtextedit.cpp index 7cc23e368c..ad136a9358 100644 --- a/src/Mod/TechDraw/Gui/mrichtextedit.cpp +++ b/src/Mod/TechDraw/Gui/mrichtextedit.cpp @@ -146,15 +146,15 @@ MRichTextEdit::MRichTextEdit(QWidget *parent, QString textIn) : QWidget(parent) // link - f_link->setShortcut(Qt::CTRL + Qt::Key_L); + f_link->setShortcut(QKeySequence(QString::fromUtf8("CTRL+L"))); connect(f_link, SIGNAL(clicked(bool)), this, SLOT(textLink(bool))); // bold, italic & underline - f_bold->setShortcut(Qt::CTRL + Qt::Key_B); - f_italic->setShortcut(Qt::CTRL + Qt::Key_I); - f_underline->setShortcut(Qt::CTRL + Qt::Key_U); + f_bold->setShortcut(QKeySequence(QString::fromUtf8("CTRL+B"))); + f_italic->setShortcut(QKeySequence(QString::fromUtf8("CTRL+I"))); + f_underline->setShortcut(QKeySequence(QString::fromUtf8("CTRL+U"))); connect(f_bold, SIGNAL(clicked()), this, SLOT(textBold())); connect(f_italic, SIGNAL(clicked()), this, SLOT(textItalic())); @@ -184,16 +184,16 @@ MRichTextEdit::MRichTextEdit(QWidget *parent, QString textIn) : QWidget(parent) // lists - f_list_bullet->setShortcut(Qt::CTRL + Qt::Key_Minus); - f_list_ordered->setShortcut(Qt::CTRL + Qt::Key_Equal); + f_list_bullet->setShortcut(QKeySequence(QString::fromUtf8("CTRL+-"))); + f_list_ordered->setShortcut(QKeySequence(QString::fromUtf8("CTRL+="))); connect(f_list_bullet, SIGNAL(clicked(bool)), this, SLOT(listBullet(bool))); connect(f_list_ordered, SIGNAL(clicked(bool)), this, SLOT(listOrdered(bool))); // indentation - f_indent_dec->setShortcut(Qt::CTRL + Qt::Key_Comma); - f_indent_inc->setShortcut(Qt::CTRL + Qt::Key_Period); + f_indent_dec->setShortcut(QKeySequence(QString::fromUtf8("CTRL+,"))); + f_indent_inc->setShortcut(QKeySequence(QString::fromUtf8("CTRL+."))); connect(f_indent_inc, SIGNAL(clicked()), this, SLOT(increaseIndentation())); connect(f_indent_dec, SIGNAL(clicked()), this, SLOT(decreaseIndentation())); From 526dc1a030939913a2c3c9c02ada0c29063dbb32 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 2 Dec 2021 11:46:13 +0100 Subject: [PATCH 113/133] App: expose more methods of Document class to Python --- src/App/DocumentPy.xml | 50 ++++++++++++++++++++++++- src/App/DocumentPyImp.cpp | 79 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 125 insertions(+), 4 deletions(-) diff --git a/src/App/DocumentPy.xml b/src/App/DocumentPy.xml index c3dbdf7157..97a419a4ba 100644 --- a/src/App/DocumentPy.xml +++ b/src/App/DocumentPy.xml @@ -38,6 +38,24 @@ Restore the document from disk + + + Checks if the document is saved + + + + + Get the program version that a project file was created with + + + + + +For a regular document it returns its file name property. +For a temporary document it returns its transient directory. + + + Merges this document with another project file @@ -144,12 +162,42 @@ object of this document. Clear the undo stack of the document + + + Clear the whole document + + + + + Set a flag that allows or forbids to close a document + + + + + Check if the document can be closed. The default value is True + + recompute(objs=None): Recompute the document and returns the amount of recomputed features - + + + Check if any object must be recomputed + + + + + Purge the touched state of all objects + + + + + Check if any object is in touched state + + + Return the object with the given name diff --git a/src/App/DocumentPyImp.cpp b/src/App/DocumentPyImp.cpp index 18d1e1830a..0896d182b1 100644 --- a/src/App/DocumentPyImp.cpp +++ b/src/App/DocumentPyImp.cpp @@ -148,6 +148,30 @@ PyObject* DocumentPy::restore(PyObject * args) Py_Return; } +PyObject* DocumentPy::isSaved(PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return nullptr; + bool ok = getDocumentPtr()->isSaved(); + return Py::new_reference_to(Py::Boolean(ok)); +} + +PyObject* DocumentPy::getProgramVersion(PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return nullptr; + const char* version = getDocumentPtr()->getProgramVersion(); + return Py::new_reference_to(Py::String(version)); +} + +PyObject* DocumentPy::getFileName(PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return nullptr; + const char* fn = getDocumentPtr()->getFileName(); + return Py::new_reference_to(Py::String(fn)); +} + PyObject* DocumentPy::mergeProject(PyObject * args) { char* filename; @@ -446,14 +470,39 @@ PyObject* DocumentPy::redo(PyObject * args) Py_Return; } -PyObject* DocumentPy::clearUndos(PyObject * args) +PyObject* DocumentPy::clearUndos(PyObject * args) { - if (!PyArg_ParseTuple(args, "")) // convert args: Python->C - return NULL; // NULL triggers exception + if (!PyArg_ParseTuple(args, "")) + return nullptr; getDocumentPtr()->clearUndos(); Py_Return; } +PyObject* DocumentPy::clearDocument(PyObject * args) +{ + if (!PyArg_ParseTuple(args, "")) + return nullptr; + getDocumentPtr()->clearDocument(); + Py_Return; +} + +PyObject* DocumentPy::setClosable(PyObject* args) +{ + PyObject* close; + if (!PyArg_ParseTuple(args, "O!", &PyBool_Type, &close)) + return nullptr; + getDocumentPtr()->setClosable(PyObject_IsTrue(close) ? true : false); + Py_Return; +} + +PyObject* DocumentPy::isClosable(PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return nullptr; + bool ok = getDocumentPtr()->isClosable(); + return Py::new_reference_to(Py::Boolean(ok)); +} + PyObject* DocumentPy::recompute(PyObject * args) { PyObject *pyobjs = Py_None; @@ -497,6 +546,30 @@ PyObject* DocumentPy::recompute(PyObject * args) } PY_CATCH; } +PyObject* DocumentPy::mustExecute(PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return nullptr; + bool ok = getDocumentPtr()->mustExecute(); + return Py::new_reference_to(Py::Boolean(ok)); +} + +PyObject* DocumentPy::isTouched(PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return nullptr; + bool ok = getDocumentPtr()->isTouched(); + return Py::new_reference_to(Py::Boolean(ok)); +} + +PyObject* DocumentPy::purgeTouched(PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return nullptr; + getDocumentPtr()->purgeTouched(); + Py_Return; +} + PyObject* DocumentPy::getObject(PyObject *args) { long id = -1; From 501c3dc65795baedff5daa4660e5addce5e51a56 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 2 Dec 2021 17:24:18 +0100 Subject: [PATCH 114/133] PD: fix ProfileBased::getAxis Introduce an enum to verify the axis depending on the used context. * For helix no restriction is needed * For Pad/Pocket the axis must not be parallel with the sketch plane * For Revolve/Groove the axis must not be perpendicular with the sketch plane --- src/Mod/PartDesign/App/FeatureExtrude.cpp | 2 +- src/Mod/PartDesign/App/FeatureGroove.cpp | 2 +- src/Mod/PartDesign/App/FeatureHelix.cpp | 2 +- src/Mod/PartDesign/App/FeatureRevolution.cpp | 2 +- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 78 +++++++++++-------- src/Mod/PartDesign/App/FeatureSketchBased.h | 7 +- 6 files changed, 56 insertions(+), 37 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp index 54a3599328..765ea8ae69 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.cpp +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -95,7 +95,7 @@ Base::Vector3d FeatureExtrude::computeDirection(const Base::Vector3d& sketchVect const std::vector& subReferenceAxis = ReferenceAxis.getSubValues(); Base::Vector3d base; Base::Vector3d dir; - getAxis(pcReferenceAxis, subReferenceAxis, base, dir, false); + getAxis(pcReferenceAxis, subReferenceAxis, base, dir, ForbiddenAxis::NotPerpendicularWithNormal); switch (addSubType) { case Type::Additive: extrudeDirection = dir; diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp index 2b4ffc00ba..bb0822ef11 100644 --- a/src/Mod/PartDesign/App/FeatureGroove.cpp +++ b/src/Mod/PartDesign/App/FeatureGroove.cpp @@ -208,7 +208,7 @@ void Groove::updateAxis(void) const std::vector &subReferenceAxis = ReferenceAxis.getSubValues(); Base::Vector3d base; Base::Vector3d dir; - getAxis(pcReferenceAxis, subReferenceAxis, base, dir); + getAxis(pcReferenceAxis, subReferenceAxis, base, dir, ForbiddenAxis::NotParallelWithNormal); if (dir.Length() > Precision::Confusion()) { Base.setValue(base.x,base.y,base.z); diff --git a/src/Mod/PartDesign/App/FeatureHelix.cpp b/src/Mod/PartDesign/App/FeatureHelix.cpp index 1ab173895c..ce56c7fd45 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.cpp +++ b/src/Mod/PartDesign/App/FeatureHelix.cpp @@ -355,7 +355,7 @@ void Helix::updateAxis(void) const std::vector& subReferenceAxis = ReferenceAxis.getSubValues(); Base::Vector3d base; Base::Vector3d dir; - getAxis(pcReferenceAxis, subReferenceAxis, base, dir, false); + getAxis(pcReferenceAxis, subReferenceAxis, base, dir, ForbiddenAxis::NoCheck); Base.setValue(base.x, base.y, base.z); Axis.setValue(dir.x, dir.y, dir.z); diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index 419dc5b817..f5ec892e74 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -204,7 +204,7 @@ void Revolution::updateAxis(void) const std::vector &subReferenceAxis = ReferenceAxis.getSubValues(); Base::Vector3d base; Base::Vector3d dir; - getAxis(pcReferenceAxis, subReferenceAxis, base, dir); + getAxis(pcReferenceAxis, subReferenceAxis, base, dir, ForbiddenAxis::NotParallelWithNormal); Base.setValue(base.x,base.y,base.z); Axis.setValue(dir.x,dir.y,dir.z); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 9fd240f5e8..d3a215be10 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -1040,10 +1040,49 @@ double ProfileBased::getReversedAngle(const Base::Vector3d &b, const Base::Vecto } void ProfileBased::getAxis(const App::DocumentObject *pcReferenceAxis, const std::vector &subReferenceAxis, - Base::Vector3d& base, Base::Vector3d& dir, bool checkPerpendicular) + Base::Vector3d& base, Base::Vector3d& dir, ProfileBased::ForbiddenAxis checkAxis) { + auto verifyAxisFunc = [](ProfileBased::ForbiddenAxis checkAxis, const gp_Pln& sketchplane, const gp_Dir& dir) { + switch (checkAxis) { + case ForbiddenAxis::NotPerpendicularWithNormal: + // If perpendicular to the normal then it's parallel to the plane + if (sketchplane.Axis().Direction().IsNormal(dir, Precision::Angular())) + throw Base::ValueError("Axis must not be parallel to the sketch plane"); + break; + case ForbiddenAxis::NotParallelWithNormal: + // If parallel with the normal then it's perpendicular to the plane + if (sketchplane.Axis().Direction().IsParallel(dir, Precision::Angular())) + throw Base::ValueError("Axis must not be perpendicular to the sketch plane"); + break; + default: + break; + } + }; + + auto getAxisFromEdge = [](const TopoDS_Edge& refEdge, Base::Vector3d& base, Base::Vector3d& dir) { + if (refEdge.IsNull()) + throw Base::ValueError("Failed to extract rotation edge"); + BRepAdaptor_Curve adapt(refEdge); + gp_Pnt b; + gp_Dir d; + if (adapt.GetType() == GeomAbs_Line) { + b = adapt.Line().Location(); + d = adapt.Line().Direction(); + } + else if (adapt.GetType() == GeomAbs_Circle) { + b = adapt.Circle().Location(); + d = adapt.Circle().Axis().Direction(); + } + else { + throw Base::TypeError("Edge must be a straight line, circle or arc of circle"); + } + + base = Base::Vector3d(b.X(), b.Y(), b.Z()); + dir = Base::Vector3d(d.X(), d.Y(), d.Z()); + }; + dir = Base::Vector3d(0,0,0); // If unchanged signals that no valid axis was found - if (pcReferenceAxis == NULL) + if (!pcReferenceAxis) return; App::DocumentObject* profile = Profile.getValue(); @@ -1102,9 +1141,7 @@ void ProfileBased::getAxis(const App::DocumentObject *pcReferenceAxis, const std base = line->getBasePoint(); dir = line->getDirection(); - // Check that axis is perpendicular with sketch plane! - if (checkPerpendicular && sketchplane.Axis().Direction().IsParallel(gp_Dir(dir.x, dir.y, dir.z), Precision::Angular())) - throw Base::ValueError("Rotation axis must not be perpendicular with the sketch plane"); + verifyAxisFunc(checkAxis, sketchplane, gp_Dir(dir.x, dir.y, dir.z)); return; } @@ -1113,9 +1150,7 @@ void ProfileBased::getAxis(const App::DocumentObject *pcReferenceAxis, const std base = Base::Vector3d(0,0,0); line->Placement.getValue().multVec(Base::Vector3d (1,0,0), dir); - // Check that axis is perpendicular with sketch plane! - if (checkPerpendicular && sketchplane.Axis().Direction().IsParallel(gp_Dir(dir.x, dir.y, dir.z), Precision::Angular())) - throw Base::ValueError("Rotation axis must not be perpendicular with the sketch plane"); + verifyAxisFunc(checkAxis, sketchplane, gp_Dir(dir.x, dir.y, dir.z)); return; } @@ -1134,34 +1169,13 @@ void ProfileBased::getAxis(const App::DocumentObject *pcReferenceAxis, const std } if (ref.ShapeType() == TopAbs_EDGE) { - TopoDS_Edge refEdge = TopoDS::Edge(ref); - if (refEdge.IsNull()) - throw Base::ValueError("Failed to extract rotation edge"); - BRepAdaptor_Curve adapt(refEdge); - gp_Pnt b; - gp_Dir d; - if (adapt.GetType() == GeomAbs_Line) { - b = adapt.Line().Location(); - d = adapt.Line().Direction(); - } else if (adapt.GetType() == GeomAbs_Circle) { - b = adapt.Circle().Location(); - d = adapt.Circle().Axis().Direction(); - } else { - throw Base::TypeError("Rotation edge must be a straight line, circle or arc of circle"); - } - base = Base::Vector3d(b.X(), b.Y(), b.Z()); - dir = Base::Vector3d(d.X(), d.Y(), d.Z()); - // Check that axis is co-planar with sketch plane! - // Check that axis is perpendicular with sketch plane! - if (sketchplane.Axis().Direction().IsParallel(d, Precision::Angular())) - throw Base::ValueError("Rotation axis must not be perpendicular with the sketch plane"); + getAxisFromEdge(TopoDS::Edge(ref), base, dir); + verifyAxisFunc(checkAxis, sketchplane, gp_Dir(dir.x, dir.y, dir.z)); return; - } else { - throw Base::TypeError("Rotation reference must be an edge"); } } - throw Base::TypeError("Rotation axis reference is invalid"); + throw Base::TypeError("Unsupported geometry type to get reference axis"); } Base::Vector3d ProfileBased::getProfileNormal() const { diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index 52e1b12f17..3e3522e156 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -42,6 +42,11 @@ class PartDesignExport ProfileBased : public PartDesign::FeatureAddSub PROPERTY_HEADER(PartDesign::SketchBased); public: + enum class ForbiddenAxis { + NoCheck = 0, + NotPerpendicularWithNormal = 1, + NotParallelWithNormal = 2 + }; ProfileBased(); // Common properties for all sketch based features @@ -182,7 +187,7 @@ protected: double getReversedAngle(const Base::Vector3d& b, const Base::Vector3d& v); /// get Axis from ReferenceAxis void getAxis(const App::DocumentObject* pcReferenceAxis, const std::vector& subReferenceAxis, - Base::Vector3d& base, Base::Vector3d& dir, bool checkPerpendicular=true); + Base::Vector3d& base, Base::Vector3d& dir, ForbiddenAxis checkAxis); void onChanged(const App::Property* prop); private: From 0042f58e4c874cf4aec397b49a8175f8948ca77e Mon Sep 17 00:00:00 2001 From: luz paz Date: Thu, 2 Dec 2021 16:18:04 -0500 Subject: [PATCH 115/133] Make source code comments use gender neutral pronouns The changes also include some grammatical fixes as well. --- src/App/Application.h | 12 ++++++------ src/App/Document.h | 2 +- src/Base/PyExport.h | 2 +- src/Gui/CornerCrossLetters.h | 2 +- src/Gui/DlgMacroExecuteImp.cpp | 4 ++-- src/Gui/TextEdit.h | 2 +- src/Gui/ViewProviderGroupExtension.cpp | 2 +- src/Gui/ViewProviderLink.cpp | 2 +- src/Gui/Workbench.cpp | 6 +++--- src/Mod/Assembly/App/opendcm/core/property.hpp | 4 ++-- src/Mod/Fem/Gui/TaskPostBoxes.cpp | 2 +- src/Mod/Fem/femmesh/gmshtools.py | 2 +- src/Mod/Fem/femmesh/meshtools.py | 2 +- src/Mod/Fem/femsolver/calculix/writer.py | 2 +- src/Mod/Fem/femtest/data/calculix/box_frequency.inp | 2 +- src/Mod/Fem/femtest/data/calculix/box_static.inp | 2 +- .../data/calculix/ccx_buckling_flexuralbuckling.inp | 2 +- .../data/calculix/ccx_cantilever_beam_circle.inp | 2 +- .../data/calculix/ccx_cantilever_beam_pipe.inp | 2 +- .../data/calculix/ccx_cantilever_beam_rect.inp | 2 +- .../data/calculix/ccx_cantilever_ele_hexa20.inp | 2 +- .../data/calculix/ccx_cantilever_ele_quad4.inp | 2 +- .../data/calculix/ccx_cantilever_ele_quad8.inp | 2 +- .../data/calculix/ccx_cantilever_ele_seg2.inp | 2 +- .../data/calculix/ccx_cantilever_ele_seg3.inp | 2 +- .../data/calculix/ccx_cantilever_ele_tria3.inp | 2 +- .../data/calculix/ccx_cantilever_ele_tria6.inp | 2 +- .../data/calculix/ccx_cantilever_faceload.inp | 2 +- .../data/calculix/ccx_cantilever_nodeload.inp | 2 +- .../ccx_cantilever_prescribeddisplacement.inp | 2 +- .../Fem/femtest/data/calculix/constraint_centrif.inp | 2 +- .../data/calculix/constraint_contact_shell_shell.inp | 2 +- .../data/calculix/constraint_contact_solid_solid.inp | 2 +- .../data/calculix/constraint_sectionprint.inp | 2 +- .../calculix/constraint_selfweight_cantilever.inp | 2 +- src/Mod/Fem/femtest/data/calculix/constraint_tie.inp | 2 +- .../calculix/constraint_transform_beam_hinged.inp | 2 +- .../data/calculix/constraint_transform_torque.inp | 2 +- .../femtest/data/calculix/frequency_beamsimple.inp | 2 +- .../material_multiple_bendingbeam_fiveboxes.inp | 2 +- .../material_multiple_bendingbeam_fivefaces.inp | 2 +- .../material_multiple_tensionrod_twoboxes.inp | 2 +- .../Fem/femtest/data/calculix/material_nonlinear.inp | 2 +- .../calculix/square_pipe_end_twisted_edgeforces.inp | 2 +- .../calculix/square_pipe_end_twisted_nodeforces.inp | 2 +- .../femtest/data/calculix/thermomech_bimetall.inp | 2 +- .../Fem/femtest/data/calculix/thermomech_flow1D.inp | 2 +- .../Fem/femtest/data/calculix/thermomech_spine.inp | 2 +- src/Mod/Fem/femtools/checksanalysis.py | 2 +- src/Mod/Mesh/App/Core/SetOperations.h | 2 +- src/Mod/PartDesign/Gui/Command.cpp | 4 ++-- src/Mod/PartDesign/Gui/CommandBody.cpp | 2 +- src/Mod/PartDesign/Gui/TaskHelixParameters.cpp | 2 +- src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp | 8 ++++---- src/Mod/PartDesign/Gui/TaskShapeBinder.cpp | 8 ++++---- src/Mod/Sketcher/App/Sketch.cpp | 2 +- src/Mod/Sketcher/Gui/CommandSketcherTools.cpp | 2 +- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 2 +- src/WindowsInstaller/include/init.nsh | 6 +++--- 59 files changed, 77 insertions(+), 77 deletions(-) diff --git a/src/App/Application.h b/src/App/Application.h index e11b3b1d6f..84ddbb64ec 100644 --- a/src/App/Application.h +++ b/src/App/Application.h @@ -330,13 +330,13 @@ public: //@} /** @name methods for the open handler - * With this facility a Application module can register - * a ending (filetype) which he can handle to open. + * With this facility an Application module can register + * an ending (filetype) which it can handle to open. * The ending and the module name are stored and if the file - * type is opened the module get loaded and need to register a + * type is opened the module gets loaded and needs to register an * OpenHandler class in the OpenHandlerFactorySingleton. - * After the module is loaded a OpenHandler of this type is created - * and the file get loaded. + * After the module is loaded, an OpenHandler of this type is created + * and the file gets loaded. * @see OpenHandler * @see OpenHandlerFactorySingleton */ @@ -446,7 +446,7 @@ protected: void renameDocument(const char *OldName, const char *NewName); /** @name I/O of the document - * This slot get connected to all App::Documents created + * This slot gets connected to all App::Documents created */ //@{ void slotBeforeChangeDocument(const App::Document&, const App::Property&); diff --git a/src/App/Document.h b/src/App/Document.h index 6d0e7c5ec2..9ca8bc97e8 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -367,7 +367,7 @@ public: * When undo, Gui component can query getAvailableUndo(id) to see if it is * possible to undo with a given ID. If there more than one undo * transactions, meaning that there are other transactions before the given - * ID. The Gui component shall ask user if he wants to undo multiple steps. + * ID. The Gui component shall ask user if they want to undo multiple steps. * And if the user agrees, call undo(id) to unroll all transaction before * and including the the one with the give ID. Same applies for redo. * diff --git a/src/Base/PyExport.h b/src/Base/PyExport.h index 530250c0f9..e6bd78e800 100644 --- a/src/Base/PyExport.h +++ b/src/Base/PyExport.h @@ -79,7 +79,7 @@ class PyObjectBase; * @remark One big consequence of this specification is that the programmer must know whether the Python interpreter * gets the Python object or not. If the interpreter gets the object then it decrements the counter later on when * the internal variable is freed. In case the interpreter doesn't get this object then the programmer must do the - * decrement on his own. + * decrement on their own. * * @note To not to undermine this specification the programmer must make sure to get the Python object always via * GetPyObject(). diff --git a/src/Gui/CornerCrossLetters.h b/src/Gui/CornerCrossLetters.h index aec6e95048..16b251e3d7 100644 --- a/src/Gui/CornerCrossLetters.h +++ b/src/Gui/CornerCrossLetters.h @@ -10,7 +10,7 @@ namespace Gui { // 21x27 is 3x a standard 5x7 representation with 1px margin // This allows good anti-aliasing aspect at any usable size // It is generated with Gimp using Bitstream Charter Bold font, 28 px, on transparent background -// It is then directy exported as C source type after image is vertically flipped for direct GL usage +// It is then directly exported as C source type after image is vertically flipped for direct GL usage // With enabled options "Use macros instead of struct" and "Save alpha channel" #define XPM_WIDTH (21) diff --git a/src/Gui/DlgMacroExecuteImp.cpp b/src/Gui/DlgMacroExecuteImp.cpp index 952d56f902..9233326010 100644 --- a/src/Gui/DlgMacroExecuteImp.cpp +++ b/src/Gui/DlgMacroExecuteImp.cpp @@ -536,7 +536,7 @@ Note: your changes will be applied when you next switch workbenches\n")); Base::Console().Warning("Toolbar walkthrough: Unable to find actionMacros combo box\n"); } else { int macroIndex = macroListBox->findText(fn); //fn is the macro filename - macroListBox->setCurrentIndex(macroIndex); //select it for the user so he doesn't have to + macroListBox->setCurrentIndex(macroIndex); //select it for the user so they don't have to } QLineEdit* menuText = setupCustomMacrosPage->findChild(QString::fromLatin1("actionMenu")); @@ -580,7 +580,7 @@ Note: your changes will be applied when you next switch workbenches\n")); moveActionRightButton->setStyleSheet(QString::fromLatin1("background-color: red")); } /** tailor instructions depending on whether user already has custom toolbar created - * if not he needs to click New button to create one first + * if not, they need to click New button to create one first **/ QString instructions2 = tr("Walkthrough instructions: Click right arrow button (->), then Close."); diff --git a/src/Gui/TextEdit.h b/src/Gui/TextEdit.h index ad7bded512..4a20c450c0 100644 --- a/src/Gui/TextEdit.h +++ b/src/Gui/TextEdit.h @@ -137,7 +137,7 @@ private: /** * The CompletionList class provides a list box that pops up in a text edit if the user has pressed - * an accelerator to complete the current word he is typing in. + * an accelerator to complete the current word they are typing in. * @author Werner Mayer */ class CompletionList : public QListWidget diff --git a/src/Gui/ViewProviderGroupExtension.cpp b/src/Gui/ViewProviderGroupExtension.cpp index fd251d108f..5d2ff145a5 100644 --- a/src/Gui/ViewProviderGroupExtension.cpp +++ b/src/Gui/ViewProviderGroupExtension.cpp @@ -163,7 +163,7 @@ void ViewProviderGroupExtension::extensionHide(void) { bool ViewProviderGroupExtension::extensionOnDelete(const std::vector< std::string >& ) { auto* group = getExtendedViewProvider()->getObject()->getExtensionByType(); - // If the group is nonempty ask the user if he wants to delete its content + // If the group is nonempty ask the user if they want to delete its content if (group->Group.getSize() > 0) { QMessageBox::StandardButton choice = QMessageBox::question(getMainWindow(), QObject::tr ( "Delete group content?" ), diff --git a/src/Gui/ViewProviderLink.cpp b/src/Gui/ViewProviderLink.cpp index 2ebc20ec6d..4a2701c538 100644 --- a/src/Gui/ViewProviderLink.cpp +++ b/src/Gui/ViewProviderLink.cpp @@ -2506,7 +2506,7 @@ ViewProvider *ViewProviderLink::startEditing(int mode) { } // TODO: the 0x8000 mask here is for caller to disambiguate the intention - // here, whether he wants to, say transform the link itself or the linked + // here, whether they want to, say transform the link itself or the linked // object. Use of a mask here will allow forwarding those editing modes that // are supported by both the link and the linked object, such as transform // and set color. We need to find a better place to declare this constant. diff --git a/src/Gui/Workbench.cpp b/src/Gui/Workbench.cpp index 58c68ed01d..4abc96ada3 100644 --- a/src/Gui/Workbench.cpp +++ b/src/Gui/Workbench.cpp @@ -56,7 +56,7 @@ using namespace Gui; FreeCAD provides the possibility to have one or more workbenches for a module. A workbench changes the appearance of the main window in that way that it defines toolbars, items in the toolbox, menus or the context menu and dockable windows that are shown to the user. - The idea behind this concept is that the user should see only the functions that are required for the task that he is doing at this moment and not to show dozens of unneeded functions which the user never uses. + The idea behind this concept is that the user should see only the functions that are required for the task that they are doing at this moment and not to show dozens of unneeded functions which the user never uses. \section stepbystep Step by step Here follows a short description of how your own workbench can be added to a module. @@ -181,8 +181,8 @@ using namespace Gui; * At startup FreeCAD scans all module directories and invokes InitGui.py. So an item for a workbench gets created. If the user * clicks on such an item the matching module gets loaded, the C++ workbench gets registered and activated. * - * The user is able to modify a workbench (Edit|Customize). E.g. he can add new toolbars or items for the toolbox and add his preferred - * functions to them. But he has only full control over "his" toolbars, the default workbench items cannot be modified or even removed. + * The user is able to modify a workbench (Edit|Customize). E.g. they can add new toolbars or items for the toolbox and add their preferred + * functions to them. But the user only has full control over "their" own toolbars, the default workbench items cannot be modified or even removed. * * FreeCAD provides also the possibility to define pure Python workbenches. Such workbenches are temporarily only and are lost after exiting * the FreeCAD session. But if you want to keep your Python workbench you can write a macro and attach it with a user defined button or just diff --git a/src/Mod/Assembly/App/opendcm/core/property.hpp b/src/Mod/Assembly/App/opendcm/core/property.hpp index 62dafc99a1..6b67eb04f2 100644 --- a/src/Mod/Assembly/App/opendcm/core/property.hpp +++ b/src/Mod/Assembly/App/opendcm/core/property.hpp @@ -302,7 +302,7 @@ struct pts { //property type sequence /** * @brief Type traits to detect if the property has a default value * - * If the user want to provide a default value for a property than he adds a default_value static function. + * If the user wants to provide a default value for a property than they add a default_value static function. * To check if the this function is available we add a type traits which searches for this special function. */ BOOST_MPL_HAS_XXX_TRAIT_DEF(default_value) @@ -312,7 +312,7 @@ BOOST_MPL_HAS_XXX_TRAIT_DEF(default_value) /** * @brief Functor to assign default values to property * - * This functor holds a pointer to the PropertyOwner in question. The operator() get the properties which + * This functor holds a pointer to the PropertyOwner in question. The operator() gets the properties which * hold a default value and assigns this value to the property the owner holds. */ template diff --git a/src/Mod/Fem/Gui/TaskPostBoxes.cpp b/src/Mod/Fem/Gui/TaskPostBoxes.cpp index 641ea09da7..f8c173ae5f 100644 --- a/src/Mod/Fem/Gui/TaskPostBoxes.cpp +++ b/src/Mod/Fem/Gui/TaskPostBoxes.cpp @@ -1138,7 +1138,7 @@ void TaskPostWarpVector::on_Max_valueChanged(double) { /* * problem, if warp_factor is 2000 one would like to input 4000 as max, one starts to input 4 - * immediately the warp_factor is changed to 4 because 4 < 2000, but one has just input one character of his 4000 + * immediately the warp_factor is changed to 4 because 4 < 2000, but one has just input one character of their 4000 * I do not know how to solve this, but the code to set slider and spinbox is fine thus I leave it ... * * mhh it works if "apply changes to pipeline directly" button is deactivated, still it really confuses if diff --git a/src/Mod/Fem/femmesh/gmshtools.py b/src/Mod/Fem/femmesh/gmshtools.py index f51b3092f8..fad41d007a 100644 --- a/src/Mod/Fem/femmesh/gmshtools.py +++ b/src/Mod/Fem/femmesh/gmshtools.py @@ -1011,7 +1011,7 @@ for len in max_mesh_sizes: """ TODO class GmshTools should be splittet in two classes -one class should only collect the mesh parameter from mesh object and his childs +one class should only collect the mesh parameter from mesh object and its childs a second class only uses the collected parameter, writes the input file runs gmsh reads back the unv and returns a FemMesh gmsh binary will be collected in the second class diff --git a/src/Mod/Fem/femmesh/meshtools.py b/src/Mod/Fem/femmesh/meshtools.py index 3f04ec7c0c..3cf89b77c0 100644 --- a/src/Mod/Fem/femmesh/meshtools.py +++ b/src/Mod/Fem/femmesh/meshtools.py @@ -1015,7 +1015,7 @@ def get_ref_edgenodes_table( nodecount += 1 if nodecount > 1: refedge_fem_faceelements.append(elem) - # for every refedge_fem_faceelement look which of his nodes is in + # for every refedge_fem_faceelement look which of its nodes is in # refedge_nodes --> add all these nodes to edge_table for elem in refedge_fem_faceelements: fe_refedge_nodes = [] diff --git a/src/Mod/Fem/femsolver/calculix/writer.py b/src/Mod/Fem/femsolver/calculix/writer.py index 89d560306a..08d37d4cf8 100644 --- a/src/Mod/Fem/femsolver/calculix/writer.py +++ b/src/Mod/Fem/femsolver/calculix/writer.py @@ -70,7 +70,7 @@ from femtools import constants units_information = """*********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/box_frequency.inp b/src/Mod/Fem/femtest/data/calculix/box_frequency.inp index 00c7073376..c6f624721c 100644 --- a/src/Mod/Fem/femtest/data/calculix/box_frequency.inp +++ b/src/Mod/Fem/femtest/data/calculix/box_frequency.inp @@ -471,7 +471,7 @@ S, E *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/box_static.inp b/src/Mod/Fem/femtest/data/calculix/box_static.inp index 195a5630cd..f5ad252b4c 100644 --- a/src/Mod/Fem/femtest/data/calculix/box_static.inp +++ b/src/Mod/Fem/femtest/data/calculix/box_static.inp @@ -599,7 +599,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_buckling_flexuralbuckling.inp b/src/Mod/Fem/femtest/data/calculix/ccx_buckling_flexuralbuckling.inp index 22f722e722..10c99f02ab 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_buckling_flexuralbuckling.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_buckling_flexuralbuckling.inp @@ -818,7 +818,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_circle.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_circle.inp index 9c70c8229e..683406edf8 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_circle.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_circle.inp @@ -113,7 +113,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_pipe.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_pipe.inp index 4f9f744756..7b88d0cd62 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_pipe.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_pipe.inp @@ -113,7 +113,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_rect.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_rect.inp index 65338dbab6..edb546f88c 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_rect.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_rect.inp @@ -113,7 +113,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_hexa20.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_hexa20.inp index e7d58efd79..8196de6c7e 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_hexa20.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_hexa20.inp @@ -453,7 +453,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad4.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad4.inp index 3105e03a28..aa88c6e3a1 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad4.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad4.inp @@ -139,7 +139,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad8.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad8.inp index 6e27d94ff0..01817ff723 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad8.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad8.inp @@ -129,7 +129,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg2.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg2.inp index 2d5115f6f4..08e6809a2a 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg2.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg2.inp @@ -255,7 +255,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg3.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg3.inp index 8884cec1f4..c9d196b933 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg3.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg3.inp @@ -113,7 +113,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria3.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria3.inp index 7a99b20451..22b20b22a7 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria3.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria3.inp @@ -1620,7 +1620,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria6.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria6.inp index 31a6b19e5c..1cac5e0ac2 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria6.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria6.inp @@ -347,7 +347,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_faceload.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_faceload.inp index 815e66a119..8f13ca6fac 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_faceload.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_faceload.inp @@ -419,7 +419,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_nodeload.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_nodeload.inp index 964b40f707..bd7dbec4cd 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_nodeload.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_nodeload.inp @@ -416,7 +416,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_prescribeddisplacement.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_prescribeddisplacement.inp index c3d571db8c..9d9d464b72 100644 --- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_prescribeddisplacement.inp +++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_prescribeddisplacement.inp @@ -426,7 +426,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_centrif.inp b/src/Mod/Fem/femtest/data/calculix/constraint_centrif.inp index 47a3e0b109..a2faa25ee5 100644 --- a/src/Mod/Fem/femtest/data/calculix/constraint_centrif.inp +++ b/src/Mod/Fem/femtest/data/calculix/constraint_centrif.inp @@ -18792,7 +18792,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_contact_shell_shell.inp b/src/Mod/Fem/femtest/data/calculix/constraint_contact_shell_shell.inp index 963dec0633..9e75a79e40 100644 --- a/src/Mod/Fem/femtest/data/calculix/constraint_contact_shell_shell.inp +++ b/src/Mod/Fem/femtest/data/calculix/constraint_contact_shell_shell.inp @@ -38424,7 +38424,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_contact_solid_solid.inp b/src/Mod/Fem/femtest/data/calculix/constraint_contact_solid_solid.inp index 71d055cc73..61e7a9a212 100644 --- a/src/Mod/Fem/femtest/data/calculix/constraint_contact_solid_solid.inp +++ b/src/Mod/Fem/femtest/data/calculix/constraint_contact_solid_solid.inp @@ -5356,7 +5356,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_sectionprint.inp b/src/Mod/Fem/femtest/data/calculix/constraint_sectionprint.inp index 2eea3f4a01..253c38210c 100644 --- a/src/Mod/Fem/femtest/data/calculix/constraint_sectionprint.inp +++ b/src/Mod/Fem/femtest/data/calculix/constraint_sectionprint.inp @@ -3470,7 +3470,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_selfweight_cantilever.inp b/src/Mod/Fem/femtest/data/calculix/constraint_selfweight_cantilever.inp index 613c03c7fc..4fda9cf903 100644 --- a/src/Mod/Fem/femtest/data/calculix/constraint_selfweight_cantilever.inp +++ b/src/Mod/Fem/femtest/data/calculix/constraint_selfweight_cantilever.inp @@ -2199,7 +2199,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_tie.inp b/src/Mod/Fem/femtest/data/calculix/constraint_tie.inp index ac07fd6743..ea73b8caa3 100644 --- a/src/Mod/Fem/femtest/data/calculix/constraint_tie.inp +++ b/src/Mod/Fem/femtest/data/calculix/constraint_tie.inp @@ -18662,7 +18662,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_transform_beam_hinged.inp b/src/Mod/Fem/femtest/data/calculix/constraint_transform_beam_hinged.inp index 433461358a..92bd75d962 100644 --- a/src/Mod/Fem/femtest/data/calculix/constraint_transform_beam_hinged.inp +++ b/src/Mod/Fem/femtest/data/calculix/constraint_transform_beam_hinged.inp @@ -3800,7 +3800,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_transform_torque.inp b/src/Mod/Fem/femtest/data/calculix/constraint_transform_torque.inp index 4e0ba5f9b6..8f95976602 100644 --- a/src/Mod/Fem/femtest/data/calculix/constraint_transform_torque.inp +++ b/src/Mod/Fem/femtest/data/calculix/constraint_transform_torque.inp @@ -13173,7 +13173,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/frequency_beamsimple.inp b/src/Mod/Fem/femtest/data/calculix/frequency_beamsimple.inp index 3203aa1474..b0a20a53a7 100644 --- a/src/Mod/Fem/femtest/data/calculix/frequency_beamsimple.inp +++ b/src/Mod/Fem/femtest/data/calculix/frequency_beamsimple.inp @@ -17084,7 +17084,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fiveboxes.inp b/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fiveboxes.inp index 53ba2564cb..c324cb241d 100644 --- a/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fiveboxes.inp +++ b/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fiveboxes.inp @@ -29200,7 +29200,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fivefaces.inp b/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fivefaces.inp index 4976a607f9..2f4da096c8 100644 --- a/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fivefaces.inp +++ b/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fivefaces.inp @@ -2711,7 +2711,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/material_multiple_tensionrod_twoboxes.inp b/src/Mod/Fem/femtest/data/calculix/material_multiple_tensionrod_twoboxes.inp index 6ba8538f1c..ab2d0d6c2a 100644 --- a/src/Mod/Fem/femtest/data/calculix/material_multiple_tensionrod_twoboxes.inp +++ b/src/Mod/Fem/femtest/data/calculix/material_multiple_tensionrod_twoboxes.inp @@ -1292,7 +1292,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/material_nonlinear.inp b/src/Mod/Fem/femtest/data/calculix/material_nonlinear.inp index a2d2f5190d..4e1e0c5b30 100644 --- a/src/Mod/Fem/femtest/data/calculix/material_nonlinear.inp +++ b/src/Mod/Fem/femtest/data/calculix/material_nonlinear.inp @@ -20129,7 +20129,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_edgeforces.inp b/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_edgeforces.inp index 22fef3842b..c16882fd25 100644 --- a/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_edgeforces.inp +++ b/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_edgeforces.inp @@ -2674,7 +2674,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_nodeforces.inp b/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_nodeforces.inp index 099ef3bea0..e439f04309 100644 --- a/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_nodeforces.inp +++ b/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_nodeforces.inp @@ -2786,7 +2786,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/thermomech_bimetall.inp b/src/Mod/Fem/femtest/data/calculix/thermomech_bimetall.inp index 5d20a88b1d..dd1f031e31 100644 --- a/src/Mod/Fem/femtest/data/calculix/thermomech_bimetall.inp +++ b/src/Mod/Fem/femtest/data/calculix/thermomech_bimetall.inp @@ -8258,7 +8258,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/thermomech_flow1D.inp b/src/Mod/Fem/femtest/data/calculix/thermomech_flow1D.inp index 22a885456a..d8b7b7b0e2 100644 --- a/src/Mod/Fem/femtest/data/calculix/thermomech_flow1D.inp +++ b/src/Mod/Fem/femtest/data/calculix/thermomech_flow1D.inp @@ -168,7 +168,7 @@ MF, PS *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtest/data/calculix/thermomech_spine.inp b/src/Mod/Fem/femtest/data/calculix/thermomech_spine.inp index 290687e1c6..7cc0b503a3 100644 --- a/src/Mod/Fem/femtest/data/calculix/thermomech_spine.inp +++ b/src/Mod/Fem/femtest/data/calculix/thermomech_spine.inp @@ -205,7 +205,7 @@ RF *********************************************************** ** About units: ** See ccx manual, ccx does not know about any unit. -** Golden rule: The user must make sure that the numbers he provides have consistent units. +** Golden rule: The user must make sure that the numbers they provide have consistent units. ** The user is the FreeCAD calculix writer module ;-) ** ** The unit system which is used at Guido Dhondt's company: mm, N, s, K diff --git a/src/Mod/Fem/femtools/checksanalysis.py b/src/Mod/Fem/femtools/checksanalysis.py index b16412e450..50624ed13b 100644 --- a/src/Mod/Fem/femtools/checksanalysis.py +++ b/src/Mod/Fem/femtools/checksanalysis.py @@ -344,7 +344,7 @@ def check_member_for_solver_calculix(analysis, solver, mesh, member): ): message += ( "Mesh without geometry link. " - "The mesh needs to know his geometry for the beam rotations.\n" + "The mesh needs to know its geometry for the beam rotations.\n" ) if len(member.geos_beamrotation) > 1: message += ( diff --git a/src/Mod/Mesh/App/Core/SetOperations.h b/src/Mod/Mesh/App/Core/SetOperations.h index d83cc4f362..d2943bf994 100644 --- a/src/Mod/Mesh/App/Core/SetOperations.h +++ b/src/Mod/Mesh/App/Core/SetOperations.h @@ -76,7 +76,7 @@ protected: float _minDistanceToPoint; /** Minimal distance to facet corner points */ private: - // Helper class cutting edge to his two attached facets + // Helper class cutting edge to its two attached facets class Edge { public: diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index cfc3a655dc..1e0271e234 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -1183,8 +1183,8 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons // a Part container and if not an error was raised and the function aborted. // First of all, for the user this wasn't obvious because the error message // was quite confusing (and thus the user may have done the wrong thing since - // he may have assumed the that the sketch was meant) and second there is no need - // that the body must be inside a Part container. + // they may have assumed the that the sketch was meant) and + // Second, there is no need that the body must be inside a Part container. // For more details see: https://forum.freecadweb.org/viewtopic.php?f=19&t=32164 // The function has been modified not to expect the body to be in the Part // and it now directly invokes the 'makeCopy' dialog. diff --git a/src/Mod/PartDesign/Gui/CommandBody.cpp b/src/Mod/PartDesign/Gui/CommandBody.cpp index a73bd62630..d3c9f45c26 100644 --- a/src/Mod/PartDesign/Gui/CommandBody.cpp +++ b/src/Mod/PartDesign/Gui/CommandBody.cpp @@ -941,7 +941,7 @@ void CmdPartDesignMoveFeatureInTree::activated(int iMsg) } // If the selected objects have been moved after the current tip then ask the - // user if he wants the last object to be the new tip. + // user if they want the last object to be the new tip. // Only do this for features that can hold a tip (not for e.g. datums) if ( lastObject && body->Tip.getValue() == target && lastObject->isDerivedFrom(PartDesign::Feature::getClassTypeId()) ) { diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp index 9452720094..8ede0b0d9e 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp @@ -436,7 +436,7 @@ void TaskHelixParameters::onAxisChanged(int num) } propReferenceAxis->Paste(lnk); - // in case user is in selection mode, but changed his mind before selecting anything. + // in case user is in selection mode, but changed their mind before selecting anything. exitSelectionMode(); } diff --git a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp index 64f0ac1b58..9a31600a18 100644 --- a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp @@ -398,7 +398,7 @@ void TaskBoxPrimitives::onCylinderRadiusChanged(double v) { void TaskBoxPrimitives::onCylinderXSkewChanged(double v) { PartDesign::Cylinder* cyl = static_cast(vp->getObject()); // we must assure that if the user incremented from e.g. 85 degree with the - // spin buttons he does not end at 90.0 but 89.9999 which is shown rounded to 90 degree + // spin buttons, they do not end at 90.0 but at 89.9999 which is shown rounded to 90 degree if ((v < 90.0) && (v > -90.0)) { cyl->FirstAngle.setValue(v); } @@ -415,7 +415,7 @@ void TaskBoxPrimitives::onCylinderXSkewChanged(double v) { void TaskBoxPrimitives::onCylinderYSkewChanged(double v) { PartDesign::Cylinder* cyl = static_cast(vp->getObject()); // we must assure that if the user incremented from e.g. 85 degree with the - // spin buttons he does not end at 90.0 but 89.9999 which is shown rounded to 90 degree + // spin buttons, they do not end at 90.0 but at 89.9999 which is shown rounded to 90 degree if ((v < 90.0) && (v > -90.0)) { cyl->SecondAngle.setValue(v); } @@ -572,7 +572,7 @@ void TaskBoxPrimitives::onPrismHeightChanged(double v) { void TaskBoxPrimitives::onPrismXSkewChanged(double v) { PartDesign::Prism* sph = static_cast(vp->getObject()); // we must assure that if the user incremented from e.g. 85 degree with the - // spin buttons he does not end at 90.0 but 89.9999 which is shown rounded to 90 degree + // spin buttons, they do not end at 90.0 but at 89.9999 which is shown rounded to 90 degree if ((v < 90.0) && (v > -90.0)) { sph->FirstAngle.setValue(v); } @@ -589,7 +589,7 @@ void TaskBoxPrimitives::onPrismXSkewChanged(double v) { void TaskBoxPrimitives::onPrismYSkewChanged(double v) { PartDesign::Prism* sph = static_cast(vp->getObject()); // we must assure that if the user incremented from e.g. 85 degree with the - // spin buttons he does not end at 90.0 but 89.9999 which is shown rounded to 90 degree + // spin buttons, they do not end at 90.0 but at 89.9999 which is shown rounded to 90 degree if ((v < 90.0) && (v > -90.0)) { sph->SecondAngle.setValue(v); } diff --git a/src/Mod/PartDesign/Gui/TaskShapeBinder.cpp b/src/Mod/PartDesign/Gui/TaskShapeBinder.cpp index ff869fdba5..bd6bf4cba0 100644 --- a/src/Mod/PartDesign/Gui/TaskShapeBinder.cpp +++ b/src/Mod/PartDesign/Gui/TaskShapeBinder.cpp @@ -91,8 +91,8 @@ TaskShapeBinder::TaskShapeBinder(ViewProviderShapeBinder *view, bool /*newObj*/, for (auto sub : subs) ui->listWidgetReferences->addItem(QString::fromStdString(sub)); - //make sure th euser sees al important things: the base feature to select edges and the - //spine/auxiliary spine he already selected + //make sure the user sees all important things: the base feature to select edges and the + //spine/auxiliary spine they already selected if(obj) { auto* svp = doc->getViewProvider(obj); if(svp) { @@ -148,8 +148,8 @@ TaskShapeBinder::~TaskShapeBinder() PartDesign::Pipe* pipe = static_cast(vp->getObject()); Gui::Document* doc = Gui::Application::Instance->activeDocument(); - //make sure th euser sees al important things: the base feature to select edges and the - //spine/auxiliary spine he already selected + //make sure the user sees all important things: the base feature to select edges and the + //spine/auxiliary spine they already selected if(pipe->BaseFeature.getValue()) doc->getViewProvider(pipe->BaseFeature.getValue())->hide(); if(pipe->Spine.getValue()) { diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index e1880af526..22f3858ba8 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -265,7 +265,7 @@ int Sketch::setUpSketch(const std::vector &GeoList, while(unsatisfied_groups) { // We tried hard not to arrive to an unsatisfied group, so we try harder // This loop has the advantage that the user will notice increased effort to solve, - // so may understand he is abusing the block constraint, while guaranteing that wrong + // so they may understand that they are abusing the block constraint, while guaranteeing that wrong // behaviour of the block constraint is not undetected. // Another QR iteration diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index f9e6aadfa1..939dcb2b04 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -1538,7 +1538,7 @@ void SketcherCopy::activate(SketcherCopy::Op op) } } - // Ask the user if he wants to clone or to simple copy + // Ask the user if they want to clone or to simple copy /* int ret = QMessageBox::question(Gui::getMainWindow(), QObject::tr("Dimensional/Geometric constraints"), QObject::tr("Do you want to clone the object, i.e. substitute dimensional constraints by geometric constraints?"), diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 1ec7513d1e..0dfef57c23 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -3931,7 +3931,7 @@ void ViewProviderSketch::initItemsSizes() // // Rationale: // -> Other WBs use the default value as is - // -> If a user has a HDPI, he will eventually change the value for the other WBs + // -> If a user has a HDPI, they will eventually change the value for the other WBs // -> If we correct the value here in addition, we would get two times a resize edit->MarkerSize = markersize; } diff --git a/src/WindowsInstaller/include/init.nsh b/src/WindowsInstaller/include/init.nsh index af385577cd..f11153ef46 100644 --- a/src/WindowsInstaller/include/init.nsh +++ b/src/WindowsInstaller/include/init.nsh @@ -89,8 +89,8 @@ Function .onInit ${endif} ${if} $0 != "" # check if the uninstaller was acidentally deleted - # if so don't bother the user if he really wants to install a new FreeCAD over an existing one - # because he won't have a chance to deny this + # if so, don't bother the user if they really want to install a new FreeCAD over an existing one + # because they won't have a chance to deny this StrCpy $4 $0 -16 # remove '\bin\FreeCAD.exe' # (for FileCheck the variables $0 and $1 cannot be used) !insertmacro FileCheck $5 "Uninstall-${APP_NAME}.exe" "$4" # macro from Utils.nsh @@ -98,7 +98,7 @@ Function .onInit Goto ForceInstallation ${endif} # installing over an existing installation of the same FreeCAD release is not necessary - # if the users does this he most probably has a problem with FreeCAD that can better be solved + # if the users does this, they most probably have a problem with FreeCAD that can better be solved # by reinstalling FreeCAD # for beta and other test releases over-installing can even cause errors MessageBox MB_YESNO|MB_DEFBUTTON2|MB_ICONEXCLAMATION "$(AlreadyInstalled)" /SD IDNO IDYES ForceInstallation From 269681d83cf835b042cf8e588e893c0144032e5b Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 3 Dec 2021 00:01:49 +0100 Subject: [PATCH 116/133] PD: use button group to make mid-plane and reversed option mutual exclusive --- src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp index 2d66e23cec..fc47b0e8aa 100644 --- a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp @@ -36,6 +36,7 @@ #include #include #include "ReferenceSelection.h" +#include using namespace PartDesignGui; using namespace Gui; @@ -52,6 +53,11 @@ TaskExtrudeParameters::TaskExtrudeParameters(ViewProviderSketchBased *SketchBase ui->setupUi(proxy); ui->lineFaceName->setPlaceholderText(tr("No face selected")); + Gui::ButtonGroup* group = new Gui::ButtonGroup(this); + group->addButton(ui->checkBoxMidplane); + group->addButton(ui->checkBoxReversed); + group->setExclusive(true); + this->groupLayout()->addWidget(proxy); } @@ -516,8 +522,6 @@ void TaskExtrudeParameters::onMidplaneChanged(bool on) { PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); extrude->Midplane.setValue(on); - // reversed is not sensible when midplane - ui->checkBoxReversed->setEnabled(!on); tryRecomputeFeature(); } @@ -525,8 +529,6 @@ void TaskExtrudeParameters::onReversedChanged(bool on) { PartDesign::FeatureExtrude* extrude = static_cast(vp->getObject()); extrude->Reversed.setValue(on); - // midplane is not sensible when reversed - ui->checkBoxMidplane->setEnabled(!on); // update the direction tryRecomputeFeature(); updateDirectionEdits(); From 3ee1d91b884fd938ef216a6627ff1b14c6054878 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 3 Dec 2021 14:46:19 +0100 Subject: [PATCH 117/133] PD: cleanup the mess with boolean arguments and replace them with a bitmask --- src/Mod/PartDesign/Gui/CMakeLists.txt | 1 + src/Mod/PartDesign/Gui/EnumFlags.h | 51 +++++++++++++++++++ src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 33 ++++++------ src/Mod/PartDesign/Gui/ReferenceSelection.h | 24 +++------ .../PartDesign/Gui/TaskDraftParameters.cpp | 7 ++- .../PartDesign/Gui/TaskDressUpParameters.cpp | 12 +++-- .../PartDesign/Gui/TaskExtrudeParameters.cpp | 6 ++- .../PartDesign/Gui/TaskHelixParameters.cpp | 4 +- .../Gui/TaskLinearPatternParameters.cpp | 2 +- .../PartDesign/Gui/TaskMirroredParameters.cpp | 2 +- .../Gui/TaskPolarPatternParameters.cpp | 2 +- .../Gui/TaskRevolutionParameters.cpp | 4 +- .../Gui/TaskSketchBasedParameters.cpp | 10 ++-- .../Gui/TaskSketchBasedParameters.h | 3 +- .../Gui/TaskTransformedParameters.cpp | 5 +- .../Gui/TaskTransformedParameters.h | 3 +- 16 files changed, 113 insertions(+), 56 deletions(-) create mode 100644 src/Mod/PartDesign/Gui/EnumFlags.h diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index 36323b94f9..e3964bcaf2 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -226,6 +226,7 @@ SET(PartDesignGuiModule_SRCS Command.cpp CommandPrimitive.cpp CommandBody.cpp + EnumFlags.h Resources/PartDesign.qrc PreCompiled.cpp PreCompiled.h diff --git a/src/Mod/PartDesign/Gui/EnumFlags.h b/src/Mod/PartDesign/Gui/EnumFlags.h new file mode 100644 index 0000000000..ecd410a6b5 --- /dev/null +++ b/src/Mod/PartDesign/Gui/EnumFlags.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (c) 2021 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef PARTDESIGNGUI_ENUMFLAGS_H +#define PARTDESIGNGUI_ENUMFLAGS_H + +#include + +namespace PartDesignGui { + +// https://wiggling-bits.net/using-enum-classes-as-type-safe-bitmasks/ +// https://www.boost.org/doc/libs/1_66_0/boost/detail/bitmask.hpp +// https://stackoverflow.com/questions/1448396/how-to-use-enums-as-flags-in-c + +enum class AllowSelection { + NONE = 0, + EDGE = 1 << 0, /**< Allow picking edges */ + FACE = 1 << 1, /**< Allow picking faces */ + PLANAR = 1 << 2, /**< Allow only linear edges and planar faces */ + CIRCLE = 1 << 3, /**< Allow picking circular edges (incl arcs) */ + POINT = 1 << 4, /**< Allow picking datum points */ + OTHERBODY = 1 << 5, /**< Allow picking objects from another body in the same part */ + WHOLE = 1 << 6 /**< Allow whole object selection */ +}; +Q_DECLARE_FLAGS(AllowSelectionFlags, AllowSelection) + +} //namespace PartDesignGui + +Q_DECLARE_OPERATORS_FOR_FLAGS(PartDesignGui::AllowSelectionFlags) + +#endif // PARTDESIGNGUI_ENUMFLAGS_H diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index c3528aa0c5..67478b0840 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -90,9 +90,9 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c // Enable selection from origin of current part/ if ( pObj->getTypeId().isDerivedFrom(App::OriginFeature::getClassTypeId()) ) { bool fits = false; - if ( plane && pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) ) { + if ( type.testFlag(AllowSelection::FACE) && pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) ) { fits = true; - } else if ( edge && pObj->getTypeId().isDerivedFrom(App::Line::getClassTypeId()) ) { + } else if ( type.testFlag(AllowSelection::EDGE) && pObj->getTypeId().isDerivedFrom(App::Line::getClassTypeId()) ) { fits = true; } @@ -107,8 +107,9 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c return true; } } - } catch (const Base::Exception&) - { } + } + catch (const Base::Exception&) { + } } return false; // The Plane/Axis doesn't fits our needs } @@ -117,21 +118,21 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c if (!body) { // Allow selecting Part::Datum features from the active Body return false; - } else if (!allowOtherBody && !body->hasObject(pObj)) { + } else if (!type.testFlag(AllowSelection::OTHERBODY) && !body->hasObject(pObj)) { return false; } - if (plane && (pObj->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId()))) + if (type.testFlag(AllowSelection::FACE) && (pObj->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId()))) return true; - if (edge && (pObj->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId()))) + if (type.testFlag(AllowSelection::EDGE) && (pObj->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId()))) return true; - if (point && (pObj->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId()))) + if (type.testFlag(AllowSelection::POINT) && (pObj->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId()))) return true; return false; } - if (!allowOtherBody) { + if (!type.testFlag(AllowSelection::OTHERBODY)) { if (support == NULL) return false; if (pObj != support) @@ -139,7 +140,7 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c } // Handle selection of geometry elements if (!sSubName || sSubName[0] == '\0') - return whole; + return type.testFlag(AllowSelection::WHOLE); // resolve links if needed if (!pObj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { @@ -148,12 +149,12 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c if (pObj && pObj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { std::string subName(sSubName); - if (edge && subName.compare(0, 4, "Edge") == 0) { + if (type.testFlag(AllowSelection::EDGE) && subName.compare(0, 4, "Edge") == 0) { const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(subName.c_str()); const TopoDS_Edge& edgeShape = TopoDS::Edge(sh); if (!edgeShape.IsNull()) { - if (planar) { + if (type.testFlag(AllowSelection::PLANAR)) { BRepAdaptor_Curve adapt(edgeShape); if (adapt.GetType() == GeomAbs_Line) return true; @@ -162,12 +163,12 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c } } } - if (plane && subName.compare(0, 4, "Face") == 0) { + if (type.testFlag(AllowSelection::FACE) && subName.compare(0, 4, "Face") == 0) { const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(subName.c_str()); const TopoDS_Face& face = TopoDS::Face(sh); if (!face.IsNull()) { - if (planar) { + if (type.testFlag(AllowSelection::PLANAR)) { BRepAdaptor_Surface adapt(face); if (adapt.GetType() == GeomAbs_Plane) return true; @@ -176,10 +177,10 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c } } } - if (point && subName.compare(0, 6, "Vertex") == 0) { + if (type.testFlag(AllowSelection::POINT) && subName.compare(0, 6, "Vertex") == 0) { return true; } - if (circle && subName.compare(0, 4, "Edge") == 0) { + if (type.testFlag(AllowSelection::CIRCLE) && subName.compare(0, 4, "Edge") == 0) { const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(subName.c_str()); const TopoDS_Edge& edgeShape = TopoDS::Edge(sh); diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.h b/src/Mod/PartDesign/Gui/ReferenceSelection.h index 42490a75ce..1c274412e3 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.h +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.h @@ -25,33 +25,21 @@ #define GUI_ReferenceSelection_H #include +#include namespace PartDesignGui { class ReferenceSelection : public Gui::SelectionFilterGate { - // TODO Replace this set of bools with bitwice enum (2015-09-04, Fat-Zer) const App::DocumentObject* support; - // If set to true, allow picking edges or planes or both - bool edge, plane; - // If set to true, allow only linear edges and planar faces - bool planar; - // If set to true, allow picking datum points - bool point; - // If set to true, allow picking objects from another body in the same part - bool allowOtherBody; - // Allow whole object selection - bool whole; - // Allow picking circular edges (incl arcs) - bool circle; + AllowSelectionFlags type; public: ReferenceSelection(const App::DocumentObject* support_, - const bool edge_, const bool plane_, const bool planar_, - const bool point_ = false, bool whole_ = false, bool circle_ = false) - : Gui::SelectionFilterGate((Gui::SelectionFilter*)0), - support(support_), edge(edge_), plane(plane_), - planar(planar_), point(point_), allowOtherBody(true), whole(whole_), circle(circle_) + AllowSelectionFlags type) + : Gui::SelectionFilterGate(static_cast(nullptr)) + , support(support_) + , type(type) { } /** diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp index 48a5a36054..afbb520963 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp @@ -212,7 +212,9 @@ void TaskDraftParameters::onButtonPlane(bool checked) hideObject(); selectionMode = plane; Gui::Selection().clearSelection(); - Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), true, true, true)); + Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), AllowSelection::EDGE | + AllowSelection::FACE | + AllowSelection::PLANAR)); } } @@ -223,7 +225,8 @@ void TaskDraftParameters::onButtonLine(bool checked) hideObject(); selectionMode = line; Gui::Selection().clearSelection(); - Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), true, false, true)); + Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), AllowSelection::EDGE | + AllowSelection::PLANAR)); } } diff --git a/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp b/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp index 79f63a2b95..880393589f 100644 --- a/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp @@ -145,8 +145,11 @@ void TaskDressUpParameters::onButtonRefAdd(bool checked) clearButtons(refAdd); hideObject(); selectionMode = refAdd; + AllowSelectionFlags allow; + allow.setFlag(AllowSelection::EDGE, allowEdges); + allow.setFlag(AllowSelection::FACE, allowFaces); Gui::Selection().clearSelection(); - Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), allowEdges, allowFaces, false)); + Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), allow)); DressUpView->highlightReferences(true); } else { exitSelectionMode(); @@ -160,8 +163,11 @@ void TaskDressUpParameters::onButtonRefRemove(const bool checked) clearButtons(refRemove); hideObject(); selectionMode = refRemove; - Gui::Selection().clearSelection(); - Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), allowEdges, allowFaces, false)); + AllowSelectionFlags allow; + allow.setFlag(AllowSelection::EDGE, allowEdges); + allow.setFlag(AllowSelection::FACE, allowFaces); + Gui::Selection().clearSelection(); + Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), allow)); DressUpView->highlightReferences(true); } else { diff --git a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp index fc47b0e8aa..b5cb476111 100644 --- a/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskExtrudeParameters.cpp @@ -411,7 +411,9 @@ void TaskExtrudeParameters::onDirectionCBChanged(int num) // to distinguish that this is the direction selection selectionFace = false; setDirectionMode(num); - TaskSketchBasedParameters::onSelectReference(true, true, false, true, true); + TaskSketchBasedParameters::onSelectReference(true, AllowSelection::EDGE | + AllowSelection::PLANAR | + AllowSelection::CIRCLE); } else { if (lnk.getValue()) { @@ -564,7 +566,7 @@ void TaskExtrudeParameters::onButtonFace(const bool pressed) selectionFace = true; // only faces are allowed - TaskSketchBasedParameters::onSelectReference(pressed, false, true, false); + TaskSketchBasedParameters::onSelectReference(pressed, AllowSelection::FACE); // Update button if onButtonFace() is called explicitly ui->buttonFace->setChecked(pressed); diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp index 8ede0b0d9e..58d4fc45c4 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp @@ -426,7 +426,9 @@ void TaskHelixParameters::onAxisChanged(int num) App::PropertyLinkSub& lnk = *(axesInList[num]); if (lnk.getValue() == 0) { // enter reference selection mode - TaskSketchBasedParameters::onSelectReference(true, true, false, true, true); + TaskSketchBasedParameters::onSelectReference(true, AllowSelection::EDGE | + AllowSelection::PLANAR | + AllowSelection::CIRCLE); return; } else { diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp index 1813f1ff00..34c05623f0 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp @@ -333,7 +333,7 @@ void TaskLinearPatternParameters::onDirectionChanged(int /*num*/) showBase(); selectionMode = reference; Gui::Selection().clearSelection(); - addReferenceSelectionGate(true, true); + addReferenceSelectionGate(AllowSelection::EDGE | AllowSelection::FACE | AllowSelection::PLANAR); } else { exitSelectionMode(); pcLinearPattern->Direction.Paste(dirLinks.getCurrentLink()); diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp index 4f1bfce4ef..b2f1e92e12 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp @@ -246,7 +246,7 @@ void TaskMirroredParameters::onPlaneChanged(int /*num*/) showBase(); selectionMode = reference; Gui::Selection().clearSelection(); - addReferenceSelectionGate(false, true); + addReferenceSelectionGate(AllowSelection::FACE | AllowSelection::PLANAR); } else { exitSelectionMode(); pcMirrored->MirrorPlane.Paste(planeLinks.getCurrentLink()); diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp index 2fa8f63e01..197dbeb9c8 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp @@ -324,7 +324,7 @@ void TaskPolarPatternParameters::onAxisChanged(int /*num*/) showBase(); selectionMode = reference; Gui::Selection().clearSelection(); - addReferenceSelectionGate(true, false, false, false, true); + addReferenceSelectionGate(AllowSelection::EDGE | AllowSelection::CIRCLE); } else { exitSelectionMode(); pcPolarPattern->Axis.Paste(axesLinks.getCurrentLink()); diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 892ad00ffa..a8db50ea67 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -262,7 +262,9 @@ void TaskRevolutionParameters::onAxisChanged(int num) App::PropertyLinkSub &lnk = *(axesInList[num]); if (lnk.getValue() == 0) { // enter reference selection mode - TaskSketchBasedParameters::onSelectReference(true, true, false, true, true); + TaskSketchBasedParameters::onSelectReference(true, AllowSelection::EDGE | + AllowSelection::PLANAR | + AllowSelection::CIRCLE); } else { if (!pcRevolution->getDocument()->isIn(lnk.getValue())){ Base::Console().Error("Object was deleted\n"); diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp index d44f7d7f66..e5a7ddf572 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp @@ -112,7 +112,7 @@ void TaskSketchBasedParameters::finishReferenceSelection(App::DocumentObject* pr } } -void TaskSketchBasedParameters::onSelectReference(const bool pressed, const bool edge, const bool face, const bool planar, const bool circle) { +void TaskSketchBasedParameters::onSelectReference(const bool pressed, AllowSelectionFlags allow) { // Note: Even if there is no solid, App::Plane and Part::Datum can still be selected PartDesign::ProfileBased* pcSketchBased = dynamic_cast(vp->getObject()); @@ -123,9 +123,9 @@ void TaskSketchBasedParameters::onSelectReference(const bool pressed, const bool if (pressed) { startReferenceSelection(pcSketchBased, prevSolid); Gui::Selection().clearSelection(); - Gui::Selection().addSelectionGate - (new ReferenceSelection(prevSolid, edge, face, planar, false, false, circle)); - } else { + Gui::Selection().addSelectionGate(new ReferenceSelection(prevSolid, allow)); + } + else { Gui::Selection().rmvSelectionGate(); finishReferenceSelection(pcSketchBased, prevSolid); } @@ -135,7 +135,7 @@ void TaskSketchBasedParameters::onSelectReference(const bool pressed, const bool void TaskSketchBasedParameters::exitSelectionMode() { - onSelectReference(false, false, false, false); + onSelectReference(false, AllowSelection::NONE); } QVariant TaskSketchBasedParameters::setUpToFace(const QString& text) diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h index 7ef9c2cd82..5fd872f256 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h @@ -29,6 +29,7 @@ #include "ViewProvider.h" #include "TaskFeatureParameters.h" +#include "EnumFlags.h" namespace App { class Property; @@ -53,7 +54,7 @@ protected: const QString onAddSelection(const Gui::SelectionChanges& msg); virtual void startReferenceSelection(App::DocumentObject* profile, App::DocumentObject* base); virtual void finishReferenceSelection(App::DocumentObject* profile, App::DocumentObject* base); - void onSelectReference(const bool pressed, const bool edge, const bool face, const bool planar, const bool circle = false); + void onSelectReference(const bool pressed, AllowSelectionFlags); void exitSelectionMode(); QVariant setUpToFace(const QString& text); /// Try to find the name of a feature with the given label. diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp index db09de8d6a..87deeaa282 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp @@ -410,10 +410,9 @@ void TaskTransformedParameters::exitSelectionMode() } } -void TaskTransformedParameters::addReferenceSelectionGate(bool edge, bool face, bool planar, bool whole, bool circle) +void TaskTransformedParameters::addReferenceSelectionGate(AllowSelectionFlags allow) { - std::unique_ptr gateRefPtr( - new ReferenceSelection(getBaseObject(), edge, face, planar, false, whole, circle)); + std::unique_ptr gateRefPtr(new ReferenceSelection(getBaseObject(), allow)); std::unique_ptr gateDepPtr(new NoDependentsSelection(getTopTransformedObject())); Gui::Selection().addSelectionGate(new CombineSelectionFilterGates(gateRefPtr, gateDepPtr)); } diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h index e8c98d75e4..dd22971828 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -188,7 +189,7 @@ protected: void hideBase(); void showBase(); - void addReferenceSelectionGate(bool edge, bool face, bool planar=true, bool whole=false, bool circle=false); + void addReferenceSelectionGate(AllowSelectionFlags); bool isViewUpdated() const; int getUpdateViewTimeout() const; From c64d86274ce312175bf417b792010b7ac30a8d08 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 3 Dec 2021 15:58:23 +0100 Subject: [PATCH 118/133] PD: minor cleanup in view provider headers --- src/Mod/PartDesign/Gui/ViewProvider.h | 1 + src/Mod/PartDesign/Gui/ViewProviderMirrored.h | 8 ++++---- src/Mod/PartDesign/Gui/ViewProviderMultiTransform.h | 7 ++++--- src/Mod/PartDesign/Gui/ViewProviderPolarPattern.h | 7 ++++--- src/Mod/PartDesign/Gui/ViewProviderScaled.h | 7 ++++--- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ViewProvider.h b/src/Mod/PartDesign/Gui/ViewProvider.h index 6ff7ffccb4..9757469234 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.h +++ b/src/Mod/PartDesign/Gui/ViewProvider.h @@ -29,6 +29,7 @@ #include #include +#include namespace PartDesignGui { diff --git a/src/Mod/PartDesign/Gui/ViewProviderMirrored.h b/src/Mod/PartDesign/Gui/ViewProviderMirrored.h index 1de7253cdd..59a1a6d347 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderMirrored.h +++ b/src/Mod/PartDesign/Gui/ViewProviderMirrored.h @@ -32,10 +32,10 @@ class PartDesignGuiExport ViewProviderMirrored : public ViewProviderTransformed { PROPERTY_HEADER(PartDesignGui::ViewProviderMirrored); public: - ViewProviderMirrored() - { featureName = std::string("Mirrored"); - sPixmap = "PartDesign_Mirrored.svg"; - } + ViewProviderMirrored() { + featureName = std::string("Mirrored"); + sPixmap = "PartDesign_Mirrored.svg"; + } protected: /// Returns a newly create dialog for the part to be placed in the task view diff --git a/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.h b/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.h index 43c73449e0..66c7040272 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.h +++ b/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.h @@ -32,9 +32,10 @@ class PartDesignGuiExport ViewProviderMultiTransform : public ViewProviderTransf { PROPERTY_HEADER(PartDesignGui::ViewProviderMultiTransform); public: - ViewProviderMultiTransform() - { featureName = std::string("MultiTransform"); - sPixmap = "PartDesign_MultiTransform.svg"; } + ViewProviderMultiTransform() { + featureName = std::string("MultiTransform"); + sPixmap = "PartDesign_MultiTransform.svg"; + } std::vector claimChildren(void) const; diff --git a/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.h b/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.h index 480ccef95b..a4441cc8bf 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.h +++ b/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.h @@ -32,9 +32,10 @@ class PartDesignGuiExport ViewProviderPolarPattern : public ViewProviderTransfor { PROPERTY_HEADER(PartDesignGui::ViewProviderPolarPattern); public: - ViewProviderPolarPattern() - { featureName = std::string("PolarPattern"); - sPixmap = "PartDesign_PolarPattern.svg"; } + ViewProviderPolarPattern() { + featureName = std::string("PolarPattern"); + sPixmap = "PartDesign_PolarPattern.svg"; + } protected: /// Returns a newly create dialog for the part to be placed in the task view diff --git a/src/Mod/PartDesign/Gui/ViewProviderScaled.h b/src/Mod/PartDesign/Gui/ViewProviderScaled.h index 6c928e6421..fc9ccb85f1 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderScaled.h +++ b/src/Mod/PartDesign/Gui/ViewProviderScaled.h @@ -32,9 +32,10 @@ class PartDesignGuiExport ViewProviderScaled : public ViewProviderTransformed { PROPERTY_HEADER(PartDesignGui::ViewProviderScaled); public: - ViewProviderScaled() - { featureName = std::string("Scaled"); - sPixmap = "PartDesign_Scaled.svg"; } + ViewProviderScaled() { + featureName = std::string("Scaled"); + sPixmap = "PartDesign_Scaled.svg"; + } protected: /// Returns a newly create dialog for the part to be placed in the task view From fab96e215158b15e02d948265a18eba6e11d81d2 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 3 Dec 2021 15:59:15 +0100 Subject: [PATCH 119/133] PD: avoid include generated .ui file in header file --- src/Mod/PartDesign/Gui/DlgActiveBody.cpp | 27 +++++++++++++----------- src/Mod/PartDesign/Gui/DlgActiveBody.h | 9 +++++--- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/Mod/PartDesign/Gui/DlgActiveBody.cpp b/src/Mod/PartDesign/Gui/DlgActiveBody.cpp index fb4841d94f..07bcd2ad02 100644 --- a/src/Mod/PartDesign/Gui/DlgActiveBody.cpp +++ b/src/Mod/PartDesign/Gui/DlgActiveBody.cpp @@ -31,29 +31,28 @@ #include #include +#include "ui_DlgActiveBody.h" #include "DlgActiveBody.h" #include "ReferenceSelection.h" #include "Utils.h" -Q_DECLARE_METATYPE(App::DocumentObject*); +Q_DECLARE_METATYPE(App::DocumentObject*) using namespace PartDesignGui; -DlgActiveBody::DlgActiveBody(QWidget *parent, App::Document*& doc, - const QString& infoText) - : QDialog(parent), - ui(new Ui_DlgActiveBody), - _doc(doc), - activeBody(nullptr) +DlgActiveBody::DlgActiveBody(QWidget *parent, App::Document*& doc, const QString& infoText) + : QDialog(parent) + , ui(new Ui_DlgActiveBody) + , _doc(doc) + , activeBody(nullptr) { ui->setupUi(this); - QObject::connect(ui->bodySelect, SIGNAL(itemDoubleClicked(QListWidgetItem *)), - this, SLOT(accept())); + connect(ui->bodySelect, SIGNAL(itemDoubleClicked(QListWidgetItem *)), + this, SLOT(accept())); - if(!infoText.isEmpty()) { - ui->label->setText(infoText + QString::fromUtf8("\n\n") + - QObject::tr("Please select")); + if (!infoText.isEmpty()) { + ui->label->setText(infoText + QString::fromUtf8("\n\n") + tr("Please select")); } auto bodies = _doc->getObjectsOfType(PartDesign::Body::getClassTypeId()); @@ -85,6 +84,10 @@ DlgActiveBody::DlgActiveBody(QWidget *parent, App::Document*& doc, } } +DlgActiveBody::~DlgActiveBody() +{ +} + void DlgActiveBody::accept() { auto selectedItems = ui->bodySelect->selectedItems(); diff --git a/src/Mod/PartDesign/Gui/DlgActiveBody.h b/src/Mod/PartDesign/Gui/DlgActiveBody.h index c73f3c8bcd..d0ccf61139 100644 --- a/src/Mod/PartDesign/Gui/DlgActiveBody.h +++ b/src/Mod/PartDesign/Gui/DlgActiveBody.h @@ -26,13 +26,15 @@ #ifndef PARTDESIGNGUI_DLGACTIVEBODY_H #define PARTDESIGNGUI_DLGACTIVEBODY_H +#include +#include #include #include +#include -// TODO: Apparently this header can be avoided. See ./Command.cpp:74. -#include "ui_DlgActiveBody.h" namespace PartDesignGui { +class Ui_DlgActiveBody; /** Dialog box to ask user to pick a Part Design body to make active * or make a new one @@ -44,9 +46,10 @@ class PartDesignGuiExport DlgActiveBody : public QDialog public: DlgActiveBody(QWidget* parent, App::Document*& doc, const QString& infoText=QString()); + ~DlgActiveBody(); void accept() override; - PartDesign::Body* getActiveBody() { return activeBody; }; + PartDesign::Body* getActiveBody() const { return activeBody; } private: std::unique_ptr ui; From 7aef0b3de76543152d91dc35e768aab1c86c071d Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Thu, 25 Nov 2021 15:22:24 +0100 Subject: [PATCH 120/133] [Gui] UserEditMode : fix operating on PartDesignObject --- src/Mod/PartDesign/Gui/ViewProvider.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index 156424678f..8717eb0660 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -66,10 +66,9 @@ ViewProvider::~ViewProvider() bool ViewProvider::doubleClicked(void) { try { - PartDesign::Body* body = PartDesign::Body::findBodyOf(getObject()); QString text = QObject::tr("Edit %1").arg(QString::fromUtf8(getObject()->Label.getValue())); Gui::Command::openCommand(text.toUtf8()); - PartDesignGui::setEdit(pcObject,body); + FCMD_SET_EDIT(pcObject); } catch (const Base::Exception&) { Gui::Command::abortCommand(); From 92a8e0e3d8f3845e5007f95f4c94bf1c83f50ff6 Mon Sep 17 00:00:00 2001 From: 0penBrain <48731257+0penBrain@users.noreply.github.com> Date: Thu, 2 Dec 2021 17:38:36 +0100 Subject: [PATCH 121/133] [Gui] Tree: implement collapse/expand system with keys Implemented using Alt modifier + arrow keys * Alt+Left : collapse selected items * Alt+Right : expand selected items * Alt+Up : expand selected items with all tier-1 children collapsed * Alt+Down : expand selected items with all tier-1 children expanded --- src/Gui/Tree.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/Gui/Tree.h | 2 ++ 2 files changed, 46 insertions(+) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 6d400dbf66..f02f0a5f87 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -1372,6 +1372,38 @@ void TreeWidget::keyPressEvent(QKeyEvent *event) event->accept(); onSearchObjects(); return; + }else if(event->modifiers() == Qt::AltModifier) { + if(event->key() == Qt::Key_Left) { + for(auto &item: selectedItems()) { + item->setExpanded(false); + } + event->accept(); + return; + }else if(event->key() == Qt::Key_Right) { + for(auto &item: selectedItems()) { + item->setExpanded(true); + } + event->accept(); + return; + }else if(event->key() == Qt::Key_Up) { + for(auto &item: selectedItems()) { + item->setExpanded(true); + for (auto &child: childrenOfItem(*item)) { + child->setExpanded(false); + } + } + event->accept(); + return; + }else if(event->key() == Qt::Key_Down) { + for(auto &item: selectedItems()) { + item->setExpanded(true); + for (auto &child: childrenOfItem(*item)) { + child->setExpanded(true); + } + } + event->accept(); + return; + } }else if(event->key() == Qt::Key_Left) { auto index = currentIndex(); if(index.column()==1) { @@ -2915,6 +2947,18 @@ void TreeWidget::synchronizeSelectionCheckBoxes() { resizeColumnToContents(0); } +QList TreeWidget::childrenOfItem(const QTreeWidgetItem &item) const{ + QList children = QList(); + + // check item is in this tree + if (!this->indexFromItem(&item).isValid()) return children; + + for (int i=0 ; i < item.childCount() ; i++) { + children.append(item.child(i)); + } + return children; +} + void TreeWidget::onItemChanged(QTreeWidgetItem *item, int column) { if (column == 0 && isSelectionCheckBoxesEnabled()) { bool selected = item->isSelected(); diff --git a/src/Gui/Tree.h b/src/Gui/Tree.h index f644f81a64..d2b4575757 100644 --- a/src/Gui/Tree.h +++ b/src/Gui/Tree.h @@ -131,6 +131,8 @@ public: void synchronizeSelectionCheckBoxes(); + QList childrenOfItem(const QTreeWidgetItem &item) const; + protected: /// Observer message from the Selection void onSelectionChanged(const SelectionChanges& msg) override; From 543024e078ba25806ccca12d26b7112536793cce Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 3 Dec 2021 20:18:46 +0100 Subject: [PATCH 122/133] PD: comment out dead code --- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index 67478b0840..bf585c598e 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -132,12 +132,15 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c return false; } + // The flag was used to be set. So, this block will never be treated and doesn't make really sense anyway +#if 0 if (!type.testFlag(AllowSelection::OTHERBODY)) { if (support == NULL) return false; if (pObj != support) return false; } +#endif // Handle selection of geometry elements if (!sSubName || sSubName[0] == '\0') return type.testFlag(AllowSelection::WHOLE); From 6e52161dce41f82dcdb6e21237b5ceba032c18cb Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 3 Dec 2021 21:38:28 +0100 Subject: [PATCH 123/133] PD: refactor ReferenceSelection --- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 270 +++++++++++------- src/Mod/PartDesign/Gui/ReferenceSelection.h | 16 ++ 2 files changed, 184 insertions(+), 102 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index bf585c598e..55feb77d9e 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -60,76 +60,21 @@ using namespace Gui; bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, const char* sSubName) { - // TODO review this function (2015-09-04, Fat-Zer) - PartDesign::Body *body; - App::DocumentObject* originGroupObject = nullptr; - - if ( support ) { - body = PartDesign::Body::findBodyOf (support); - } else { - body = PartDesignGui::getBody (false); - } - - if ( body ) { // Search for Part of the body - originGroupObject = App::OriginGroupExtension::getGroupOfObject ( body ) ; - } else if ( support ) { // if no body search part for support - originGroupObject = App::OriginGroupExtension::getGroupOfObject ( support ) ; - } else { // fallback to active part - originGroupObject = PartDesignGui::getActivePart ( ); - } - - App::OriginGroupExtension* originGroup = nullptr; - if(originGroupObject) - originGroup = originGroupObject->getExtensionByType(); + PartDesign::Body *body = getBody(); + App::OriginGroupExtension* originGroup = getOriginGroupExtension(body); // Don't allow selection in other document - if ( support && pDoc != support->getDocument() ) { + if (support && pDoc != support->getDocument()) { return false; } // Enable selection from origin of current part/ - if ( pObj->getTypeId().isDerivedFrom(App::OriginFeature::getClassTypeId()) ) { - bool fits = false; - if ( type.testFlag(AllowSelection::FACE) && pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) ) { - fits = true; - } else if ( type.testFlag(AllowSelection::EDGE) && pObj->getTypeId().isDerivedFrom(App::Line::getClassTypeId()) ) { - fits = true; - } - - if (fits) { // check that it is actually belongs to the chosen body or part - try { // here are some throwers - if (body) { - if (body->getOrigin ()->hasObject (pObj) ) { - return true; - } - } else if (originGroup ) { - if ( originGroup->getOrigin ()->hasObject (pObj) ) { - return true; - } - } - } - catch (const Base::Exception&) { - } - } - return false; // The Plane/Axis doesn't fits our needs + if (pObj->getTypeId().isDerivedFrom(App::OriginFeature::getClassTypeId())) { + return allowOrigin(body, originGroup, pObj); } if (pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { - - if (!body) { // Allow selecting Part::Datum features from the active Body - return false; - } else if (!type.testFlag(AllowSelection::OTHERBODY) && !body->hasObject(pObj)) { - return false; - } - - if (type.testFlag(AllowSelection::FACE) && (pObj->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId()))) - return true; - if (type.testFlag(AllowSelection::EDGE) && (pObj->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId()))) - return true; - if (type.testFlag(AllowSelection::POINT) && (pObj->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId()))) - return true; - - return false; + return allowDatum(body, pObj); } // The flag was used to be set. So, this block will never be treated and doesn't make really sense anyway @@ -151,51 +96,172 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c } if (pObj && pObj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - std::string subName(sSubName); - if (type.testFlag(AllowSelection::EDGE) && subName.compare(0, 4, "Edge") == 0) { - const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); - TopoDS_Shape sh = shape.getSubShape(subName.c_str()); - const TopoDS_Edge& edgeShape = TopoDS::Edge(sh); - if (!edgeShape.IsNull()) { - if (type.testFlag(AllowSelection::PLANAR)) { - BRepAdaptor_Curve adapt(edgeShape); - if (adapt.GetType() == GeomAbs_Line) - return true; - } else { - return true; - } - } - } - if (type.testFlag(AllowSelection::FACE) && subName.compare(0, 4, "Face") == 0) { - const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); - TopoDS_Shape sh = shape.getSubShape(subName.c_str()); - const TopoDS_Face& face = TopoDS::Face(sh); - if (!face.IsNull()) { - if (type.testFlag(AllowSelection::PLANAR)) { - BRepAdaptor_Surface adapt(face); - if (adapt.GetType() == GeomAbs_Plane) - return true; - } else { - return true; - } - } - } - if (type.testFlag(AllowSelection::POINT) && subName.compare(0, 6, "Vertex") == 0) { - return true; - } - if (type.testFlag(AllowSelection::CIRCLE) && subName.compare(0, 4, "Edge") == 0) { - const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); - TopoDS_Shape sh = shape.getSubShape(subName.c_str()); - const TopoDS_Edge& edgeShape = TopoDS::Edge(sh); - BRepAdaptor_Curve adapt(edgeShape); - if (adapt.GetType() == GeomAbs_Circle) { - return true; - } - } + return allowPartFeature(pObj, sSubName); } + return false; } +PartDesign::Body* ReferenceSelection::getBody() const +{ + PartDesign::Body *body; + if (support) { + body = PartDesign::Body::findBodyOf (support); + } + else { + body = PartDesignGui::getBody(false); + } + + return body; +} + +App::OriginGroupExtension* ReferenceSelection::getOriginGroupExtension(PartDesign::Body *body) const +{ + App::DocumentObject* originGroupObject = nullptr; + + if (body) { // Search for Part of the body + originGroupObject = App::OriginGroupExtension::getGroupOfObject(body); + } + else if (support) { // if no body search part for support + originGroupObject = App::OriginGroupExtension::getGroupOfObject(support); + } + else { // fallback to active part + originGroupObject = PartDesignGui::getActivePart(); + } + + App::OriginGroupExtension* originGroup = nullptr; + if (originGroupObject) + originGroup = originGroupObject->getExtensionByType(); + + return originGroup; +} + +bool ReferenceSelection::allowOrigin(PartDesign::Body *body, App::OriginGroupExtension* originGroup, App::DocumentObject* pObj) const +{ + bool fits = false; + if (type.testFlag(AllowSelection::FACE) && pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + fits = true; + } + else if (type.testFlag(AllowSelection::EDGE) && pObj->getTypeId().isDerivedFrom(App::Line::getClassTypeId())) { + fits = true; + } + + if (fits) { // check that it actually belongs to the chosen body or part + try { // here are some throwers + if (body) { + if (body->getOrigin ()->hasObject (pObj) ) { + return true; + } + } + else if (originGroup ) { + if (originGroup->getOrigin()->hasObject(pObj)) { + return true; + } + } + } + catch (const Base::Exception&) { + } + } + return false; // The Plane/Axis doesn't fits our needs +} + +bool ReferenceSelection::allowDatum(PartDesign::Body *body, App::DocumentObject* pObj) const +{ + if (!body) { // Allow selecting Part::Datum features from the active Body + return false; + } + else if (!type.testFlag(AllowSelection::OTHERBODY) && !body->hasObject(pObj)) { + return false; + } + + if (type.testFlag(AllowSelection::FACE) && (pObj->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId()))) + return true; + if (type.testFlag(AllowSelection::EDGE) && (pObj->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId()))) + return true; + if (type.testFlag(AllowSelection::POINT) && (pObj->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId()))) + return true; + + return false; +} + +bool ReferenceSelection::allowPartFeature(App::DocumentObject* pObj, const char* sSubName) const +{ + std::string subName(sSubName); + if (type.testFlag(AllowSelection::POINT) && subName.compare(0, 6, "Vertex") == 0) { + return true; + } + + if (type.testFlag(AllowSelection::EDGE) && subName.compare(0, 4, "Edge") == 0) { + if (isEdge(pObj, sSubName)) + return true; + } + + if (type.testFlag(AllowSelection::CIRCLE) && subName.compare(0, 4, "Edge") == 0) { + if (isCircle(pObj, sSubName)) + return true; + } + + if (type.testFlag(AllowSelection::FACE) && subName.compare(0, 4, "Face") == 0) { + if (isFace(pObj, sSubName)) + return true; + } + + return false; +} + +bool ReferenceSelection::isEdge(App::DocumentObject* pObj, const char* sSubName) const +{ + const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); + TopoDS_Shape sh = shape.getSubShape(sSubName); + const TopoDS_Edge& edgeShape = TopoDS::Edge(sh); + if (!edgeShape.IsNull()) { + if (type.testFlag(AllowSelection::PLANAR)) { + BRepAdaptor_Curve adapt(edgeShape); + if (adapt.GetType() == GeomAbs_Line) + return true; + } + else { + return true; + } + } + + return false; +} + +bool ReferenceSelection::isFace(App::DocumentObject* pObj, const char* sSubName) const +{ + const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); + TopoDS_Shape sh = shape.getSubShape(sSubName); + const TopoDS_Face& face = TopoDS::Face(sh); + if (!face.IsNull()) { + if (type.testFlag(AllowSelection::PLANAR)) { + BRepAdaptor_Surface adapt(face); + if (adapt.GetType() == GeomAbs_Plane) + return true; + } + else { + return true; + } + } + + return false; +} + +bool ReferenceSelection::isCircle(App::DocumentObject* pObj, const char* sSubName) const +{ + const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); + TopoDS_Shape sh = shape.getSubShape(sSubName); + const TopoDS_Edge& edgeShape = TopoDS::Edge(sh); + BRepAdaptor_Curve adapt(edgeShape); + if (adapt.GetType() == GeomAbs_Circle) { + return true; + } + + return false; +} + +// ---------------------------------------------------------------------------- + bool NoDependentsSelection::allow(App::Document* /*pDoc*/, App::DocumentObject* pObj, const char* /*sSubName*/) { if (support && support->testIfLinkDAGCompatible(pObj)) { diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.h b/src/Mod/PartDesign/Gui/ReferenceSelection.h index 1c274412e3..ce662c9c77 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.h +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.h @@ -27,6 +27,12 @@ #include #include +namespace App { +class OriginGroupExtension; +} +namespace PartDesign { +class Body; +} namespace PartDesignGui { class ReferenceSelection : public Gui::SelectionFilterGate @@ -47,6 +53,16 @@ public: * Optionally restrict the selection to planar edges/faces */ bool allow(App::Document* pDoc, App::DocumentObject* pObj, const char* sSubName); + +private: + PartDesign::Body* getBody() const; + App::OriginGroupExtension* getOriginGroupExtension(PartDesign::Body *body) const; + bool allowOrigin(PartDesign::Body *body, App::OriginGroupExtension* originGroup, App::DocumentObject* pObj) const; + bool allowDatum(PartDesign::Body *body, App::DocumentObject* pObj) const; + bool allowPartFeature(App::DocumentObject* pObj, const char* sSubName) const; + bool isEdge(App::DocumentObject* pObj, const char* sSubName) const; + bool isFace(App::DocumentObject* pObj, const char* sSubName) const; + bool isCircle(App::DocumentObject* pObj, const char* sSubName) const; }; class NoDependentsSelection : public Gui::SelectionFilterGate From 04be1a4af9c98f0002ddc457dd922777445767d3 Mon Sep 17 00:00:00 2001 From: Uwe Date: Sat, 4 Dec 2021 02:57:34 +0100 Subject: [PATCH 124/133] [GUI] code style fixes for Tree.cpp tons of style fixes by MSVC (the idea was initially just to fix the code style issues from commit 92a8e0e3d8f38 and then MSVC found many more) --- src/Gui/Tree.cpp | 2523 ++++++++++++++++++++++++---------------------- 1 file changed, 1291 insertions(+), 1232 deletions(-) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index f02f0a5f87..2e2c0f41a5 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -67,7 +67,7 @@ #include "Widgets.h" #include "ExpressionCompleter.h" -FC_LOG_LEVEL_INIT("Tree",false,true,true) +FC_LOG_LEVEL_INIT("Tree", false, true, true) #define _TREE_PRINT(_level,_func,_msg) \ _FC_PRINT(FC_LOG_INSTANCE,_level,_func, '['< TreeWidget::documentPixmap; std::unique_ptr TreeWidget::documentPartialPixmap; -std::set TreeWidget::Instances; -static TreeWidget *_LastSelectedTreeWidget; +std::set TreeWidget::Instances; +static TreeWidget* _LastSelectedTreeWidget; const int TreeWidget::DocumentType = 1000; const int TreeWidget::ObjectType = 1001; bool _DragEventFilter; @@ -113,7 +113,7 @@ void TreeParams::set##_name(_type value) {\ FC_TREEPARAM_DEFS -void TreeParams::OnChange(Base::Subject &, const char* sReason) { +void TreeParams::OnChange(Base::Subject&, const char* sReason) { #undef FC_TREEPARAM_DEF #define FC_TREEPARAM_DEF(_name,_type,_Type,_default) \ @@ -134,7 +134,7 @@ void TreeParams::OnChange(Base::Subject &, const char* sReason) { } void TreeParams::onSyncSelectionChanged() { - if(!TreeParams::Instance()->SyncSelection() || !Gui::Selection().hasSelection()) + if (!TreeParams::Instance()->SyncSelection() || !Gui::Selection().hasSelection()) return; TreeWidget::scrollItemToTop(); } @@ -148,9 +148,9 @@ void TreeParams::onDocumentModeChanged() { App::GetApplication().setActiveDocument(App::GetApplication().getActiveDocument()); } -TreeParams *TreeParams::Instance() { - static TreeParams *instance; - if(!instance) +TreeParams* TreeParams::Instance() { + static TreeParams* instance; + if (!instance) instance = new TreeParams; return instance; } @@ -170,7 +170,7 @@ struct Stats { DEFINE_STATS - void init() { + void init() { #undef DEFINE_STAT #define DEFINE_STAT(_name) \ FC_DURATION_INIT(_name);\ @@ -200,8 +200,8 @@ struct Stats { struct TimingInfo { bool timed = false; FC_TIME_POINT t; - FC_DURATION &d; - TimingInfo(FC_DURATION &d) + FC_DURATION& d; + TimingInfo(FC_DURATION& d) :d(d) { _FC_TIME_INIT(t); @@ -210,9 +210,9 @@ struct TimingInfo { stop(); } void stop() { - if(!timed) { + if (!timed) { timed = true; - FC_DURATION_PLUS(d,t); + FC_DURATION_PLUS(d, t); } } void reset() { @@ -244,10 +244,10 @@ typedef std::set DocumentObjectItems; class Gui::DocumentObjectData { public: - DocumentItem *docItem; + DocumentItem* docItem; DocumentObjectItems items; - ViewProviderDocumentObject *viewObject; - DocumentObjectItem *rootItem; + ViewProviderDocumentObject* viewObject; + DocumentObjectItem* rootItem; std::vector children; std::set childSet; bool removeChildrenFromRoot; @@ -261,16 +261,16 @@ public: Connection connectTool; Connection connectStat; - DocumentObjectData(DocumentItem *docItem, ViewProviderDocumentObject* vpd) - : docItem(docItem), viewObject(vpd),rootItem(0) + DocumentObjectData(DocumentItem* docItem, ViewProviderDocumentObject* vpd) + : docItem(docItem), viewObject(vpd), rootItem(0) { // Setup connections connectIcon = viewObject->signalChangeIcon.connect( - boost::bind(&DocumentObjectData::slotChangeIcon, this)); + boost::bind(&DocumentObjectData::slotChangeIcon, this)); connectTool = viewObject->signalChangeToolTip.connect( - boost::bind(&DocumentObjectData::slotChangeToolTip, this, bp::_1)); + boost::bind(&DocumentObjectData::slotChangeToolTip, this, bp::_1)); connectStat = viewObject->signalChangeStatusTip.connect( - boost::bind(&DocumentObjectData::slotChangeStatusTip, this, bp::_1)); + boost::bind(&DocumentObjectData::slotChangeStatusTip, this, bp::_1)); removeChildrenFromRoot = viewObject->canRemoveChildrenFromRoot(); itemHidden = !viewObject->showInTree(); @@ -278,7 +278,7 @@ public: label2 = viewObject->getObject()->Label2.getValue(); } - const char *getTreeName() const { + const char* getTreeName() const { return docItem->getTreeName(); } @@ -290,28 +290,29 @@ public: bool updateChildren(bool checkVisibility) { auto newChildren = viewObject->claimChildren(); auto obj = viewObject->getObject(); - std::set newSet; + std::set newSet; bool updated = false; for (auto child : newChildren) { auto childVp = docItem->getViewProvider(child); if (!childVp) continue; - if(child && child->getNameInDocument()) { - if(!newSet.insert(child).second) { + if (child && child->getNameInDocument()) { + if (!newSet.insert(child).second) { TREE_WARN("duplicate child item " << obj->getFullName() << '.' << child->getNameInDocument()); - }else if(!childSet.erase(child)) { + } + else if (!childSet.erase(child)) { // this means new child detected updated = true; - if(child->getDocument()==obj->getDocument() && - child->getDocument()==docItem->document()->getDocument()) + if (child->getDocument() == obj->getDocument() && + child->getDocument() == docItem->document()->getDocument()) { - auto &parents = docItem->_ParentMap[child]; - if(parents.insert(obj).second && child->Visibility.getValue()) { + auto& parents = docItem->_ParentMap[child]; + if (parents.insert(obj).second && child->Visibility.getValue()) { bool showable = false; - for(auto parent : parents) { - if(!parent->hasChildElement() - && parent->getLinkedObject(false)==parent) + for (auto parent : parents) { + if (!parent->hasChildElement() + && parent->getLinkedObject(false) == parent) { showable = true; break; @@ -341,12 +342,12 @@ public: } } // We still need to check the order of the children - updated = updated || children!=newChildren; + updated = updated || children != newChildren; children.swap(newChildren); childSet.swap(newSet); - if(updated && checkVisibility) { - for(auto child : children) { + if (updated && checkVisibility) { + for (auto child : children) { auto childVp = docItem->getViewProvider(child); if (childVp && child->getDocument() == obj->getDocument()) childVp->setShowable(docItem->isObjectShowable(child)); @@ -356,9 +357,9 @@ public: } void testStatus(bool resetStatus = false) { - QIcon icon,icon2; - for(auto item : items) - item->testStatus(resetStatus,icon,icon2); + QIcon icon, icon2; + for (auto item : items) + item->testStatus(resetStatus, icon, icon2); } void slotChangeIcon() { @@ -366,34 +367,34 @@ public: } void slotChangeToolTip(const QString& tip) { - for(auto item : items) + for (auto item : items) item->setToolTip(0, tip); } void slotChangeStatusTip(const QString& tip) { - for(auto item : items) + for (auto item : items) item->setStatusTip(0, tip); } }; // --------------------------------------------------------------------------- -class DocumentItem::ExpandInfo: +class DocumentItem::ExpandInfo : public std::unordered_map { public: - void restore(Base::XMLReader &reader) { + void restore(Base::XMLReader& reader) { int level = reader.level(); int count = reader.getAttributeAsInteger("count"); - for(int i=0;irestore(reader); } - reader.readEndElement("Expand",level-1); + reader.readEndElement("Expand", level - 1); } }; @@ -405,21 +406,21 @@ TreeWidgetEditDelegate::TreeWidgetEditDelegate(QObject* parent) } QWidget* TreeWidgetEditDelegate::createEditor( - QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const + QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& index) const { auto ti = static_cast(index.internalPointer()); - if(ti->type()!=TreeWidget::ObjectType || index.column()>1) + if (ti->type() != TreeWidget::ObjectType || index.column() > 1) return 0; - DocumentObjectItem *item = static_cast(ti); - App::DocumentObject *obj = item->object()->getObject(); - auto &prop = index.column()?obj->Label2:obj->Label; + DocumentObjectItem* item = static_cast(ti); + App::DocumentObject* obj = item->object()->getObject(); + auto& prop = index.column() ? obj->Label2 : obj->Label; std::ostringstream str; str << "Change " << obj->getNameInDocument() << '.' << prop.getName(); App::GetApplication().setActiveTransaction(str.str().c_str()); FC_LOG("create editor transaction " << App::GetApplication().getActiveTransaction()); - ExpLineEdit *le = new ExpLineEdit(parent); + ExpLineEdit* le = new ExpLineEdit(parent); le->setFrame(false); le->setReadOnly(prop.isReadOnly()); le->bind(App::ObjectIdentifier(prop)); @@ -429,14 +430,14 @@ QWidget* TreeWidgetEditDelegate::createEditor( // --------------------------------------------------------------------------- -TreeWidget::TreeWidget(const char *name, QWidget* parent) - : QTreeWidget(parent), SelectionObserver(true,0), contextItem(0) +TreeWidget::TreeWidget(const char* name, QWidget* parent) + : QTreeWidget(parent), SelectionObserver(true, 0), contextItem(0) , searchObject(0), searchDoc(0), searchContextDoc(0) , editingItem(0), currentDocItem(0) , myName(name) { Instances.insert(this); - if(!_LastSelectedTreeWidget) + if (!_LastSelectedTreeWidget) _LastSelectedTreeWidget = this; this->setDragEnabled(true); @@ -450,27 +451,27 @@ TreeWidget::TreeWidget(const char *name, QWidget* parent) this->showHiddenAction = new QAction(this); this->showHiddenAction->setCheckable(true); connect(this->showHiddenAction, SIGNAL(triggered()), - this, SLOT(onShowHidden())); + this, SLOT(onShowHidden())); this->hideInTreeAction = new QAction(this); this->hideInTreeAction->setCheckable(true); connect(this->hideInTreeAction, SIGNAL(triggered()), - this, SLOT(onHideInTree())); + this, SLOT(onHideInTree())); this->createGroupAction = new QAction(this); connect(this->createGroupAction, SIGNAL(triggered()), - this, SLOT(onCreateGroup())); + this, SLOT(onCreateGroup())); this->relabelObjectAction = new QAction(this); #ifndef Q_OS_MAC this->relabelObjectAction->setShortcut(Qt::Key_F2); #endif connect(this->relabelObjectAction, SIGNAL(triggered()), - this, SLOT(onRelabelObject())); + this, SLOT(onRelabelObject())); this->finishEditingAction = new QAction(this); connect(this->finishEditingAction, SIGNAL(triggered()), - this, SLOT(onFinishEditing())); + this, SLOT(onFinishEditing())); this->selectDependentsAction = new QAction(this); connect(this->selectDependentsAction, SIGNAL(triggered()), @@ -478,34 +479,34 @@ TreeWidget::TreeWidget(const char *name, QWidget* parent) this->closeDocAction = new QAction(this); connect(this->closeDocAction, SIGNAL(triggered()), - this, SLOT(onCloseDoc())); + this, SLOT(onCloseDoc())); this->reloadDocAction = new QAction(this); connect(this->reloadDocAction, SIGNAL(triggered()), - this, SLOT(onReloadDoc())); + this, SLOT(onReloadDoc())); this->skipRecomputeAction = new QAction(this); this->skipRecomputeAction->setCheckable(true); connect(this->skipRecomputeAction, SIGNAL(toggled(bool)), - this, SLOT(onSkipRecompute(bool))); + this, SLOT(onSkipRecompute(bool))); this->allowPartialRecomputeAction = new QAction(this); this->allowPartialRecomputeAction->setCheckable(true); connect(this->allowPartialRecomputeAction, SIGNAL(toggled(bool)), - this, SLOT(onAllowPartialRecompute(bool))); + this, SLOT(onAllowPartialRecompute(bool))); this->markRecomputeAction = new QAction(this); connect(this->markRecomputeAction, SIGNAL(triggered()), - this, SLOT(onMarkRecompute())); + this, SLOT(onMarkRecompute())); this->recomputeObjectAction = new QAction(this); connect(this->recomputeObjectAction, SIGNAL(triggered()), - this, SLOT(onRecomputeObject())); + this, SLOT(onRecomputeObject())); this->searchObjectsAction = new QAction(this); this->searchObjectsAction->setText(tr("Search...")); this->searchObjectsAction->setStatusTip(tr("Search for objects")); connect(this->searchObjectsAction, SIGNAL(triggered()), - this, SLOT(onSearchObjects())); + this, SLOT(onSearchObjects())); // Setup connections connectNewDocument = Application::Instance->signalNewDocument.connect(boost::bind(&TreeWidget::slotNewDocument, this, bp::_1, bp::_2)); @@ -519,7 +520,7 @@ TreeWidget::TreeWidget(const char *name, QWidget* parent) // change, not view provider's own property, which is what the signal below // for connectChangedViewObj = Application::Instance->signalChangedObject.connect( - boost::bind(&TreeWidget::slotChangedViewObject, this, bp::_1, bp::_2)); + boost::bind(&TreeWidget::slotChangedViewObject, this, bp::_1, bp::_2)); // make sure to show a horizontal scrollbar if needed this->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); @@ -544,28 +545,28 @@ TreeWidget::TreeWidget(const char *name, QWidget* parent) this->selectTimer->setSingleShot(true); connect(this->statusTimer, SIGNAL(timeout()), - this, SLOT(onUpdateStatus())); + this, SLOT(onUpdateStatus())); connect(this, SIGNAL(itemEntered(QTreeWidgetItem*, int)), - this, SLOT(onItemEntered(QTreeWidgetItem*))); + this, SLOT(onItemEntered(QTreeWidgetItem*))); connect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)), - this, SLOT(onItemCollapsed(QTreeWidgetItem*))); + this, SLOT(onItemCollapsed(QTreeWidgetItem*))); connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), - this, SLOT(onItemExpanded(QTreeWidgetItem*))); + this, SLOT(onItemExpanded(QTreeWidgetItem*))); connect(this, SIGNAL(itemSelectionChanged()), - this, SLOT(onItemSelectionChanged())); + this, SLOT(onItemSelectionChanged())); connect(this, SIGNAL(itemChanged(QTreeWidgetItem*, int)), - this, SLOT(onItemChanged(QTreeWidgetItem*, int))); + this, SLOT(onItemChanged(QTreeWidgetItem*, int))); connect(this->preselectTimer, SIGNAL(timeout()), - this, SLOT(onPreSelectTimer())); + this, SLOT(onPreSelectTimer())); connect(this->selectTimer, SIGNAL(timeout()), - this, SLOT(onSelectTimer())); + this, SLOT(onSelectTimer())); preselectTime.start(); setupText(); - if(!documentPixmap) { + if (!documentPixmap) { documentPixmap.reset(new QPixmap(Gui::BitmapFactory().pixmap("Document"))); QIcon icon(*documentPixmap); - documentPartialPixmap.reset(new QPixmap(icon.pixmap(documentPixmap->size(),QIcon::Disabled))); + documentPartialPixmap.reset(new QPixmap(icon.pixmap(documentPixmap->size(), QIcon::Disabled))); } } @@ -579,113 +580,115 @@ TreeWidget::~TreeWidget() connectShowHidden.disconnect(); connectChangedViewObj.disconnect(); Instances.erase(this); - if(_LastSelectedTreeWidget == this) + if (_LastSelectedTreeWidget == this) _LastSelectedTreeWidget = 0; } -const char *TreeWidget::getTreeName() const { +const char* TreeWidget::getTreeName() const { return myName.c_str(); } // reimpelement to select only objects in the active document void TreeWidget::selectAll() { auto gdoc = Application::Instance->getDocument( - App::GetApplication().getActiveDocument()); - if(!gdoc) + App::GetApplication().getActiveDocument()); + if (!gdoc) return; auto itDoc = DocumentMap.find(gdoc); - if(itDoc == DocumentMap.end()) + if (itDoc == DocumentMap.end()) return; - if(TreeParams::Instance()->RecordSelection()) + if (TreeParams::Instance()->RecordSelection()) Gui::Selection().selStackPush(); Gui::Selection().clearSelection(); - Gui::Selection().setSelection(gdoc->getDocument()->getName(),gdoc->getDocument()->getObjects()); + Gui::Selection().setSelection(gdoc->getDocument()->getName(), gdoc->getDocument()->getObjects()); } -bool TreeWidget::isObjectShowable(App::DocumentObject *obj) { - if(!obj || !obj->getNameInDocument()) +bool TreeWidget::isObjectShowable(App::DocumentObject* obj) { + if (!obj || !obj->getNameInDocument()) return true; - Gui::Document *doc = Application::Instance->getDocument(obj->getDocument()); - if(!doc) + Gui::Document* doc = Application::Instance->getDocument(obj->getDocument()); + if (!doc) return true; - if(Instances.empty()) + if (Instances.empty()) return true; auto tree = *Instances.begin(); auto it = tree->DocumentMap.find(doc); - if(it != tree->DocumentMap.end()) + if (it != tree->DocumentMap.end()) return it->second->isObjectShowable(obj); return true; } static bool _DisableCheckTopParent; -void TreeWidget::checkTopParent(App::DocumentObject *&obj, std::string &subname) { - if(_DisableCheckTopParent) +void TreeWidget::checkTopParent(App::DocumentObject*& obj, std::string& subname) { + if (_DisableCheckTopParent) return; - if(Instances.size() && obj && obj->getNameInDocument()) { + if (Instances.size() && obj && obj->getNameInDocument()) { auto tree = *Instances.begin(); auto it = tree->DocumentMap.find(Application::Instance->getDocument(obj->getDocument())); - if(it != tree->DocumentMap.end()) { - if(tree->statusTimer->isActive()) { + if (it != tree->DocumentMap.end()) { + if (tree->statusTimer->isActive()) { bool locked = tree->blockConnection(true); tree->_updateStatus(false); tree->blockConnection(locked); } - auto parent = it->second->getTopParent(obj,subname); - if(parent) + auto parent = it->second->getTopParent(obj, subname); + if (parent) obj = parent; } } } void TreeWidget::resetItemSearch() { - if(!searchObject) + if (!searchObject) return; auto it = ObjectTable.find(searchObject); - if(it != ObjectTable.end()) { - for(auto &data : it->second) { - if(!data) + if (it != ObjectTable.end()) { + for (auto& data : it->second) { + if (!data) continue; - for(auto item : data->items) + for (auto item : data->items) static_cast(item)->restoreBackground(); } } searchObject = 0; } -void TreeWidget::startItemSearch(QLineEdit *edit) { +void TreeWidget::startItemSearch(QLineEdit* edit) { resetItemSearch(); searchDoc = 0; searchContextDoc = 0; auto sels = selectedItems(); - if(sels.size() == 1) { - if(sels.front()->type() == DocumentType) { + if (sels.size() == 1) { + if (sels.front()->type() == DocumentType) { searchDoc = static_cast(sels.front())->document(); - } else if(sels.front()->type() == ObjectType) { + } + else if (sels.front()->type() == ObjectType) { auto item = static_cast(sels.front()); searchDoc = item->object()->getDocument(); searchContextDoc = item->getOwnerDocument()->document(); } - }else + } + else searchDoc = Application::Instance->activeDocument(); - App::DocumentObject *obj = 0; - if(searchContextDoc && searchContextDoc->getDocument()->getObjects().size()) + App::DocumentObject* obj = 0; + if (searchContextDoc && searchContextDoc->getDocument()->getObjects().size()) obj = searchContextDoc->getDocument()->getObjects().front(); - else if(searchDoc && searchDoc->getDocument()->getObjects().size()) + else if (searchDoc && searchDoc->getDocument()->getObjects().size()) obj = searchDoc->getDocument()->getObjects().front(); - if(obj) + if (obj) static_cast(edit)->setDocumentObject(obj); } -void TreeWidget::itemSearch(const QString &text, bool select) { +void TreeWidget::itemSearch(const QString& text, bool select) { resetItemSearch(); auto docItem = getDocumentItem(searchDoc); - if(!docItem) { + if (!docItem) { docItem = getDocumentItem(Application::Instance->activeDocument()); - if(!docItem) { + if (!docItem) { FC_TRACE("item search no document"); resetItemSearch(); return; @@ -693,122 +696,125 @@ void TreeWidget::itemSearch(const QString &text, bool select) { } auto doc = docItem->document()->getDocument(); - const auto &objs = doc->getObjects(); - if(objs.empty()) { + const auto& objs = doc->getObjects(); + if (objs.empty()) { FC_TRACE("item search no objects"); return; } std::string txt(text.toUtf8().constData()); try { - if(txt.empty()) + if (txt.empty()) return; - if(txt.find("<<") == std::string::npos) { + if (txt.find("<<") == std::string::npos) { auto pos = txt.find('.'); - if(pos==std::string::npos) + if (pos == std::string::npos) txt += '.'; - else if(pos!=txt.size()-1) { - txt.insert(pos+1,"<<"); - if(txt.back()!='.') + else if (pos != txt.size() - 1) { + txt.insert(pos + 1, "<<"); + if (txt.back() != '.') txt += '.'; txt += ">>."; } - }else if(txt.back() != '.') + } + else if (txt.back() != '.') txt += '.'; txt += "_self"; - auto path = App::ObjectIdentifier::parse(objs.front(),txt); - if(path.getPropertyName() != "_self") { + auto path = App::ObjectIdentifier::parse(objs.front(), txt); + if (path.getPropertyName() != "_self") { FC_TRACE("Object " << txt << " not found in " << doc->getName()); return; } auto obj = path.getDocumentObject(); - if(!obj) { + if (!obj) { FC_TRACE("Object " << txt << " not found in " << doc->getName()); return; } std::string subname = path.getSubObjectName(); - App::DocumentObject *parent = 0; - if(searchContextDoc) { + App::DocumentObject* parent = 0; + if (searchContextDoc) { auto it = DocumentMap.find(searchContextDoc); - if(it!=DocumentMap.end()) { - parent = it->second->getTopParent(obj,subname); - if(parent) { + if (it != DocumentMap.end()) { + parent = it->second->getTopParent(obj, subname); + if (parent) { obj = parent; docItem = it->second; doc = docItem->document()->getDocument(); } } } - if(!parent) { - parent = docItem->getTopParent(obj,subname); - while(!parent) { - if(docItem->document()->getDocument() == obj->getDocument()) { + if (!parent) { + parent = docItem->getTopParent(obj, subname); + while (!parent) { + if (docItem->document()->getDocument() == obj->getDocument()) { // this shouldn't happen FC_LOG("Object " << txt << " not found in " << doc->getName()); return; } auto it = DocumentMap.find(Application::Instance->getDocument(obj->getDocument())); - if(it==DocumentMap.end()) + if (it == DocumentMap.end()) return; docItem = it->second; - parent = docItem->getTopParent(obj,subname); + parent = docItem->getTopParent(obj, subname); } obj = parent; } - auto item = docItem->findItemByObject(true,obj,subname.c_str()); - if(!item) { + auto item = docItem->findItemByObject(true, obj, subname.c_str()); + if (!item) { FC_TRACE("item " << txt << " not found in " << doc->getName()); return; } scrollToItem(item); Selection().setPreselect(obj->getDocument()->getName(), - obj->getNameInDocument(), subname.c_str(),0,0,0,2); - if(select) { + obj->getNameInDocument(), subname.c_str(), 0, 0, 0, 2); + if (select) { Gui::Selection().selStackPush(); Gui::Selection().clearSelection(); Gui::Selection().addSelection(obj->getDocument()->getName(), - obj->getNameInDocument(),subname.c_str()); + obj->getNameInDocument(), subname.c_str()); Gui::Selection().selStackPush(); - }else{ + } + else { searchObject = item->object()->getObject(); item->setBackground(0, QColor(255, 255, 0, 100)); } FC_TRACE("found item " << txt); - } catch(...) + } + catch (...) { FC_TRACE("item " << txt << " search exception in " << doc->getName()); } } -Gui::Document *TreeWidget::selectedDocument() { - for(auto tree : Instances) { - if(!tree->isVisible()) +Gui::Document* TreeWidget::selectedDocument() { + for (auto tree : Instances) { + if (!tree->isVisible()) continue; auto sels = tree->selectedItems(); - if(sels.size()==1 && sels[0]->type()==DocumentType) + if (sels.size() == 1 && sels[0]->type() == DocumentType) return static_cast(sels[0])->document(); } return 0; } void TreeWidget::updateStatus(bool delay) { - for(auto tree : Instances) + for (auto tree : Instances) tree->_updateStatus(delay); } void TreeWidget::_updateStatus(bool delay) { - if(!delay) { - if(ChangedObjects.size() || NewObjects.size()) + if (!delay) { + if (ChangedObjects.size() || NewObjects.size()) onUpdateStatus(); return; } int timeout = TreeParams::Instance()->StatusTimeout(); - if (timeout<0) + if (timeout < 0) timeout = 1; FC_LOG("delay update status"); statusTimer->start(timeout); } -void TreeWidget::contextMenuEvent (QContextMenuEvent * e) +void TreeWidget::contextMenuEvent(QContextMenuEvent* e) { // ask workbenches and view provider, ... MenuItem view; @@ -824,7 +830,7 @@ void TreeWidget::contextMenuEvent (QContextMenuEvent * e) QActionGroup subMenuGroup(&subMenu); subMenuGroup.setExclusive(true); connect(&subMenuGroup, SIGNAL(triggered(QAction*)), - this, SLOT(onActivateDocument(QAction*))); + this, SLOT(onActivateDocument(QAction*))); MenuManager::getInstance()->setupContextMenu(&view, contextMenu); // get the current item @@ -838,11 +844,11 @@ void TreeWidget::contextMenuEvent (QContextMenuEvent * e) contextMenu.addAction(this->showHiddenAction); contextMenu.addAction(this->searchObjectsAction); contextMenu.addAction(this->closeDocAction); - if(doc->testStatus(App::Document::PartialDoc)) + if (doc->testStatus(App::Document::PartialDoc)) contextMenu.addAction(this->reloadDocAction); else { - for(auto d : doc->getDependentDocuments()) { - if(d->testStatus(App::Document::PartialDoc)) { + for (auto d : doc->getDependentDocuments()) { + if (d->testStatus(App::Document::PartialDoc)) { contextMenu.addAction(this->reloadDocAction); break; } @@ -851,7 +857,7 @@ void TreeWidget::contextMenuEvent (QContextMenuEvent * e) this->skipRecomputeAction->setChecked(doc->testStatus(App::Document::SkipRecompute)); contextMenu.addAction(this->skipRecomputeAction); this->allowPartialRecomputeAction->setChecked(doc->testStatus(App::Document::AllowPartialRecompute)); - if(doc->testStatus(App::Document::SkipRecompute)) + if (doc->testStatus(App::Document::SkipRecompute)) contextMenu.addAction(this->allowPartialRecomputeAction); contextMenu.addAction(this->markRecomputeAction); contextMenu.addAction(this->createGroupAction); @@ -873,7 +879,7 @@ void TreeWidget::contextMenuEvent (QContextMenuEvent * e) break; } } - + showHiddenAction->setChecked(doc->ShowHidden.getValue()); contextMenu.addAction(this->showHiddenAction); @@ -905,7 +911,7 @@ void TreeWidget::contextMenuEvent (QContextMenuEvent * e) if (!editAct.isEmpty()) { QAction* topact = contextMenu.actions().front(); for (QList::iterator it = editAct.begin(); it != editAct.end(); ++it) - contextMenu.insertAction(topact,*it); + contextMenu.insertAction(topact, *it); QAction* first = editAct.front(); contextMenu.setDefaultAction(first); if (objitem->object()->isEditing()) @@ -941,18 +947,21 @@ void TreeWidget::contextMenuEvent (QContextMenuEvent * e) if (contextMenu.actions().count() > 0) { try { contextMenu.exec(QCursor::pos()); - } catch (Base::Exception &e) { + } + catch (Base::Exception& e) { e.ReportException(); - } catch (std::exception &e) { + } + catch (std::exception& e) { FC_ERR("C++ exception: " << e.what()); - } catch (...) { + } + catch (...) { FC_ERR("Unknown exception"); } contextItem = 0; } } -void TreeWidget::hideEvent(QHideEvent *ev) { +void TreeWidget::hideEvent(QHideEvent* ev) { // No longer required. Visibility is now handled inside onUpdateStatus() by // UpdateDisabler. #if 0 @@ -963,14 +972,14 @@ void TreeWidget::hideEvent(QHideEvent *ev) { QTreeWidget::hideEvent(ev); } -void TreeWidget::showEvent(QShowEvent *ev) { +void TreeWidget::showEvent(QShowEvent* ev) { // No longer required. Visibility is now handled inside onUpdateStatus() by // UpdateDisabler. #if 0 TREE_TRACE("attaching selection observer"); this->attachSelection(); int timeout = TreeParams::Instance()->SelectionTimeout(); - if(timeout<=0) + if (timeout <= 0) timeout = 1; selectTimer->start(timeout); _updateStatus(); @@ -986,8 +995,8 @@ void TreeWidget::onCreateGroup() DocumentItem* docitem = static_cast(this->contextItem); App::Document* doc = docitem->document()->getDocument(); QString cmd = QString::fromLatin1("App.getDocument(\"%1\").addObject" - "(\"App::DocumentObjectGroup\",\"%2\")") - .arg(QString::fromLatin1(doc->getName()), name); + "(\"App::DocumentObjectGroup\",\"%2\")") + .arg(QString::fromLatin1(doc->getName()), name); Gui::Command::runCommand(Gui::Command::App, cmd.toUtf8()); } else if (this->contextItem->type() == ObjectType) { @@ -996,10 +1005,10 @@ void TreeWidget::onCreateGroup() App::DocumentObject* obj = objitem->object()->getObject(); App::Document* doc = obj->getDocument(); QString cmd = QString::fromLatin1("App.getDocument(\"%1\").getObject(\"%2\")" - ".newObject(\"App::DocumentObjectGroup\",\"%3\")") - .arg(QString::fromLatin1(doc->getName()), - QString::fromLatin1(obj->getNameInDocument()), - name); + ".newObject(\"App::DocumentObjectGroup\",\"%3\")") + .arg(QString::fromLatin1(doc->getName()), + QString::fromLatin1(obj->getNameInDocument()), + name); Gui::Command::runCommand(Gui::Command::App, cmd.toUtf8()); } } @@ -1024,7 +1033,7 @@ void TreeWidget::onStartEditing() if (!obj || !obj->getNameInDocument()) return; auto doc = const_cast(objitem->getOwnerDocument()->document()); - MDIView *view = doc->getActiveView(); + MDIView* view = doc->getActiveView(); if (view) getMainWindow()->setActiveWindow(view); // Always open a transaction here doesn't make much sense because: @@ -1040,7 +1049,7 @@ void TreeWidget::onStartEditing() if (!ok) doc->abortCommand(); #else editingItem = objitem; - if(!doc->setEdit(objitem->object(), edit)) + if (!doc->setEdit(objitem->object(), edit)) editingItem = 0; #endif } @@ -1173,99 +1182,99 @@ void TreeWidget::onMarkRecompute() void TreeWidget::onRecomputeObject() { std::vector objs; - for(auto ti : selectedItems()) { + for (auto ti : selectedItems()) { if (ti->type() == ObjectType) { DocumentObjectItem* objitem = static_cast(ti); objs.push_back(objitem->object()->getObject()); objs.back()->enforceRecompute(); } } - if(objs.empty()) + if (objs.empty()) return; App::AutoTransaction committer("Recompute object"); - objs.front()->getDocument()->recompute(objs,true); + objs.front()->getDocument()->recompute(objs, true); } -DocumentItem *TreeWidget::getDocumentItem(const Gui::Document *doc) const { +DocumentItem* TreeWidget::getDocumentItem(const Gui::Document* doc) const { auto it = DocumentMap.find(doc); - if(it != DocumentMap.end()) + if (it != DocumentMap.end()) return it->second; return 0; } -void TreeWidget::selectAllInstances(const ViewProviderDocumentObject &vpd) { - if(!isConnectionAttached()) +void TreeWidget::selectAllInstances(const ViewProviderDocumentObject& vpd) { + if (!isConnectionAttached()) return; - if(selectTimer->isActive()) + if (selectTimer->isActive()) onSelectTimer(); else _updateStatus(false); - for(const auto &v : DocumentMap) + for (const auto& v : DocumentMap) v.second->selectAllInstances(vpd); } -TreeWidget *TreeWidget::instance() { +TreeWidget* TreeWidget::instance() { auto res = _LastSelectedTreeWidget; - if(res && res->isVisible()) + if (res && res->isVisible()) return res; - for(auto inst : Instances) { - if(!res) res = inst; - if(inst->isVisible()) + for (auto inst : Instances) { + if (!res) res = inst; + if (inst->isVisible()) return inst; } return res; } -std::vector TreeWidget::getSelection(App::Document *doc) +std::vector TreeWidget::getSelection(App::Document* doc) { std::vector ret; - TreeWidget *tree = instance(); - if(!tree || !tree->isConnectionAttached()) { - for(auto pTree : Instances) - if(pTree->isConnectionAttached()) { + TreeWidget* tree = instance(); + if (!tree || !tree->isConnectionAttached()) { + for (auto pTree : Instances) + if (pTree->isConnectionAttached()) { tree = pTree; break; } } - if(!tree) return ret; + if (!tree) return ret; - if(tree->selectTimer->isActive()) + if (tree->selectTimer->isActive()) tree->onSelectTimer(); else tree->_updateStatus(false); - for(auto ti : tree->selectedItems()) { - if(ti->type() != ObjectType) continue; + for (auto ti : tree->selectedItems()) { + if (ti->type() != ObjectType) continue; auto item = static_cast(ti); auto vp = item->object(); auto obj = vp->getObject(); - if(!obj || !obj->getNameInDocument()) { + if (!obj || !obj->getNameInDocument()) { FC_WARN("skip invalid object"); continue; } - if(doc && obj->getDocument()!=doc) { + if (doc && obj->getDocument() != doc) { FC_LOG("skip objects not from current document"); continue; } - ViewProviderDocumentObject *parentVp = 0; + ViewProviderDocumentObject* parentVp = 0; auto parent = item->getParentItem(); - if(parent) { + if (parent) { parentVp = parent->object(); - if(!parentVp->getObject()->getNameInDocument()) { + if (!parentVp->getObject()->getNameInDocument()) { FC_WARN("skip '" << obj->getFullName() << "' with invalid parent"); continue; } } ret.emplace_back(); - auto &sel = ret.back(); + auto& sel = ret.back(); sel.topParent = 0; std::ostringstream ss; - item->getSubName(ss,sel.topParent); - if(!sel.topParent) + item->getSubName(ss, sel.topParent); + if (!sel.topParent) sel.topParent = obj; else ss << obj->getNameInDocument() << '.'; @@ -1276,33 +1285,33 @@ std::vector TreeWidget::getSelection(App::Document *doc) return ret; } -void TreeWidget::selectAllLinks(App::DocumentObject *obj) { - if(!isConnectionAttached()) +void TreeWidget::selectAllLinks(App::DocumentObject* obj) { + if (!isConnectionAttached()) return; - if(!obj || !obj->getNameInDocument()) { + if (!obj || !obj->getNameInDocument()) { TREE_ERR("invalid object"); return; } - if(selectTimer->isActive()) + if (selectTimer->isActive()) onSelectTimer(); else _updateStatus(false); - for(auto link: App::GetApplication().getLinksTo(obj,App::GetLinkRecursive)) + for (auto link : App::GetApplication().getLinksTo(obj, App::GetLinkRecursive)) { - if(!link || !link->getNameInDocument()) { + if (!link || !link->getNameInDocument()) { TREE_ERR("invalid linked object"); continue; } auto vp = dynamic_cast( - Application::Instance->getViewProvider(link)); - if(!vp) { + Application::Instance->getViewProvider(link)); + if (!vp) { TREE_ERR("invalid view provider of the linked object"); continue; } - for(auto &v : DocumentMap) + for (auto& v : DocumentMap) v.second->selectAllInstances(*vp); } } @@ -1318,40 +1327,40 @@ void TreeWidget::onActivateDocument(QAction* active) QByteArray docname = active->data().toByteArray(); Gui::Document* doc = Application::Instance->getDocument((const char*)docname); if (doc && !doc->setActiveView()) - doc->setActiveView(0,View3DInventor::getClassTypeId()); + doc->setActiveView(0, View3DInventor::getClassTypeId()); } -Qt::DropActions TreeWidget::supportedDropActions () const +Qt::DropActions TreeWidget::supportedDropActions() const { return Qt::LinkAction | Qt::CopyAction | Qt::MoveAction; } -bool TreeWidget::event(QEvent *e) +bool TreeWidget::event(QEvent* e) { #if 0 if (e->type() == QEvent::ShortcutOverride) { - QKeyEvent* ke = static_cast(e); + QKeyEvent* ke = static_cast(e); switch (ke->key()) { - case Qt::Key_Delete: - ke->accept(); + case Qt::Key_Delete: + ke->accept(); } } #endif return QTreeWidget::event(e); } -bool TreeWidget::eventFilter(QObject *, QEvent *ev) { +bool TreeWidget::eventFilter(QObject*, QEvent* ev) { switch (ev->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: { - QKeyEvent *ke = static_cast(ev); + QKeyEvent* ke = static_cast(ev); if (ke->key() != Qt::Key_Escape) { // Qt 5 only recheck key modifier on mouse move, so generate a fake // event to trigger drag cursor change - QMouseEvent *mouseEvent = new QMouseEvent(QEvent::MouseMove, - mapFromGlobal(QCursor::pos()), QCursor::pos(), Qt::NoButton, - QApplication::mouseButtons(), QApplication::queryKeyboardModifiers()); - QApplication::postEvent(this,mouseEvent); + QMouseEvent* mouseEvent = new QMouseEvent(QEvent::MouseMove, + mapFromGlobal(QCursor::pos()), QCursor::pos(), Qt::NoButton, + QApplication::mouseButtons(), QApplication::queryKeyboardModifiers()); + QApplication::postEvent(this, mouseEvent); } break; } @@ -1361,59 +1370,65 @@ bool TreeWidget::eventFilter(QObject *, QEvent *ev) { return false; } -void TreeWidget::keyPressEvent(QKeyEvent *event) +void TreeWidget::keyPressEvent(QKeyEvent* event) { #if 0 if (event && event->matches(QKeySequence::Delete)) { event->ignore(); } #endif - if(event->matches(QKeySequence::Find)) { + if (event->matches(QKeySequence::Find)) { event->accept(); onSearchObjects(); return; - }else if(event->modifiers() == Qt::AltModifier) { - if(event->key() == Qt::Key_Left) { - for(auto &item: selectedItems()) { + } + else if (event->modifiers() == Qt::AltModifier) { + if (event->key() == Qt::Key_Left) { + for (auto& item : selectedItems()) { item->setExpanded(false); } event->accept(); return; - }else if(event->key() == Qt::Key_Right) { - for(auto &item: selectedItems()) { + } + else if (event->key() == Qt::Key_Right) { + for (auto& item : selectedItems()) { item->setExpanded(true); } event->accept(); return; - }else if(event->key() == Qt::Key_Up) { - for(auto &item: selectedItems()) { + } + else if (event->key() == Qt::Key_Up) { + for (auto& item : selectedItems()) { item->setExpanded(true); - for (auto &child: childrenOfItem(*item)) { + for (auto& child : childrenOfItem(*item)) { child->setExpanded(false); } } event->accept(); return; - }else if(event->key() == Qt::Key_Down) { - for(auto &item: selectedItems()) { + } + else if (event->key() == Qt::Key_Down) { + for (auto& item : selectedItems()) { item->setExpanded(true); - for (auto &child: childrenOfItem(*item)) { + for (auto& child : childrenOfItem(*item)) { child->setExpanded(true); } } event->accept(); return; } - }else if(event->key() == Qt::Key_Left) { + } + else if (event->key() == Qt::Key_Left) { auto index = currentIndex(); - if(index.column()==1) { + if (index.column() == 1) { setCurrentIndex(model()->index(index.row(), 0, index.parent())); event->accept(); return; } - }else if(event->key() == Qt::Key_Right) { + } + else if (event->key() == Qt::Key_Right) { auto index = currentIndex(); - if(index.column()==0) { + if (index.column() == 0) { setCurrentIndex(model()->index(index.row(), 1, index.parent())); event->accept(); return; @@ -1422,7 +1437,7 @@ void TreeWidget::keyPressEvent(QKeyEvent *event) QTreeWidget::keyPressEvent(event); } -void TreeWidget::mouseDoubleClickEvent (QMouseEvent * event) +void TreeWidget::mouseDoubleClickEvent(QMouseEvent* event) { QTreeWidgetItem* item = itemAt(event->pos()); if (!item) return; @@ -1432,13 +1447,13 @@ void TreeWidget::mouseDoubleClickEvent (QMouseEvent * event) //QTreeWidget::mouseDoubleClickEvent(event); Gui::Document* doc = static_cast(item)->document(); if (!doc) return; - if(doc->getDocument()->testStatus(App::Document::PartialDoc)) { + if (doc->getDocument()->testStatus(App::Document::PartialDoc)) { contextItem = item; onReloadDoc(); return; } - if(!doc->setActiveView()) - doc->setActiveView(0,View3DInventor::getClassTypeId()); + if (!doc->setActiveView()) + doc->setActiveView(0, View3DInventor::getClassTypeId()); } else if (item->type() == TreeWidget::ObjectType) { DocumentObjectItem* objitem = static_cast(item); @@ -1473,19 +1488,22 @@ void TreeWidget::mouseDoubleClickEvent (QMouseEvent * event) manager->addLine(MacroManager::Gui, ss.str().c_str()); } } - } catch (Base::Exception &e) { + } + catch (Base::Exception& e) { e.ReportException(); - } catch (std::exception &e) { + } + catch (std::exception& e) { FC_ERR("C++ exception: " << e.what()); - } catch (...) { + } + catch (...) { FC_ERR("Unknown exception"); } } void TreeWidget::startDragging() { - if(state() != NoState) + if (state() != NoState) return; - if(selectedItems().empty()) + if (selectedItems().empty()) return; setState(DraggingState); @@ -1497,21 +1515,21 @@ void TreeWidget::startDragging() { void TreeWidget::startDrag(Qt::DropActions supportedActions) { QTreeWidget::startDrag(supportedActions); - if(_DragEventFilter) { + if (_DragEventFilter) { _DragEventFilter = false; qApp->removeEventFilter(this); } } -QMimeData * TreeWidget::mimeData (const QList items) const +QMimeData* TreeWidget::mimeData(const QList items) const { #if 0 // all selected items must reference an object from the same document - App::Document* doc=0; - for (QList::ConstIterator it = items.begin(); it != items.end(); ++it) { + App::Document* doc = 0; + for (QList::ConstIterator it = items.begin(); it != items.end(); ++it) { if ((*it)->type() != TreeWidget::ObjectType) return 0; - App::DocumentObject* obj = static_cast(*it)->object()->getObject(); + App::DocumentObject* obj = static_cast(*it)->object()->getObject(); if (!doc) doc = obj->getDocument(); else if (doc != obj->getDocument()) @@ -1521,29 +1539,29 @@ QMimeData * TreeWidget::mimeData (const QList items) const return QTreeWidget::mimeData(items); } -bool TreeWidget::dropMimeData(QTreeWidgetItem *parent, int index, - const QMimeData *data, Qt::DropAction action) +bool TreeWidget::dropMimeData(QTreeWidgetItem* parent, int index, + const QMimeData* data, Qt::DropAction action) { return QTreeWidget::dropMimeData(parent, index, data, action); } -void TreeWidget::dragEnterEvent(QDragEnterEvent * event) +void TreeWidget::dragEnterEvent(QDragEnterEvent* event) { QTreeWidget::dragEnterEvent(event); } -void TreeWidget::dragLeaveEvent(QDragLeaveEvent * event) +void TreeWidget::dragLeaveEvent(QDragLeaveEvent* event) { QTreeWidget::dragLeaveEvent(event); } -void TreeWidget::dragMoveEvent(QDragMoveEvent *event) +void TreeWidget::dragMoveEvent(QDragMoveEvent* event) { // Qt5 does not change drag cursor in response to modifier key press, // because QDrag installs a event filter that eats up key event. We install // a filter after Qt and generate fake mouse move event in response to key // press event, which triggers QDrag to update its cursor - if(!_DragEventFilter) { + if (!_DragEventFilter) { _DragEventFilter = true; qApp->installEventFilter(this); } @@ -1560,9 +1578,9 @@ void TreeWidget::dragMoveEvent(QDragMoveEvent *event) } else if (targetItem->type() == TreeWidget::DocumentType) { leaveEvent(0); - if(modifier== Qt::ControlModifier) + if (modifier == Qt::ControlModifier) event->setDropAction(Qt::CopyAction); - else if(modifier== Qt::AltModifier) + else if (modifier == Qt::AltModifier) event->setDropAction(Qt::LinkAction); else event->setDropAction(Qt::MoveAction); @@ -1576,23 +1594,23 @@ void TreeWidget::dragMoveEvent(QDragMoveEvent *event) try { auto items = selectedItems(); - if(modifier == Qt::ControlModifier) + if (modifier == Qt::ControlModifier) event->setDropAction(Qt::CopyAction); - else if(modifier== Qt::AltModifier && items.size()==1) + else if (modifier == Qt::AltModifier && items.size() == 1) event->setDropAction(Qt::LinkAction); else event->setDropAction(Qt::MoveAction); auto da = event->dropAction(); - bool dropOnly = da==Qt::CopyAction || da==Qt::MoveAction; + bool dropOnly = da == Qt::CopyAction || da == Qt::MoveAction; - if (da!=Qt::LinkAction && !vp->canDropObjects()) { - if(!(event->possibleActions() & Qt::LinkAction) || items.size()!=1) { + if (da != Qt::LinkAction && !vp->canDropObjects()) { + if (!(event->possibleActions() & Qt::LinkAction) || items.size() != 1) { TREE_TRACE("cannot drop"); event->ignore(); return; } } - for(auto ti : items) { + for (auto ti : items) { if (ti->type() != TreeWidget::ObjectType) { TREE_TRACE("cannot drop"); event->ignore(); @@ -1602,14 +1620,14 @@ void TreeWidget::dragMoveEvent(QDragMoveEvent *event) auto obj = item->object()->getObject(); - if(!dropOnly && !vp->canDragAndDropObject(obj)) { + if (!dropOnly && !vp->canDragAndDropObject(obj)) { // check if items can be dragged auto parentItem = item->getParentItem(); - if(parentItem - && (!parentItem->object()->canDragObjects() - || !parentItem->object()->canDragObject(item->object()->getObject()))) + if (parentItem + && (!parentItem->object()->canDragObjects() + || !parentItem->object()->canDragObject(item->object()->getObject()))) { - if(!(event->possibleActions() & Qt::CopyAction)) { + if (!(event->possibleActions() & Qt::CopyAction)) { TREE_TRACE("Cannot drag object"); event->ignore(); return; @@ -1619,18 +1637,18 @@ void TreeWidget::dragMoveEvent(QDragMoveEvent *event) } std::ostringstream str; - auto owner = item->getRelativeParent(str,targetItemObj); + auto owner = item->getRelativeParent(str, targetItemObj); auto subname = str.str(); // let the view provider decide to accept the object or ignore it - if (da!=Qt::LinkAction && !vp->canDropObjectEx(obj,owner,subname.c_str(), item->mySubs)) { - if(event->possibleActions() & Qt::LinkAction) { - if(items.size()>1) { + if (da != Qt::LinkAction && !vp->canDropObjectEx(obj, owner, subname.c_str(), item->mySubs)) { + if (event->possibleActions() & Qt::LinkAction) { + if (items.size() > 1) { TREE_TRACE("Cannot replace with more than one object"); event->ignore(); return; } - if(!targetItemObj->getParentItem()) { + if (!targetItemObj->getParentItem()) { TREE_TRACE("Cannot replace without parent"); event->ignore(); return; @@ -1640,18 +1658,21 @@ void TreeWidget::dragMoveEvent(QDragMoveEvent *event) } TREE_TRACE("cannot drop " << obj->getFullName() << ' ' - << (owner?owner->getFullName():"") << '.' << subname); + << (owner ? owner->getFullName() : "") << '.' << subname); event->ignore(); return; } } - } catch (Base::Exception &e){ + } + catch (Base::Exception& e) { e.ReportException(); event->ignore(); - } catch (std::exception &e) { + } + catch (std::exception& e) { FC_ERR("C++ exception: " << e.what()); event->ignore(); - } catch (...) { + } + catch (...) { FC_ERR("Unknown exception"); event->ignore(); } @@ -1686,7 +1707,7 @@ struct ItemInfo2 { std::string topSubname; }; -void TreeWidget::dropEvent(QDropEvent *event) +void TreeWidget::dropEvent(QDropEvent* event) { //FIXME: This should actually be done inside dropMimeData @@ -1699,27 +1720,27 @@ void TreeWidget::dropEvent(QDropEvent *event) if (targetItem->isSelected()) return; - App::Document *thisDoc; + App::Document* thisDoc; Base::EmptySequencer seq; // filter out the selected items we cannot handle - std::vector > > items; + std::vector > > items; auto sels = selectedItems(); items.reserve(sels.size()); - for(auto ti : sels) { + for (auto ti : sels) { if (ti->type() != TreeWidget::ObjectType) continue; // ignore child elements if the parent is selected - if(sels.contains(ti->parent())) + if (sels.contains(ti->parent())) continue; if (ti == targetItem) continue; auto item = static_cast(ti); items.emplace_back(); - auto &info = items.back(); + auto& info = items.back(); info.first = item; - info.second.insert(info.second.end(),item->mySubs.begin(),item->mySubs.end()); + info.second.insert(info.second.end(), item->mySubs.begin(), item->mySubs.end()); } if (items.empty()) @@ -1727,15 +1748,15 @@ void TreeWidget::dropEvent(QDropEvent *event) std::string errMsg; - if(QApplication::keyboardModifiers()== Qt::ControlModifier) + if (QApplication::keyboardModifiers() == Qt::ControlModifier) event->setDropAction(Qt::CopyAction); - else if(QApplication::keyboardModifiers()== Qt::AltModifier - && (items.size()==1||targetItem->type()==TreeWidget::DocumentType)) + else if (QApplication::keyboardModifiers() == Qt::AltModifier + && (items.size() == 1 || targetItem->type() == TreeWidget::DocumentType)) event->setDropAction(Qt::LinkAction); else event->setDropAction(Qt::MoveAction); auto da = event->dropAction(); - bool dropOnly = da==Qt::CopyAction || da==Qt::LinkAction; + bool dropOnly = da == Qt::CopyAction || da == Qt::LinkAction; if (targetItem->type() == TreeWidget::ObjectType) { // add object to group @@ -1743,60 +1764,61 @@ void TreeWidget::dropEvent(QDropEvent *event) thisDoc = targetItemObj->getOwnerDocument()->document()->getDocument(); Gui::ViewProviderDocumentObject* vp = targetItemObj->object(); - if(!vp || !vp->getObject() || !vp->getObject()->getNameInDocument()) { + if (!vp || !vp->getObject() || !vp->getObject()->getNameInDocument()) { TREE_TRACE("invalid object"); return; } - if (da!=Qt::LinkAction && !vp->canDropObjects()) { - if(!(event->possibleActions() & Qt::LinkAction) || items.size()!=1) { + if (da != Qt::LinkAction && !vp->canDropObjects()) { + if (!(event->possibleActions() & Qt::LinkAction) || items.size() != 1) { TREE_TRACE("Cannot drop objects"); return; // no group like object } } std::ostringstream targetSubname; - App::DocumentObject *targetParent = 0; - targetItemObj->getSubName(targetSubname,targetParent); + App::DocumentObject* targetParent = 0; + targetItemObj->getSubName(targetSubname, targetParent); Selection().selStackPush(); Selection().clearCompleteSelection(); - if(targetParent) { + if (targetParent) { targetSubname << vp->getObject()->getNameInDocument() << '.'; Selection().addSelection(targetParent->getDocument()->getName(), - targetParent->getNameInDocument(), targetSubname.str().c_str()); - } else { + targetParent->getNameInDocument(), targetSubname.str().c_str()); + } + else { targetParent = targetItemObj->object()->getObject(); Selection().addSelection(targetParent->getDocument()->getName(), - targetParent->getNameInDocument()); + targetParent->getNameInDocument()); } bool syncPlacement = TreeParams::Instance()->SyncPlacement() && targetItemObj->isGroup(); bool setSelection = true; - std::vector > droppedObjects; + std::vector > droppedObjects; std::vector infos; // Only keep text names here, because you never know when doing drag // and drop some object may delete other objects. infos.reserve(items.size()); - for(auto &v : items) { + for (auto& v : items) { infos.emplace_back(); - auto &info = infos.back(); + auto& info = infos.back(); auto item = v.first; Gui::ViewProviderDocumentObject* vpc = item->object(); App::DocumentObject* obj = vpc->getObject(); std::ostringstream str; - App::DocumentObject *topParent=0; - auto owner = item->getRelativeParent(str,targetItemObj,&topParent,&info.topSubname); - if(syncPlacement && topParent) { + App::DocumentObject* topParent = 0; + auto owner = item->getRelativeParent(str, targetItemObj, &topParent, &info.topSubname); + if (syncPlacement && topParent) { info.topDoc = topParent->getDocument()->getName(); info.topObj = topParent->getNameInDocument(); } info.subname = str.str(); info.doc = obj->getDocument()->getName(); info.obj = obj->getNameInDocument(); - if(owner) { + if (owner) { info.ownerDoc = owner->getDocument()->getName(); info.owner = owner->getNameInDocument(); } @@ -1804,16 +1826,16 @@ void TreeWidget::dropEvent(QDropEvent *event) info.subs.swap(v.second); // check if items can be dragged - if(!dropOnly && - item->myOwner == targetItemObj->myOwner && - vp->canDragAndDropObject(item->object()->getObject())) + if (!dropOnly && + item->myOwner == targetItemObj->myOwner && + vp->canDragAndDropObject(item->object()->getObject())) { // check if items can be dragged auto parentItem = item->getParentItem(); - if(!parentItem) + if (!parentItem) info.dragging = true; - else if(parentItem->object()->canDragObjects() - && parentItem->object()->canDragObject(item->object()->getObject())) + else if (parentItem->object()->canDragObjects() + && parentItem->object()->canDragObject(item->object()->getObject())) { info.dragging = true; auto vpp = parentItem->object(); @@ -1822,16 +1844,16 @@ void TreeWidget::dropEvent(QDropEvent *event) } } - if (da!=Qt::LinkAction - && !vp->canDropObjectEx(obj,owner,info.subname.c_str(),item->mySubs)) + if (da != Qt::LinkAction + && !vp->canDropObjectEx(obj, owner, info.subname.c_str(), item->mySubs)) { - if(event->possibleActions() & Qt::LinkAction) { - if(items.size()>1) { + if (event->possibleActions() & Qt::LinkAction) { + if (items.size() > 1) { TREE_TRACE("Cannot replace with more than one object"); return; } auto ext = vp->getObject()->getExtensionByType(true); - if((!ext || !ext->getLinkedObjectProperty()) && !targetItemObj->getParentItem()) { + if ((!ext || !ext->getLinkedObjectProperty()) && !targetItemObj->getParentItem()) { TREE_TRACE("Cannot replace without parent"); return; } @@ -1847,80 +1869,81 @@ void TreeWidget::dropEvent(QDropEvent *event) std::set inList; auto parentObj = targetObj; - if(da == Qt::LinkAction && targetItemObj->getParentItem()) + if (da == Qt::LinkAction && targetItemObj->getParentItem()) parentObj = targetItemObj->getParentItem()->object()->getObject(); inList = parentObj->getInListEx(true); inList.insert(parentObj); std::string target = targetObj->getNameInDocument(); auto targetDoc = targetObj->getDocument(); - for (auto &info : infos) { - auto &subname = info.subname; + for (auto& info : infos) { + auto& subname = info.subname; targetObj = targetDoc->getObject(target.c_str()); vp = Base::freecad_dynamic_cast( - Application::Instance->getViewProvider(targetObj)); - if(!vp) { + Application::Instance->getViewProvider(targetObj)); + if (!vp) { FC_ERR("Cannot find drop target object " << target); break; } auto doc = App::GetApplication().getDocument(info.doc.c_str()); - if(!doc) { + if (!doc) { FC_WARN("Cannot find document " << info.doc); continue; } auto obj = doc->getObject(info.obj.c_str()); auto vpc = dynamic_cast( - Application::Instance->getViewProvider(obj)); - if(!vpc) { + Application::Instance->getViewProvider(obj)); + if (!vpc) { FC_WARN("Cannot find dragging object " << info.obj); continue; } - ViewProviderDocumentObject *vpp = 0; - if(da!=Qt::LinkAction && info.parentDoc.size()) { + ViewProviderDocumentObject* vpp = 0; + if (da != Qt::LinkAction && info.parentDoc.size()) { auto parentDoc = App::GetApplication().getDocument(info.parentDoc.c_str()); - if(parentDoc) { + if (parentDoc) { auto parent = parentDoc->getObject(info.parent.c_str()); vpp = dynamic_cast( - Application::Instance->getViewProvider(parent)); + Application::Instance->getViewProvider(parent)); } - if(!vpp) { + if (!vpp) { FC_WARN("Cannot find dragging object's parent " << info.parent); continue; } } - App::DocumentObject *owner = 0; - if(info.ownerDoc.size()) { + App::DocumentObject* owner = 0; + if (info.ownerDoc.size()) { auto ownerDoc = App::GetApplication().getDocument(info.ownerDoc.c_str()); - if(ownerDoc) + if (ownerDoc) owner = ownerDoc->getObject(info.owner.c_str()); - if(!owner) { + if (!owner) { FC_WARN("Cannot find dragging object's top parent " << info.owner); continue; } } Base::Matrix4D mat; - App::PropertyPlacement *propPlacement = 0; - if(syncPlacement) { - if(info.topObj.size()) { + App::PropertyPlacement* propPlacement = 0; + if (syncPlacement) { + if (info.topObj.size()) { auto doc = App::GetApplication().getDocument(info.topDoc.c_str()); - if(doc) { + if (doc) { auto topObj = doc->getObject(info.topObj.c_str()); - if(topObj) { - auto sobj = topObj->getSubObject(info.topSubname.c_str(),0,&mat); - if(sobj == obj) { + if (topObj) { + auto sobj = topObj->getSubObject(info.topSubname.c_str(), 0, &mat); + if (sobj == obj) { propPlacement = Base::freecad_dynamic_cast( - obj->getPropertyByName("Placement")); + obj->getPropertyByName("Placement")); } } } - }else{ + } + else { propPlacement = Base::freecad_dynamic_cast( - obj->getPropertyByName("Placement")); - if(propPlacement) + obj->getPropertyByName("Placement")); + if (propPlacement) mat = propPlacement->getValue().toMatrix(); } } @@ -1929,34 +1952,34 @@ void TreeWidget::dropEvent(QDropEvent *event) auto manager = Application::Instance->macroManager(); std::ostringstream ss; - if(vpp) { + if (vpp) { auto lines = manager->getLines(); ss << Command::getObjectCmd(vpp->getObject()) << ".ViewObject.dragObject(" << Command::getObjectCmd(obj) << ')'; vpp->dragObject(obj); - if(manager->getLines() == lines) - manager->addLine(MacroManager::Gui,ss.str().c_str()); + if (manager->getLines() == lines) + manager->addLine(MacroManager::Gui, ss.str().c_str()); owner = 0; subname.clear(); ss.str(""); obj = doc->getObject(info.obj.c_str()); - if(!obj || !obj->getNameInDocument()) { + if (!obj || !obj->getNameInDocument()) { FC_WARN("Dropping object deleted: " << info.doc << '#' << info.obj); continue; } } - if(da == Qt::MoveAction) { + if (da == Qt::MoveAction) { // Try to adjust relative links to avoid cyclic dependency, may // throw exception if failed ss.str(""); ss << Command::getObjectCmd(obj) << ".adjustRelativeLinks(" << Command::getObjectCmd(targetObj) << ")"; - manager->addLine(MacroManager::Gui,ss.str().c_str()); + manager->addLine(MacroManager::Gui, ss.str().c_str()); std::set visited; - if(obj->adjustRelativeLinks(inList,&visited)) { + if (obj->adjustRelativeLinks(inList, &visited)) { inList = parentObj->getInListEx(true); inList.insert(parentObj); @@ -1966,60 +1989,63 @@ void TreeWidget::dropEvent(QDropEvent *event) } } - if(inList.count(obj)) + if (inList.count(obj)) FC_THROWM(Base::RuntimeError, - "Dependency loop detected for " << obj->getFullName()); + "Dependency loop detected for " << obj->getFullName()); std::string dropName; ss.str(""); - if(da == Qt::LinkAction) { + if (da == Qt::LinkAction) { auto parentItem = targetItemObj->getParentItem(); if (parentItem) { ss << Command::getObjectCmd( - parentItem->object()->getObject(),0,".replaceObject(",true) + parentItem->object()->getObject(), 0, ".replaceObject(", true) << Command::getObjectCmd(targetObj) << "," << Command::getObjectCmd(obj) << ")"; std::ostringstream ss; dropParent = 0; - parentItem->getSubName(ss,dropParent); - if(dropParent) + parentItem->getSubName(ss, dropParent); + if (dropParent) ss << parentItem->object()->getObject()->getNameInDocument() << '.'; else dropParent = parentItem->object()->getObject(); ss << obj->getNameInDocument() << '.'; dropName = ss.str(); - } else { + } + else { TREE_WARN("ignore replace operation without parent"); continue; } Gui::Command::runCommand(Gui::Command::App, ss.str().c_str()); - }else{ + } + else { ss << Command::getObjectCmd(vp->getObject()) << ".ViewObject.dropObject(" << Command::getObjectCmd(obj); - if(owner) { + if (owner) { ss << "," << Command::getObjectCmd(owner) << ",'" << subname << "',["; - }else + } + else ss << ",None,'',["; - for(auto &sub : info.subs) + for (auto& sub : info.subs) ss << "'" << sub << "',"; ss << "])"; auto lines = manager->getLines(); - dropName = vp->dropObjectEx(obj,owner,subname.c_str(),info.subs); - if(manager->getLines() == lines) - manager->addLine(MacroManager::Gui,ss.str().c_str()); - if(dropName.size()) + dropName = vp->dropObjectEx(obj, owner, subname.c_str(), info.subs); + if (manager->getLines() == lines) + manager->addLine(MacroManager::Gui, ss.str().c_str()); + if (dropName.size()) dropName = targetSubname.str() + dropName; } touched = true; // Construct the subname pointing to the dropped object - if(dropName.empty()) { + if (dropName.empty()) { auto pos = targetSubname.tellp(); targetSubname << obj->getNameInDocument() << '.' << std::ends; dropName = targetSubname.str(); @@ -2027,55 +2053,58 @@ void TreeWidget::dropEvent(QDropEvent *event) } Base::Matrix4D newMat; - auto sobj = dropParent->getSubObject(dropName.c_str(),0,&newMat); - if(!sobj) { + auto sobj = dropParent->getSubObject(dropName.c_str(), 0, &newMat); + if (!sobj) { FC_LOG("failed to find dropped object " - << dropParent->getFullName() << '.' << dropName); + << dropParent->getFullName() << '.' << dropName); setSelection = false; continue; } - if(da!=Qt::CopyAction && propPlacement) { + if (da != Qt::CopyAction && propPlacement) { // try to adjust placement - if((info.dragging && sobj==obj) || - (!info.dragging && sobj->getLinkedObject(false)==obj)) + if ((info.dragging && sobj == obj) || + (!info.dragging && sobj->getLinkedObject(false) == obj)) { - if(!info.dragging) + if (!info.dragging) propPlacement = Base::freecad_dynamic_cast( - sobj->getPropertyByName("Placement")); - if(propPlacement) { + sobj->getPropertyByName("Placement")); + if (propPlacement) { newMat *= propPlacement->getValue().inverse().toMatrix(); newMat.inverseGauss(); - Base::Placement pla(newMat*mat); + Base::Placement pla(newMat * mat); propPlacement->setValueIfChanged(pla); } } } - droppedObjects.emplace_back(dropParent,dropName); + droppedObjects.emplace_back(dropParent, dropName); } Base::FlagToggler<> guard(_DisableCheckTopParent); - if(setSelection && droppedObjects.size()) { + if (setSelection && droppedObjects.size()) { Selection().selStackPush(); Selection().clearCompleteSelection(); - for(auto &v : droppedObjects) + for (auto& v : droppedObjects) Selection().addSelection(v.first->getDocument()->getName(), v.first->getNameInDocument(), v.second.c_str()); Selection().selStackPush(); } - } catch (const Base::Exception& e) { + } + catch (const Base::Exception& e) { e.ReportException(); errMsg = e.what(); - } catch (std::exception &e) { + } + catch (std::exception& e) { FC_ERR("C++ exception: " << e.what()); errMsg = e.what(); - } catch (...) { + } + catch (...) { FC_ERR("Unknown exception"); errMsg = "Unknown exception"; } - if(errMsg.size()) { + if (errMsg.size()) { committer.close(true); QMessageBox::critical(getMainWindow(), QObject::tr("Drag & drop failed"), - QString::fromUtf8(errMsg.c_str())); + QString::fromUtf8(errMsg.c_str())); return; } } @@ -2088,39 +2117,41 @@ void TreeWidget::dropEvent(QDropEvent *event) bool syncPlacement = TreeParams::Instance()->SyncPlacement(); // check if items can be dragged - for(auto &v : items) { + for (auto& v : items) { auto item = v.first; auto obj = item->object()->getObject(); auto parentItem = item->getParentItem(); - if(!parentItem) { - if(da==Qt::MoveAction && obj->getDocument()==thisDoc) + if (!parentItem) { + if (da == Qt::MoveAction && obj->getDocument() == thisDoc) continue; - }else if(dropOnly || item->myOwner!=targetItem) { + } + else if (dropOnly || item->myOwner != targetItem) { // We will not drag item out of parent if either, 1) the CTRL // key is held, or 2) the dragging item is not inside the // dropping document tree. parentItem = 0; - }else if(!parentItem->object()->canDragObjects() - || !parentItem->object()->canDragObject(obj)) + } + else if (!parentItem->object()->canDragObjects() + || !parentItem->object()->canDragObject(obj)) { TREE_ERR("'" << obj->getFullName() << "' cannot be dragged out of '" << parentItem->object()->getObject()->getFullName() << "'"); return; } infos.emplace_back(); - auto &info = infos.back(); + auto& info = infos.back(); info.doc = obj->getDocument()->getName(); info.obj = obj->getNameInDocument(); - if(parentItem) { + if (parentItem) { auto parent = parentItem->object()->getObject(); info.parentDoc = parent->getDocument()->getName(); info.parent = parent->getNameInDocument(); } - if(syncPlacement) { + if (syncPlacement) { std::ostringstream ss; - App::DocumentObject *topParent=0; - item->getSubName(ss,topParent); - if(topParent) { + App::DocumentObject* topParent = 0; + item->getSubName(ss, topParent); + if (topParent) { info.topDoc = topParent->getDocument()->getName(); info.topObj = topParent->getNameInDocument(); ss << obj->getNameInDocument() << '.'; @@ -2136,66 +2167,68 @@ void TreeWidget::dropEvent(QDropEvent *event) // Open command auto manager = Application::Instance->macroManager(); App::AutoTransaction committer( - da==Qt::LinkAction?"Link object": - da==Qt::CopyAction?"Copy object":"Move object"); + da == Qt::LinkAction ? "Link object" : + da == Qt::CopyAction ? "Copy object" : "Move object"); try { std::vector droppedObjs; - for (auto &info : infos) { + for (auto& info : infos) { auto doc = App::GetApplication().getDocument(info.doc.c_str()); - if(!doc) continue; + if (!doc) continue; auto obj = doc->getObject(info.obj.c_str()); auto vpc = dynamic_cast( - Application::Instance->getViewProvider(obj)); - if(!vpc) { + Application::Instance->getViewProvider(obj)); + if (!vpc) { FC_WARN("Cannot find dragging object " << info.obj); continue; } Base::Matrix4D mat; - App::PropertyPlacement *propPlacement = 0; - if(syncPlacement) { - if(info.topObj.size()) { + App::PropertyPlacement* propPlacement = 0; + if (syncPlacement) { + if (info.topObj.size()) { auto doc = App::GetApplication().getDocument(info.topDoc.c_str()); - if(doc) { + if (doc) { auto topObj = doc->getObject(info.topObj.c_str()); - if(topObj) { - auto sobj = topObj->getSubObject(info.topSubname.c_str(),0,&mat); - if(sobj == obj) { + if (topObj) { + auto sobj = topObj->getSubObject(info.topSubname.c_str(), 0, &mat); + if (sobj == obj) { propPlacement = dynamic_cast( - obj->getPropertyByName("Placement")); + obj->getPropertyByName("Placement")); } } } - }else{ + } + else { propPlacement = dynamic_cast( - obj->getPropertyByName("Placement")); - if(propPlacement) + obj->getPropertyByName("Placement")); + if (propPlacement) mat = propPlacement->getValue().toMatrix(); } } - if(da == Qt::LinkAction) { + if (da == Qt::LinkAction) { std::string name = thisDoc->getUniqueObjectName("Link"); - FCMD_DOC_CMD(thisDoc,"addObject('App::Link','" << name << "').setLink(" - << Command::getObjectCmd(obj) << ")"); + FCMD_DOC_CMD(thisDoc, "addObject('App::Link','" << name << "').setLink(" + << Command::getObjectCmd(obj) << ")"); auto link = thisDoc->getObject(name.c_str()); - if(!link) + if (!link) continue; - FCMD_OBJ_CMD(link,"Label='" << obj->getLinkedObject(true)->Label.getValue() << "'"); + FCMD_OBJ_CMD(link, "Label='" << obj->getLinkedObject(true)->Label.getValue() << "'"); propPlacement = dynamic_cast(link->getPropertyByName("Placement")); - if(propPlacement) + if (propPlacement) propPlacement->setValueIfChanged(Base::Placement(mat)); droppedObjs.push_back(link); - }else if(info.parent.size()) { + } + else if (info.parent.size()) { auto parentDoc = App::GetApplication().getDocument(info.parentDoc.c_str()); - if(!parentDoc) { + if (!parentDoc) { FC_WARN("Canont find document " << info.parentDoc); continue; } auto parent = parentDoc->getObject(info.parent.c_str()); auto vpp = dynamic_cast( - Application::Instance->getViewProvider(parent)); - if(!vpp) { + Application::Instance->getViewProvider(parent)); + if (!vpp) { FC_WARN("Cannot find dragging object's parent " << info.parent); continue; } @@ -2205,79 +2238,84 @@ void TreeWidget::dropEvent(QDropEvent *event) << ".ViewObject.dragObject(" << Command::getObjectCmd(obj) << ')'; auto lines = manager->getLines(); vpp->dragObject(obj); - if(manager->getLines() == lines) - manager->addLine(MacroManager::Gui,ss.str().c_str()); + if (manager->getLines() == lines) + manager->addLine(MacroManager::Gui, ss.str().c_str()); //make sure it is not part of a geofeaturegroup anymore. //When this has happen we need to handle all removed //objects auto grp = App::GeoFeatureGroupExtension::getGroupOfObject(obj); - if(grp) { - FCMD_OBJ_CMD(grp,"removeObject(" << Command::getObjectCmd(obj) << ")"); + if (grp) { + FCMD_OBJ_CMD(grp, "removeObject(" << Command::getObjectCmd(obj) << ")"); } // check if the object has been deleted obj = doc->getObject(info.obj.c_str()); - if(!obj || !obj->getNameInDocument()) + if (!obj || !obj->getNameInDocument()) continue; droppedObjs.push_back(obj); - if(propPlacement) + if (propPlacement) propPlacement->setValueIfChanged(Base::Placement(mat)); - } else { + } + else { std::ostringstream ss; ss << "App.getDocument('" << thisDoc->getName() << "')." - << (da==Qt::CopyAction?"copyObject(":"moveObject(") + << (da == Qt::CopyAction ? "copyObject(" : "moveObject(") << Command::getObjectCmd(obj) << ", True)"; - App::DocumentObject *res = 0; - if(da == Qt::CopyAction) { - auto copied = thisDoc->copyObject({obj},true); - if(copied.size()) + App::DocumentObject* res = 0; + if (da == Qt::CopyAction) { + auto copied = thisDoc->copyObject({ obj }, true); + if (copied.size()) res = copied.back(); - }else - res = thisDoc->moveObject(obj,true); - if(res) { + } + else + res = thisDoc->moveObject(obj, true); + if (res) { propPlacement = dynamic_cast( - res->getPropertyByName("Placement")); - if(propPlacement) + res->getPropertyByName("Placement")); + if (propPlacement) propPlacement->setValueIfChanged(Base::Placement(mat)); droppedObjs.push_back(res); } - manager->addLine(MacroManager::App,ss.str().c_str()); + manager->addLine(MacroManager::App, ss.str().c_str()); } } touched = true; Base::FlagToggler<> guard(_DisableCheckTopParent); - Selection().setSelection(thisDoc->getName(),droppedObjs); + Selection().setSelection(thisDoc->getName(), droppedObjs); - } catch (const Base::Exception& e) { + } + catch (const Base::Exception& e) { e.ReportException(); errMsg = e.what(); - } catch (std::exception &e) { + } + catch (std::exception& e) { FC_ERR("C++ exception: " << e.what()); errMsg = e.what(); - } catch (...) { + } + catch (...) { FC_ERR("Unknown exception"); errMsg = "Unknown exception"; } - if(errMsg.size()) { + if (errMsg.size()) { committer.close(true); QMessageBox::critical(getMainWindow(), QObject::tr("Drag & drop failed"), - QString::fromUtf8(errMsg.c_str())); + QString::fromUtf8(errMsg.c_str())); return; } } - if(touched && TreeParams::Instance()->RecomputeOnDrop()) + if (touched && TreeParams::Instance()->RecomputeOnDrop()) thisDoc->recompute(); - if(touched && TreeParams::Instance()->SyncView()) { + if (touched && TreeParams::Instance()->SyncView()) { auto gdoc = Application::Instance->getDocument(thisDoc); - if(gdoc) + if (gdoc) gdoc->setActiveView(); } } -void TreeWidget::drawRow(QPainter *painter, const QStyleOptionViewItem &options, const QModelIndex &index) const +void TreeWidget::drawRow(QPainter* painter, const QStyleOptionViewItem& options, const QModelIndex& index) const { QTreeWidget::drawRow(painter, options, index); // Set the text and highlighted text color of a hidden object to a dark @@ -2297,14 +2335,14 @@ void TreeWidget::drawRow(QPainter *painter, const QStyleOptionViewItem &options, void TreeWidget::slotNewDocument(const Gui::Document& Doc, bool isMainDoc) { - if(Doc.getDocument()->testStatus(App::Document::TempDoc)) + if (Doc.getDocument()->testStatus(App::Document::TempDoc)) return; DocumentItem* item = new DocumentItem(&Doc, this->rootItem); - if(isMainDoc) + if (isMainDoc) this->expandItem(item); item->setIcon(0, *documentPixmap); item->setText(0, QString::fromUtf8(Doc.getDocument()->Label.getValue())); - DocumentMap[ &Doc ] = item; + DocumentMap[&Doc] = item; } void TreeWidget::slotStartOpenDocument() { @@ -2325,8 +2363,8 @@ void TreeWidget::onReloadDoc() { App::Document* doc = docitem->document()->getDocument(); std::string name = doc->FileName.getValue(); Application::Instance->reopen(doc); - for(auto &v : DocumentMap) { - if(name == v.first->getDocument()->FileName.getValue()) { + for (auto& v : DocumentMap) { + if (name == v.first->getDocument()->FileName.getValue()) { scrollToItem(v.second); App::GetApplication().setActiveDocument(v.first->getDocument()); break; @@ -2344,11 +2382,14 @@ void TreeWidget::onCloseDoc() App::Document* doc = gui->getDocument(); if (gui->canClose(true, true)) Command::doCommand(Command::Doc, "App.closeDocument(\"%s\")", doc->getName()); - } catch (const Base::Exception& e) { + } + catch (const Base::Exception& e) { e.ReportException(); - } catch (std::exception &e) { + } + catch (std::exception& e) { FC_ERR("C++ exception: " << e.what()); - } catch (...) { + } + catch (...) { FC_ERR("Unknown exception"); } } @@ -2359,21 +2400,21 @@ void TreeWidget::slotRenameDocument(const Gui::Document& Doc) Q_UNUSED(Doc); } -void TreeWidget::slotChangedViewObject(const Gui::ViewProvider& vp, const App::Property &prop) +void TreeWidget::slotChangedViewObject(const Gui::ViewProvider& vp, const App::Property& prop) { - if(!App::GetApplication().isRestoring() - && vp.isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) + if (!App::GetApplication().isRestoring() + && vp.isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) { - const auto &vpd = static_cast(vp); - if(&prop == &vpd.ShowInTree) { - ChangedObjects.emplace(vpd.getObject(),0); + const auto& vpd = static_cast(vp); + if (&prop == &vpd.ShowInTree) { + ChangedObjects.emplace(vpd.getObject(), 0); _updateStatus(); } } } -void TreeWidget::slotTouchedObject(const App::DocumentObject &obj) { - ChangedObjects.emplace(const_cast(&obj),0); +void TreeWidget::slotTouchedObject(const App::DocumentObject& obj) { + ChangedObjects.emplace(const_cast(&obj), 0); _updateStatus(); } @@ -2381,7 +2422,7 @@ void TreeWidget::slotShowHidden(const Gui::Document& Doc) { auto it = DocumentMap.find(&Doc); if (it != DocumentMap.end()) - it->second->updateItemsVisibility(it->second,it->second->showHidden()); + it->second->updateItemsVisibility(it->second, it->second->showHidden()); } void TreeWidget::slotRelabelDocument(const Gui::Document& Doc) @@ -2399,7 +2440,7 @@ void TreeWidget::slotActiveDocument(const Gui::Document& Doc) return; // signal is emitted before the item gets created int displayMode = TreeParams::Instance()->DocumentMode(); for (auto it = DocumentMap.begin(); - it != DocumentMap.end(); ++it) + it != DocumentMap.end(); ++it) { QFont f = it->second->font(0); f.setBold(it == jt); @@ -2413,21 +2454,21 @@ void TreeWidget::slotActiveDocument(const Gui::Document& Doc) } struct UpdateDisabler { - QWidget &widget; - int &blocked; + QWidget& widget; + int& blocked; bool visible; bool focus; // Note! DO NOT block signal here, or else // QTreeWidgetItem::setChildIndicatorPolicy() does not work - UpdateDisabler(QWidget &w, int &blocked) + UpdateDisabler(QWidget& w, int& blocked) : widget(w), blocked(blocked), visible(false), focus(false) { - if(++blocked > 1) + if (++blocked > 1) return; focus = widget.hasFocus(); visible = widget.isVisible(); - if(visible) { + if (visible) { // setUpdatesEnabled(false) does not seem to speed up anything. // setVisible(false) on the other hand makes QTreeWidget::setData // (i.e. any change to QTreeWidgetItem) faster by 10+ times. @@ -2438,13 +2479,13 @@ struct UpdateDisabler { } } ~UpdateDisabler() { - if(blocked<=0 || --blocked!=0) + if (blocked <= 0 || --blocked != 0) return; - if(visible) { + if (visible) { widget.setVisible(true); // widget.setUpdatesEnabled(true); - if(focus) + if (focus) widget.setFocus(); } } @@ -2452,13 +2493,13 @@ struct UpdateDisabler { void TreeWidget::onUpdateStatus(void) { - if(this->state()==DraggingState || App::GetApplication().isRestoring()) { + if (this->state() == DraggingState || App::GetApplication().isRestoring()) { _updateStatus(); return; } - for(auto &v : DocumentMap) { - if(v.first->isPerformingTransaction()) { + for (auto& v : DocumentMap) { + if (v.first->isPerformingTransaction()) { // We have to delay item creation until undo/redo is done, because the // object re-creation while in transaction may break tree view item // update logic. For example, a parent object re-created before its @@ -2471,56 +2512,56 @@ void TreeWidget::onUpdateStatus(void) FC_LOG("begin update status"); - UpdateDisabler disabler(*this,updateBlocked); + UpdateDisabler disabler(*this, updateBlocked); std::vector errors; // Checking for new objects - for(auto &v : NewObjects) { + for (auto& v : NewObjects) { auto doc = App::GetApplication().getDocument(v.first.c_str()); - if(!doc) + if (!doc) continue; auto gdoc = Application::Instance->getDocument(doc); - if(!gdoc) + if (!gdoc) continue; auto docItem = getDocumentItem(gdoc); - if(!docItem) + if (!docItem) continue; - for(auto id : v.second) { + for (auto id : v.second) { auto obj = doc->getObjectByID(id); - if(!obj) + if (!obj) continue; - if(obj->isError()) + if (obj->isError()) errors.push_back(obj); - if(docItem->ObjectMap.count(obj)) + if (docItem->ObjectMap.count(obj)) continue; auto vpd = Base::freecad_dynamic_cast(gdoc->getViewProvider(obj)); - if(vpd) + if (vpd) docItem->createNewItem(*vpd); } } NewObjects.clear(); // Update children of changed objects - for(auto &v : ChangedObjects) { + for (auto& v : ChangedObjects) { auto obj = v.first; auto iter = ObjectTable.find(obj); - if(iter == ObjectTable.end()) + if (iter == ObjectTable.end()) continue; - if(v.second.test(CS_Error) && obj->isError()) + if (v.second.test(CS_Error) && obj->isError()) errors.push_back(obj); - if(iter->second.size()) { + if (iter->second.size()) { auto data = *iter->second.begin(); bool itemHidden = !data->viewObject->showInTree(); - if(data->itemHidden != itemHidden) { - for(auto &data : iter->second) { + if (data->itemHidden != itemHidden) { + for (auto& data : iter->second) { data->itemHidden = itemHidden; - if(data->docItem->showHidden()) + if (data->docItem->showHidden()) continue; - for(auto item : data->items) + for (auto item : data->items) item->setHidden(itemHidden); } } @@ -2532,45 +2573,45 @@ void TreeWidget::onUpdateStatus(void) FC_LOG("update item status"); TimingInit(); - for (auto pos = DocumentMap.begin();pos!=DocumentMap.end();++pos) { + for (auto pos = DocumentMap.begin(); pos != DocumentMap.end(); ++pos) { pos->second->testStatus(); } TimingPrint(); // Checking for just restored documents - for(auto &v : DocumentMap) { + for (auto& v : DocumentMap) { auto docItem = v.second; - for(auto obj : docItem->PopulateObjects) + for (auto obj : docItem->PopulateObjects) docItem->populateObject(obj); docItem->PopulateObjects.clear(); auto doc = v.first->getDocument(); - if(!docItem->connectChgObject.connected()) { + if (!docItem->connectChgObject.connected()) { docItem->connectChgObject = docItem->document()->signalChangedObject.connect( - boost::bind(&TreeWidget::slotChangeObject, this, bp::_1, bp::_2)); + boost::bind(&TreeWidget::slotChangeObject, this, bp::_1, bp::_2)); docItem->connectTouchedObject = doc->signalTouchedObject.connect( - boost::bind(&TreeWidget::slotTouchedObject, this, bp::_1)); + boost::bind(&TreeWidget::slotTouchedObject, this, bp::_1)); } - if(doc->testStatus(App::Document::PartialDoc)) + if (doc->testStatus(App::Document::PartialDoc)) docItem->setIcon(0, *documentPartialPixmap); - else if(docItem->_ExpandInfo) { - for(auto &entry : *docItem->_ExpandInfo) { - const char *name = entry.first.c_str(); + else if (docItem->_ExpandInfo) { + for (auto& entry : *docItem->_ExpandInfo) { + const char* name = entry.first.c_str(); bool legacy = name[0] == '*'; - if(legacy) + if (legacy) ++name; auto obj = doc->getObject(name); - if(!obj) + if (!obj) continue; auto iter = docItem->ObjectMap.find(obj); - if(iter==docItem->ObjectMap.end()) + if (iter == docItem->ObjectMap.end()) continue; - if(iter->second->rootItem) - docItem->restoreItemExpansion(entry.second,iter->second->rootItem); - else if(legacy && iter->second->items.size()) { + if (iter->second->rootItem) + docItem->restoreItemExpansion(entry.second, iter->second->rootItem); + else if (legacy && iter->second->items.size()) { auto item = *iter->second->items.begin(); item->setExpanded(true); } @@ -2579,10 +2620,10 @@ void TreeWidget::onUpdateStatus(void) docItem->_ExpandInfo.reset(); } - if(Selection().hasSelection() && !selectTimer->isActive() && !this->isConnectionBlocked()) { + if (Selection().hasSelection() && !selectTimer->isActive() && !this->isConnectionBlocked()) { this->blockConnection(true); currentDocItem = 0; - for(auto &v : DocumentMap) { + for (auto& v : DocumentMap) { v.second->setSelected(false); v.second->selectItems(); } @@ -2591,34 +2632,34 @@ void TreeWidget::onUpdateStatus(void) auto activeDocItem = getDocumentItem(Application::Instance->activeDocument()); - QTreeWidgetItem *errItem = 0; - for(auto obj : errors) { + QTreeWidgetItem* errItem = 0; + for (auto obj : errors) { DocumentObjectDataPtr data; - if(activeDocItem) { + if (activeDocItem) { auto it = activeDocItem->ObjectMap.find(obj); - if(it!=activeDocItem->ObjectMap.end()) + if (it != activeDocItem->ObjectMap.end()) data = it->second; } - if(!data) { + if (!data) { auto docItem = getDocumentItem( - Application::Instance->getDocument(obj->getDocument())); - if(docItem) { + Application::Instance->getDocument(obj->getDocument())); + if (docItem) { auto it = docItem->ObjectMap.find(obj); - if(it!=docItem->ObjectMap.end()) + if (it != docItem->ObjectMap.end()) data = it->second; } } - if(data) { + if (data) { auto item = data->rootItem; - if(!item && data->items.size()) { + if (!item && data->items.size()) { item = *data->items.begin(); - data->docItem->showItem(item,false,true); + data->docItem->showItem(item, false, true); } - if(!errItem) + if (!errItem) errItem = item; } } - if(errItem) + if (errItem) scrollToItem(errItem); updateGeometries(); @@ -2627,43 +2668,44 @@ void TreeWidget::onUpdateStatus(void) FC_LOG("done update status"); } -void TreeWidget::onItemEntered(QTreeWidgetItem * item) +void TreeWidget::onItemEntered(QTreeWidgetItem* item) { // object item selected if (item && item->type() == TreeWidget::ObjectType) { DocumentObjectItem* objItem = static_cast(item); objItem->displayStatusInfo(); - if(TreeParams::Instance()->PreSelection()) { + if (TreeParams::Instance()->PreSelection()) { int timeout = TreeParams::Instance()->PreSelectionDelay(); - if(timeout < 0) + if (timeout < 0) timeout = 1; - if(preselectTime.elapsed() < timeout) + if (preselectTime.elapsed() < timeout) onPreSelectTimer(); - else{ + else { timeout = TreeParams::Instance()->PreSelectionTimeout(); - if(timeout < 0) + if (timeout < 0) timeout = 1; preselectTimer->start(timeout); Selection().rmvPreselect(); } } - } else if(TreeParams::Instance()->PreSelection()) + } + else if (TreeParams::Instance()->PreSelection()) Selection().rmvPreselect(); } -void TreeWidget::leaveEvent(QEvent *) { - if(!updateBlocked && TreeParams::Instance()->PreSelection()) { +void TreeWidget::leaveEvent(QEvent*) { + if (!updateBlocked && TreeParams::Instance()->PreSelection()) { preselectTimer->stop(); Selection().rmvPreselect(); } } void TreeWidget::onPreSelectTimer() { - if(!TreeParams::Instance()->PreSelection()) + if (!TreeParams::Instance()->PreSelection()) return; auto item = itemAt(viewport()->mapFromGlobal(QCursor::pos())); - if(!item || item->type()!=TreeWidget::ObjectType) + if (!item || item->type() != TreeWidget::ObjectType) return; preselectTime.restart(); @@ -2671,17 +2713,17 @@ void TreeWidget::onPreSelectTimer() { auto vp = objItem->object(); auto obj = vp->getObject(); std::ostringstream ss; - App::DocumentObject *parent = 0; - objItem->getSubName(ss,parent); - if(!parent) + App::DocumentObject* parent = 0; + objItem->getSubName(ss, parent); + if (!parent) parent = obj; - else if(!obj->redirectSubName(ss,parent,0)) + else if (!obj->redirectSubName(ss, parent, 0)) ss << obj->getNameInDocument() << '.'; - Selection().setPreselect(parent->getDocument()->getName(),parent->getNameInDocument(), - ss.str().c_str(),0,0,0,2); + Selection().setPreselect(parent->getDocument()->getName(), parent->getNameInDocument(), + ss.str().c_str(), 0, 0, 0, 2); } -void TreeWidget::onItemCollapsed(QTreeWidgetItem * item) +void TreeWidget::onItemCollapsed(QTreeWidgetItem* item) { // object item collapsed if (item && item->type() == TreeWidget::ObjectType) { @@ -2689,40 +2731,41 @@ void TreeWidget::onItemCollapsed(QTreeWidgetItem * item) } } -void TreeWidget::onItemExpanded(QTreeWidgetItem * item) +void TreeWidget::onItemExpanded(QTreeWidgetItem* item) { // object item expanded if (item && item->type() == TreeWidget::ObjectType) { DocumentObjectItem* objItem = static_cast(item); objItem->setExpandedStatus(true); - objItem->getOwnerDocument()->populateItem(objItem,false,false); + objItem->getOwnerDocument()->populateItem(objItem, false, false); } } void TreeWidget::scrollItemToTop() { auto doc = Application::Instance->activeDocument(); - for(auto tree : Instances) { - if(!tree->isConnectionAttached() || tree->isConnectionBlocked()) + for (auto tree : Instances) { + if (!tree->isConnectionAttached() || tree->isConnectionBlocked()) continue; tree->_updateStatus(false); - if(doc && Gui::Selection().hasSelection(doc->getDocument()->getName(),false)) { + if (doc && Gui::Selection().hasSelection(doc->getDocument()->getName(), false)) { auto it = tree->DocumentMap.find(doc); if (it != tree->DocumentMap.end()) { bool lock = tree->blockConnection(true); it->second->selectItems(DocumentItem::SR_FORCE_EXPAND); tree->blockConnection(lock); } - } else { + } + else { tree->blockConnection(true); - for (int i=0; irootItem->childCount(); i++) { + for (int i = 0; i < tree->rootItem->childCount(); i++) { auto docItem = dynamic_cast(tree->rootItem->child(i)); - if(!docItem) + if (!docItem) continue; auto doc = docItem->document()->getDocument(); - if(Gui::Selection().hasSelection(doc->getName())) { + if (Gui::Selection().hasSelection(doc->getName())) { tree->currentDocItem = docItem; docItem->selectItems(DocumentItem::SR_FORCE_EXPAND); tree->currentDocItem = 0; @@ -2738,10 +2781,10 @@ void TreeWidget::scrollItemToTop() void TreeWidget::expandSelectedItems(TreeItemMode mode) { - if(!isConnectionAttached()) + if (!isConnectionAttached()) return; - for(auto item : selectedItems()) { + for (auto item : selectedItems()) { switch (mode) { case TreeItemMode::ExpandPath: { QTreeWidgetItem* parentItem = item->parent(); @@ -2791,7 +2834,7 @@ void TreeWidget::setupText() this->selectDependentsAction->setText(tr("Add dependent objects to selection")); this->selectDependentsAction->setStatusTip(tr("Adds all dependent objects to the selection")); - + this->closeDocAction->setText(tr("Close document")); this->closeDocAction->setStatusTip(tr("Close the document")); @@ -2803,7 +2846,7 @@ void TreeWidget::setupText() this->allowPartialRecomputeAction->setText(tr("Allow partial recomputes")); this->allowPartialRecomputeAction->setStatusTip( - tr("Enable or disable recomputating editing object when 'skip recomputation' is enabled")); + tr("Enable or disable recomputating editing object when 'skip recomputation' is enabled")); this->markRecomputeAction->setText(tr("Mark to recompute")); this->markRecomputeAction->setStatusTip(tr("Mark this object to be recomputed")); @@ -2814,12 +2857,12 @@ void TreeWidget::setupText() this->recomputeObjectAction->setIcon(BitmapFactory().iconFromTheme("view-refresh")); } -void TreeWidget::syncView(ViewProviderDocumentObject *vp) +void TreeWidget::syncView(ViewProviderDocumentObject* vp) { - if(currentDocItem && TreeParams::Instance()->SyncView()) { + if (currentDocItem && TreeParams::Instance()->SyncView()) { bool focus = hasFocus(); currentDocItem->document()->setActiveView(vp); - if(focus) + if (focus) setFocus(); } } @@ -2827,12 +2870,12 @@ void TreeWidget::syncView(ViewProviderDocumentObject *vp) void TreeWidget::onShowHidden() { if (!this->contextItem) return; - DocumentItem *docItem = nullptr; - if(this->contextItem->type() == DocumentType) + DocumentItem* docItem = nullptr; + if (this->contextItem->type() == DocumentType) docItem = static_cast(contextItem); - else if(this->contextItem->type() == ObjectType) + else if (this->contextItem->type() == ObjectType) docItem = static_cast(contextItem)->getOwnerDocument(); - if(docItem) + if (docItem) docItem->setShowHidden(showHiddenAction->isChecked()); } @@ -2844,7 +2887,7 @@ void TreeWidget::onHideInTree() } } -void TreeWidget::changeEvent(QEvent *e) +void TreeWidget::changeEvent(QEvent* e) { if (e->type() == QEvent::LanguageChange) setupText(); @@ -2852,11 +2895,11 @@ void TreeWidget::changeEvent(QEvent *e) QTreeWidget::changeEvent(e); } -void TreeWidget::onItemSelectionChanged () +void TreeWidget::onItemSelectionChanged() { if (!this->isConnectionAttached() - || this->isConnectionBlocked() - || updateBlocked) + || this->isConnectionBlocked() + || updateBlocked) return; _LastSelectedTreeWidget = this; @@ -2864,7 +2907,7 @@ void TreeWidget::onItemSelectionChanged () // block tmp. the connection to avoid to notify us ourself bool lock = this->blockConnection(true); - if(selectTimer->isActive()) + if (selectTimer->isActive()) onSelectTimer(); else _updateStatus(false); @@ -2872,59 +2915,61 @@ void TreeWidget::onItemSelectionChanged () auto selItems = selectedItems(); // do not allow document item multi-selection - if(selItems.size()) { + if (selItems.size()) { auto firstType = selItems.back()->type(); - for(auto it=selItems.begin();it!=selItems.end();) { + for (auto it = selItems.begin(); it != selItems.end();) { auto item = *it; - if((firstType==ObjectType && item->type()!=ObjectType) - || (firstType==DocumentType && item!=selItems.back())) + if ((firstType == ObjectType && item->type() != ObjectType) + || (firstType == DocumentType && item != selItems.back())) { item->setSelected(false); it = selItems.erase(it); - } else + } + else ++it; } } - if(selItems.size()<=1) { - if(TreeParams::Instance()->RecordSelection()) + if (selItems.size() <= 1) { + if (TreeParams::Instance()->RecordSelection()) Gui::Selection().selStackPush(); // This special handling to deal with possible discrepancy of // Gui.Selection and Tree view selection because of newly added // DocumentObject::redirectSubName() Selection().clearCompleteSelection(); - DocumentObjectItem *item=0; - if(selItems.size()) { - if(selItems.front()->type() == ObjectType) + DocumentObjectItem* item = 0; + if (selItems.size()) { + if (selItems.front()->type() == ObjectType) item = static_cast(selItems.front()); - else if(selItems.front()->type() == DocumentType) { + else if (selItems.front()->type() == DocumentType) { auto ditem = static_cast(selItems.front()); - if(TreeParams::Instance()->SyncView()) { + if (TreeParams::Instance()->SyncView()) { bool focus = hasFocus(); ditem->document()->setActiveView(); - if(focus) + if (focus) setFocus(); } // For triggering property editor refresh Gui::Selection().signalSelectionChanged(SelectionChanges()); } } - for(auto &v : DocumentMap) { + for (auto& v : DocumentMap) { currentDocItem = v.second; v.second->clearSelection(item); currentDocItem = 0; } - if(TreeParams::Instance()->RecordSelection()) + if (TreeParams::Instance()->RecordSelection()) Gui::Selection().selStackPush(); - }else{ - for (auto pos = DocumentMap.begin();pos!=DocumentMap.end();++pos) { + } + else { + for (auto pos = DocumentMap.begin(); pos != DocumentMap.end(); ++pos) { currentDocItem = pos->second; pos->second->updateSelection(pos->second); currentDocItem = 0; } - if(TreeParams::Instance()->RecordSelection()) - Gui::Selection().selStackPush(true,true); + if (TreeParams::Instance()->RecordSelection()) + Gui::Selection().selStackPush(true, true); } this->blockConnection(lock); @@ -2947,19 +2992,20 @@ void TreeWidget::synchronizeSelectionCheckBoxes() { resizeColumnToContents(0); } -QList TreeWidget::childrenOfItem(const QTreeWidgetItem &item) const{ - QList children = QList(); +QList TreeWidget::childrenOfItem(const QTreeWidgetItem& item) const { + QList children = QList(); // check item is in this tree - if (!this->indexFromItem(&item).isValid()) return children; + if (!this->indexFromItem(&item).isValid()) + return children; - for (int i=0 ; i < item.childCount() ; i++) { + for (int i = 0; i < item.childCount(); i++) { children.append(item.child(i)); } return children; } -void TreeWidget::onItemChanged(QTreeWidgetItem *item, int column) { +void TreeWidget::onItemChanged(QTreeWidgetItem* item, int column) { if (column == 0 && isSelectionCheckBoxesEnabled()) { bool selected = item->isSelected(); bool checked = item->checkState(0) == Qt::Checked; @@ -2975,15 +3021,16 @@ void TreeWidget::onSelectTimer() { bool syncSelect = TreeParams::Instance()->SyncSelection(); bool locked = this->blockConnection(true); - if(Selection().hasSelection()) { - for(auto &v : DocumentMap) { + if (Selection().hasSelection()) { + for (auto& v : DocumentMap) { v.second->setSelected(false); currentDocItem = v.second; - v.second->selectItems(syncSelect?DocumentItem::SR_EXPAND:DocumentItem::SR_SELECT); + v.second->selectItems(syncSelect ? DocumentItem::SR_EXPAND : DocumentItem::SR_SELECT); currentDocItem = 0; } - }else{ - for(auto &v : DocumentMap) + } + else { + for (auto& v : DocumentMap) v.second->clearSelection(); } this->blockConnection(locked); @@ -3000,7 +3047,7 @@ void TreeWidget::onSelectionChanged(const SelectionChanges& msg) case SelectionChanges::SetSelection: case SelectionChanges::ClrSelection: { int timeout = TreeParams::Instance()->SelectionTimeout(); - if(timeout<=0) + if (timeout <= 0) timeout = 1; selectTimer->start(timeout); break; @@ -3014,31 +3061,31 @@ void TreeWidget::onSelectionChanged(const SelectionChanges& msg) /* TRANSLATOR Gui::TreePanel */ -TreePanel::TreePanel(const char *name, QWidget* parent) - : QWidget(parent) +TreePanel::TreePanel(const char* name, QWidget* parent) + : QWidget(parent) { this->treeWidget = new TreeWidget(name, this); int indent = TreeParams::Instance()->Indentation(); - if(indent) + if (indent) this->treeWidget->setIndentation(indent); QVBoxLayout* pLayout = new QVBoxLayout(this); pLayout->setSpacing(0); - pLayout->setMargin (0); + pLayout->setMargin(0); pLayout->addWidget(this->treeWidget); connect(this->treeWidget, SIGNAL(emitSearchObjects()), - this, SLOT(showEditor())); + this, SLOT(showEditor())); - this->searchBox = new Gui::ExpressionLineEdit(this,true); + this->searchBox = new Gui::ExpressionLineEdit(this, true); static_cast(this->searchBox)->setExactMatch(Gui::ExpressionParameter::instance()->isExactMatch()); pLayout->addWidget(this->searchBox); this->searchBox->hide(); this->searchBox->installEventFilter(this); this->searchBox->setPlaceholderText(tr("Search")); connect(this->searchBox, SIGNAL(returnPressed()), - this, SLOT(accept())); + this, SLOT(accept())); connect(this->searchBox, SIGNAL(textChanged(QString)), - this, SLOT(itemSearch(QString))); + this, SLOT(itemSearch(QString))); } TreePanel::~TreePanel() @@ -3050,10 +3097,10 @@ void TreePanel::accept() QString text = this->searchBox->text(); hideEditor(); this->treeWidget->setFocus(); - this->treeWidget->itemSearch(text,true); + this->treeWidget->itemSearch(text, true); } -bool TreePanel::eventFilter(QObject *obj, QEvent *ev) +bool TreePanel::eventFilter(QObject* obj, QEvent* ev) { if (obj != this->searchBox) return false; @@ -3092,103 +3139,103 @@ void TreePanel::hideEditor() this->searchBox->hide(); this->treeWidget->resetItemSearch(); auto sels = this->treeWidget->selectedItems(); - if(sels.size()) + if (sels.size()) this->treeWidget->scrollToItem(sels.front()); } -void TreePanel::itemSearch(const QString &text) +void TreePanel::itemSearch(const QString& text) { - this->treeWidget->itemSearch(text,false); + this->treeWidget->itemSearch(text, false); } // ---------------------------------------------------------------------------- /* TRANSLATOR Gui::TreeDockWidget */ -TreeDockWidget::TreeDockWidget(Gui::Document* pcDocument,QWidget *parent) - : DockWindow(pcDocument,parent) +TreeDockWidget::TreeDockWidget(Gui::Document* pcDocument, QWidget* parent) + : DockWindow(pcDocument, parent) { setWindowTitle(tr("Tree view")); auto panel = new TreePanel("TreeView", this); QGridLayout* pLayout = new QGridLayout(this); pLayout->setSpacing(0); - pLayout->setMargin (0); - pLayout->addWidget(panel, 0, 0 ); + pLayout->setMargin(0); + pLayout->addWidget(panel, 0, 0); } TreeDockWidget::~TreeDockWidget() { } -void TreeWidget::selectLinkedObject(App::DocumentObject *linked) { - if(!isConnectionAttached() || isConnectionBlocked()) +void TreeWidget::selectLinkedObject(App::DocumentObject* linked) { + if (!isConnectionAttached() || isConnectionBlocked()) return; auto linkedVp = Base::freecad_dynamic_cast( - Application::Instance->getViewProvider(linked)); - if(!linkedVp) { + Application::Instance->getViewProvider(linked)); + if (!linkedVp) { TREE_ERR("invalid linked view provider"); return; } auto linkedDoc = getDocumentItem(linkedVp->getDocument()); - if(!linkedDoc) { + if (!linkedDoc) { TREE_ERR("cannot find document of linked object"); return; } - if(selectTimer->isActive()) + if (selectTimer->isActive()) onSelectTimer(); else _updateStatus(false); auto it = linkedDoc->ObjectMap.find(linked); - if(it == linkedDoc->ObjectMap.end()) { + if (it == linkedDoc->ObjectMap.end()) { TREE_ERR("cannot find tree item of linked object"); return; } auto linkedItem = it->second->rootItem; - if(!linkedItem) + if (!linkedItem) linkedItem = *it->second->items.begin(); - if(linkedDoc->showItem(linkedItem,true)) + if (linkedDoc->showItem(linkedItem, true)) scrollToItem(linkedItem); - if(linkedDoc->document()->getDocument() != App::GetApplication().getActiveDocument()) { + if (linkedDoc->document()->getDocument() != App::GetApplication().getActiveDocument()) { bool focus = hasFocus(); linkedDoc->document()->setActiveView(linkedItem->object()); - if(focus) + if (focus) setFocus(); } } // ---------------------------------------------------------------------------- -DocumentItem::DocumentItem(const Gui::Document* doc, QTreeWidgetItem * parent) +DocumentItem::DocumentItem(const Gui::Document* doc, QTreeWidgetItem* parent) : QTreeWidgetItem(parent, TreeWidget::DocumentType), pDocument(const_cast(doc)) { // Setup connections connectNewObject = doc->signalNewObject.connect(boost::bind(&DocumentItem::slotNewObject, this, bp::_1)); connectDelObject = doc->signalDeletedObject.connect( - boost::bind(&TreeWidget::slotDeleteObject, getTree(), bp::_1)); - if(!App::GetApplication().isRestoring()) { + boost::bind(&TreeWidget::slotDeleteObject, getTree(), bp::_1)); + if (!App::GetApplication().isRestoring()) { connectChgObject = doc->signalChangedObject.connect( - boost::bind(&TreeWidget::slotChangeObject, getTree(), bp::_1, bp::_2)); + boost::bind(&TreeWidget::slotChangeObject, getTree(), bp::_1, bp::_2)); connectTouchedObject = doc->getDocument()->signalTouchedObject.connect( - boost::bind(&TreeWidget::slotTouchedObject, getTree(), bp::_1)); + boost::bind(&TreeWidget::slotTouchedObject, getTree(), bp::_1)); } connectEdtObject = doc->signalInEdit.connect(boost::bind(&DocumentItem::slotInEdit, this, bp::_1)); connectResObject = doc->signalResetEdit.connect(boost::bind(&DocumentItem::slotResetEdit, this, bp::_1)); connectHltObject = doc->signalHighlightObject.connect( - boost::bind(&DocumentItem::slotHighlightObject, this, bp::_1, bp::_2, bp::_3, bp::_4, bp::_5)); + boost::bind(&DocumentItem::slotHighlightObject, this, bp::_1, bp::_2, bp::_3, bp::_4, bp::_5)); connectExpObject = doc->signalExpandObject.connect( - boost::bind(&DocumentItem::slotExpandObject, this, bp::_1, bp::_2, bp::_3, bp::_4)); + boost::bind(&DocumentItem::slotExpandObject, this, bp::_1, bp::_2, bp::_3, bp::_4)); connectScrObject = doc->signalScrollToObject.connect(boost::bind(&DocumentItem::slotScrollToObject, this, bp::_1)); auto adoc = doc->getDocument(); connectRecomputed = adoc->signalRecomputed.connect(boost::bind(&DocumentItem::slotRecomputed, this, bp::_1, bp::_2)); connectRecomputedObj = adoc->signalRecomputedObject.connect( - boost::bind(&DocumentItem::slotRecomputedObject, this, bp::_1)); + boost::bind(&DocumentItem::slotRecomputedObject, this, bp::_1)); - setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable/*|Qt::ItemIsEditable*/); + setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable/*|Qt::ItemIsEditable*/); treeName = getTree()->getTreeName(); } @@ -3208,11 +3255,11 @@ DocumentItem::~DocumentItem() connectRecomputedObj.disconnect(); } -TreeWidget *DocumentItem::getTree() const{ +TreeWidget* DocumentItem::getTree() const { return static_cast(treeWidget()); } -const char *DocumentItem::getTreeName() const { +const char* DocumentItem::getTreeName() const { return treeName; } @@ -3235,27 +3282,27 @@ void DocumentItem::slotInEdit(const Gui::ViewProviderDocumentObject& v) (void)v; ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/TreeView"); - unsigned long col = hGrp->GetUnsigned("TreeEditColor",4294902015); - QColor color((col >> 24) & 0xff,(col >> 16) & 0xff,(col >> 8) & 0xff); + unsigned long col = hGrp->GetUnsigned("TreeEditColor", 4294902015); + QColor color((col >> 24) & 0xff, (col >> 16) & 0xff, (col >> 8) & 0xff); - if(!getTree()->editingItem) { + if (!getTree()->editingItem) { auto doc = Application::Instance->editDocument(); - if(!doc) + if (!doc) return; - ViewProviderDocumentObject *parentVp=0; + ViewProviderDocumentObject* parentVp = 0; std::string subname; - auto vp = doc->getInEdit(&parentVp,&subname); - if(!parentVp) + auto vp = doc->getInEdit(&parentVp, &subname); + if (!parentVp) parentVp = dynamic_cast(vp); - if(parentVp) - getTree()->editingItem = findItemByObject(true,parentVp->getObject(),subname.c_str()); + if (parentVp) + getTree()->editingItem = findItemByObject(true, parentVp->getObject(), subname.c_str()); } - if(getTree()->editingItem) - getTree()->editingItem->setBackground(0,color); - else{ - FOREACH_ITEM(item,v) - item->setBackground(0,color); + if (getTree()->editingItem) + getTree()->editingItem->setBackground(0, color); + else { + FOREACH_ITEM(item, v) + item->setBackground(0, color); END_FOREACH_ITEM } } @@ -3264,19 +3311,20 @@ void DocumentItem::slotResetEdit(const Gui::ViewProviderDocumentObject& v) { auto tree = getTree(); FOREACH_ITEM_ALL(item) - if(tree->editingItem) { - if(item == tree->editingItem) { - item->setData(0, Qt::BackgroundRole,QVariant()); + if (tree->editingItem) { + if (item == tree->editingItem) { + item->setData(0, Qt::BackgroundRole, QVariant()); break; } - }else if(item->object() == &v) - item->setData(0, Qt::BackgroundRole,QVariant()); + } + else if (item->object() == &v) + item->setData(0, Qt::BackgroundRole, QVariant()); END_FOREACH_ITEM - tree->editingItem = 0; + tree->editingItem = 0; } void DocumentItem::slotNewObject(const Gui::ViewProviderDocumentObject& obj) { - if(!obj.getObject() || !obj.getObject()->getNameInDocument()) { + if (!obj.getObject() || !obj.getObject()->getNameInDocument()) { FC_ERR("view provider not attached"); return; } @@ -3285,48 +3333,49 @@ void DocumentItem::slotNewObject(const Gui::ViewProviderDocumentObject& obj) { } bool DocumentItem::createNewItem(const Gui::ViewProviderDocumentObject& obj, - QTreeWidgetItem *parent, int index, DocumentObjectDataPtr data) + QTreeWidgetItem* parent, int index, DocumentObjectDataPtr data) { - const char *name; + const char* name; if (!obj.getObject() || - !(name=obj.getObject()->getNameInDocument()) || + !(name = obj.getObject()->getNameInDocument()) || obj.getObject()->testStatus(App::PartialObject)) return false; - if(!data) { - auto &pdata = ObjectMap[obj.getObject()]; - if(!pdata) { + if (!data) { + auto& pdata = ObjectMap[obj.getObject()]; + if (!pdata) { pdata = std::make_shared( - this, const_cast(&obj)); - auto &entry = getTree()->ObjectTable[obj.getObject()]; - if(entry.size()) + this, const_cast(&obj)); + auto& entry = getTree()->ObjectTable[obj.getObject()]; + if (entry.size()) pdata->updateChildren(*entry.begin()); else pdata->updateChildren(true); entry.insert(pdata); - }else if(pdata->rootItem && parent==NULL) { + } + else if (pdata->rootItem && parent == NULL) { Base::Console().Warning("DocumentItem::slotNewObject: Cannot add view provider twice.\n"); return false; } data = pdata; } - DocumentObjectItem* item = new DocumentObjectItem(this,data); - if(!parent || parent==this) { + DocumentObjectItem* item = new DocumentObjectItem(this, data); + if (!parent || parent == this) { parent = this; data->rootItem = item; - if(index<0) + if (index < 0) index = findRootIndex(obj.getObject()); } - if(index<0) + if (index < 0) parent->addChild(item); else - parent->insertChild(index,item); + parent->insertChild(index, item); assert(item->parent() == parent); item->setText(0, QString::fromUtf8(data->label.c_str())); - if(data->label2.size()) + if (data->label2.size()) item->setText(1, QString::fromUtf8(data->label2.c_str())); - if(!obj.showInTree() && !showHidden()) + if (!obj.showInTree() && !showHidden()) item->setHidden(true); item->testStatus(true); @@ -3334,7 +3383,7 @@ bool DocumentItem::createNewItem(const Gui::ViewProviderDocumentObject& obj, return true; } -ViewProviderDocumentObject *DocumentItem::getViewProvider(App::DocumentObject *obj) { +ViewProviderDocumentObject* DocumentItem::getViewProvider(App::DocumentObject* obj) { // Note: It is possible that we receive an invalid pointer from // claimChildren(), e.g. if multiple properties were changed in // a transaction and slotChangedObject() is triggered by one @@ -3351,14 +3400,14 @@ ViewProviderDocumentObject *DocumentItem::getViewProvider(App::DocumentObject *o // getNameInDocument() check be sufficient? - if(!obj || !obj->getNameInDocument()) return 0; + if (!obj || !obj->getNameInDocument()) return 0; - ViewProvider *vp; - if(obj->getDocument() == pDocument->getDocument()) + ViewProvider* vp; + if (obj->getDocument() == pDocument->getDocument()) vp = pDocument->getViewProvider(obj); else vp = Application::Instance->getViewProvider(obj); - if(!vp || !vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) + if (!vp || !vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) return 0; return static_cast(vp); } @@ -3368,19 +3417,19 @@ void TreeWidget::slotDeleteDocument(const Gui::Document& Doc) NewObjects.erase(Doc.getDocument()->getName()); auto it = DocumentMap.find(&Doc); if (it != DocumentMap.end()) { - UpdateDisabler disabler(*this,updateBlocked); + UpdateDisabler disabler(*this, updateBlocked); auto docItem = it->second; - for(auto &v : docItem->ObjectMap) { - for(auto item : v.second->items) + for (auto& v : docItem->ObjectMap) { + for (auto item : v.second->items) item->myOwner = 0; auto obj = v.second->viewObject->getObject(); - if(obj->getDocument() == Doc.getDocument()) { + if (obj->getDocument() == Doc.getDocument()) { _slotDeleteObject(*v.second->viewObject, docItem); continue; } auto it = ObjectTable.find(obj); - assert(it!=ObjectTable.end()); - assert(it->second.size()>1); + assert(it != ObjectTable.end()); + assert(it->second.size() > 1); it->second.erase(v.second); } this->rootItem->takeChild(this->rootItem->indexOfChild(docItem)); @@ -3393,14 +3442,14 @@ void TreeWidget::slotDeleteObject(const Gui::ViewProviderDocumentObject& view) { _slotDeleteObject(view, 0); } -void TreeWidget::_slotDeleteObject(const Gui::ViewProviderDocumentObject& view, DocumentItem *deletingDoc) +void TreeWidget::_slotDeleteObject(const Gui::ViewProviderDocumentObject& view, DocumentItem* deletingDoc) { auto obj = view.getObject(); auto itEntry = ObjectTable.find(obj); - if(itEntry == ObjectTable.end()) + if (itEntry == ObjectTable.end()) return; - if(itEntry->second.empty()) { + if (itEntry->second.empty()) { ObjectTable.erase(itEntry); return; } @@ -3409,41 +3458,41 @@ void TreeWidget::_slotDeleteObject(const Gui::ViewProviderDocumentObject& view, bool needUpdate = false; - for(auto data : itEntry->second) { - DocumentItem *docItem = data->docItem; - if(docItem == deletingDoc) + for (auto data : itEntry->second) { + DocumentItem* docItem = data->docItem; + if (docItem == deletingDoc) continue; auto doc = docItem->document()->getDocument(); - auto &items = data->items; + auto& items = data->items; - if(obj->getDocument() == doc) + if (obj->getDocument() == doc) docItem->_ParentMap.erase(obj); bool lock = blockConnection(true); - for(auto cit=items.begin(),citNext=cit;cit!=items.end();cit=citNext) { + for (auto cit = items.begin(), citNext = cit; cit != items.end(); cit = citNext) { ++citNext; (*cit)->myOwner = 0; - delete *cit; + delete* cit; } blockConnection(lock); // Check for any child of the deleted object that is not in the tree, and put it // under document item. - for(auto child : data->children) { + for (auto child : data->children) { auto childVp = docItem->getViewProvider(child); if (!childVp || child->getDocument() != doc) continue; docItem->_ParentMap[child].erase(obj); auto cit = docItem->ObjectMap.find(child); - if (cit==docItem->ObjectMap.end() || cit->second->items.empty()) { + if (cit == docItem->ObjectMap.end() || cit->second->items.empty()) { if (docItem->createNewItem(*childVp)) needUpdate = true; } else { auto childItem = *cit->second->items.begin(); if (childItem->requiredAtRoot(false)) { - if (docItem->createNewItem(*childItem->object(),docItem,-1,childItem->myData)) + if (docItem->createNewItem(*childItem->object(), docItem, -1, childItem->myData)) needUpdate = true; } } @@ -3453,30 +3502,30 @@ void TreeWidget::_slotDeleteObject(const Gui::ViewProviderDocumentObject& view, } ObjectTable.erase(itEntry); - if(needUpdate) + if (needUpdate) _updateStatus(); } -bool DocumentItem::populateObject(App::DocumentObject *obj) { +bool DocumentItem::populateObject(App::DocumentObject* obj) { // make sure at least one of the item corresponding to obj is populated auto it = ObjectMap.find(obj); - if(it == ObjectMap.end()) + if (it == ObjectMap.end()) return false; - auto &items = it->second->items; - if(items.empty()) + auto& items = it->second->items; + if (items.empty()) return false; - for(auto item : items) { - if(item->populated) + for (auto item : items) { + if (item->populated) return true; } TREE_LOG("force populate object " << obj->getFullName()); auto item = *items.begin(); item->populated = true; - populateItem(item,true); + populateItem(item, true); return true; } -void DocumentItem::populateItem(DocumentObjectItem *item, bool refresh, bool delay) +void DocumentItem::populateItem(DocumentObjectItem* item, bool refresh, bool delay) { (void)delay; @@ -3487,29 +3536,29 @@ void DocumentItem::populateItem(DocumentObjectItem *item, bool refresh, bool del // a) the item is expanded, or b) there is at least one free child, i.e. // child originally located at root. - item->setChildIndicatorPolicy(item->myData->children.empty()? - QTreeWidgetItem::DontShowIndicator:QTreeWidgetItem::ShowIndicator); + item->setChildIndicatorPolicy(item->myData->children.empty() ? + QTreeWidgetItem::DontShowIndicator : QTreeWidgetItem::ShowIndicator); if (!item->populated && !item->isExpanded()) { bool doPopulate = false; - bool external = item->object()->getDocument()!=item->getOwnerDocument()->document(); - if(external) + bool external = item->object()->getDocument() != item->getOwnerDocument()->document(); + if (external) return; auto obj = item->object()->getObject(); auto linked = obj->getLinkedObject(true); - if (linked && linked->getDocument()!=obj->getDocument()) + if (linked && linked->getDocument() != obj->getDocument()) return; - for(auto child : item->myData->children) { + for (auto child : item->myData->children) { auto it = ObjectMap.find(child); - if(it == ObjectMap.end() || it->second->items.empty()) { + if (it == ObjectMap.end() || it->second->items.empty()) { auto vp = getViewProvider(child); - if(!vp) continue; + if (!vp) continue; doPopulate = true; break; } - if(item->myData->removeChildrenFromRoot) { - if(it->second->rootItem) { + if (item->myData->removeChildrenFromRoot) { + if (it->second->rootItem) { doPopulate = true; break; } @@ -3524,45 +3573,46 @@ void DocumentItem::populateItem(DocumentObjectItem *item, bool refresh, bool del bool checkHidden = !showHidden(); bool updated = false; - int i=-1; + int i = -1; // iterate through the claimed children, and try to synchronize them with the // children tree item with the same order of appearance. int childCount = item->childCount(); - for(auto child : item->myData->children) { + for (auto child : item->myData->children) { ++i; // the current index of the claimed child bool found = false; - for (int j=i;jchild(j); + for (int j = i; j < childCount; ++j) { + QTreeWidgetItem* ci = item->child(j); if (ci->type() != TreeWidget::ObjectType) continue; - DocumentObjectItem *childItem = static_cast(ci); + DocumentObjectItem* childItem = static_cast(ci); if (childItem->object()->getObject() != child) continue; found = true; - if (j!=i) { // fix index if it is changed + if (j != i) { // fix index if it is changed childItem->setHighlight(false); item->removeChild(ci); - item->insertChild(i,ci); - assert(ci->parent()==item); - if(checkHidden) - updateItemsVisibility(ci,false); + item->insertChild(i, ci); + assert(ci->parent() == item); + if (checkHidden) + updateItemsVisibility(ci, false); } // Check if the item just changed its policy of whether to remove // children item from the root. - if(item->myData->removeChildrenFromRoot) { - if(childItem->myData->rootItem) { + if (item->myData->removeChildrenFromRoot) { + if (childItem->myData->rootItem) { assert(childItem != childItem->myData->rootItem); bool lock = getTree()->blockConnection(true); delete childItem->myData->rootItem; getTree()->blockConnection(lock); } - }else if(childItem->requiredAtRoot()) { - createNewItem(*childItem->object(),this,-1,childItem->myData); + } + else if (childItem->requiredAtRoot()) { + createNewItem(*childItem->object(), this, -1, childItem->myData); updated = true; } break; @@ -3575,24 +3625,25 @@ void DocumentItem::populateItem(DocumentObjectItem *item, bool refresh, bool del // through slotNewObject -> populateItem auto it = ObjectMap.find(child); - if(it==ObjectMap.end() || it->second->items.empty()) { + if (it == ObjectMap.end() || it->second->items.empty()) { auto vp = getViewProvider(child); - if(!vp || !createNewItem(*vp,item,i,it==ObjectMap.end()?DocumentObjectDataPtr():it->second)) + if (!vp || !createNewItem(*vp, item, i, it == ObjectMap.end() ? DocumentObjectDataPtr() : it->second)) --i; else updated = true; continue; } - if(!item->myData->removeChildrenFromRoot || !it->second->rootItem) { - DocumentObjectItem *childItem = *it->second->items.begin(); - if(!createNewItem(*childItem->object(),item,i,it->second)) + if (!item->myData->removeChildrenFromRoot || !it->second->rootItem) { + DocumentObjectItem* childItem = *it->second->items.begin(); + if (!createNewItem(*childItem->object(), item, i, it->second)) --i; else updated = true; - }else { - DocumentObjectItem *childItem = it->second->rootItem; - if(item==childItem || item->isChildOfItem(childItem)) { + } + else { + DocumentObjectItem* childItem = it->second->rootItem; + if (item == childItem || item->isChildOfItem(childItem)) { TREE_ERR("Cyclic dependency in " << item->object()->getObject()->getFullName() << '.' << childItem->object()->getObject()->getFullName()); @@ -3602,27 +3653,27 @@ void DocumentItem::populateItem(DocumentObjectItem *item, bool refresh, bool del it->second->rootItem = 0; childItem->setHighlight(false); this->removeChild(childItem); - item->insertChild(i,childItem); - assert(childItem->parent()==item); - if(checkHidden) - updateItemsVisibility(childItem,false); + item->insertChild(i, childItem); + assert(childItem->parent() == item); + if (checkHidden) + updateItemsVisibility(childItem, false); } } - for (++i;item->childCount()>i;) { - QTreeWidgetItem *ci = item->child(i); + for (++i; item->childCount() > i;) { + QTreeWidgetItem* ci = item->child(i); if (ci->type() == TreeWidget::ObjectType) { DocumentObjectItem* childItem = static_cast(ci); - if(childItem->requiredAtRoot()) { + if (childItem->requiredAtRoot()) { item->removeChild(childItem); auto index = findRootIndex(childItem->object()->getObject()); - if(index>=0) - this->insertChild(index,childItem); + if (index >= 0) + this->insertChild(index, childItem); else this->addChild(childItem); - assert(childItem->parent()==this); - if(checkHidden) - updateItemsVisibility(childItem,false); + assert(childItem->parent() == this); + if (checkHidden) + updateItemsVisibility(childItem, false); childItem->myData->rootItem = childItem; continue; } @@ -3632,40 +3683,40 @@ void DocumentItem::populateItem(DocumentObjectItem *item, bool refresh, bool del delete ci; getTree()->blockConnection(lock); } - if(updated) + if (updated) getTree()->_updateStatus(); } -int DocumentItem::findRootIndex(App::DocumentObject *childObj) { - if(!TreeParams::Instance()->KeepRootOrder() || !childObj || !childObj->getNameInDocument()) +int DocumentItem::findRootIndex(App::DocumentObject* childObj) { + if (!TreeParams::Instance()->KeepRootOrder() || !childObj || !childObj->getNameInDocument()) return -1; // object id is monotonically increasing, so use this as a hint to insert // object back so that we can have a stable order in root level. int count = this->childCount(); - if(!count) + if (!count) return -1; - int first,last; + int first, last; // find the last item - for(last=count-1;last>=0;--last) { + for (last = count - 1; last >= 0; --last) { auto citem = this->child(last); - if(citem->type() == TreeWidget::ObjectType) { + if (citem->type() == TreeWidget::ObjectType) { auto obj = static_cast(citem)->object()->getObject(); - if(obj->getID()<=childObj->getID()) - return last+1; + if (obj->getID() <= childObj->getID()) + return last + 1; break; } } // find the first item - for(first=0;firstchild(first); - if(citem->type() == TreeWidget::ObjectType) { + if (citem->type() == TreeWidget::ObjectType) { auto obj = static_cast(citem)->object()->getObject(); - if(obj->getID()>=childObj->getID()) + if (obj->getID() >= childObj->getID()) return first; break; } @@ -3673,186 +3724,188 @@ int DocumentItem::findRootIndex(App::DocumentObject *childObj) { // now do a binary search to find the lower bound, assuming the root level // object is already in order - count = last-first; + count = last - first; int pos; while (count > 0) { int step = count / 2; pos = first + step; - for(;pos<=last;++pos) { + for (; pos <= last; ++pos) { auto citem = this->child(pos); - if(citem->type() != TreeWidget::ObjectType) + if (citem->type() != TreeWidget::ObjectType) continue; auto obj = static_cast(citem)->object()->getObject(); - if(obj->getID()getID()) { + if (obj->getID() < childObj->getID()) { first = ++pos; - count -= step+1; - } else + count -= step + 1; + } + else count = step; break; } - if(pos>last) + if (pos > last) return -1; } - if(first>last) + if (first > last) return -1; return first; } void TreeWidget::slotChangeObject( - const Gui::ViewProviderDocumentObject& view, const App::Property &prop) { + const Gui::ViewProviderDocumentObject& view, const App::Property& prop) { auto obj = view.getObject(); - if(!obj || !obj->getNameInDocument()) + if (!obj || !obj->getNameInDocument()) return; auto itEntry = ObjectTable.find(obj); - if(itEntry == ObjectTable.end() || itEntry->second.empty()) + if (itEntry == ObjectTable.end() || itEntry->second.empty()) return; _updateStatus(); // Let's not waste time on the newly added Visibility property in // DocumentObject. - if(&prop == &obj->Visibility) + if (&prop == &obj->Visibility) return; - if(&prop == &obj->Label) { - const char *label = obj->Label.getValue(); + if (&prop == &obj->Label) { + const char* label = obj->Label.getValue(); auto firstData = *itEntry->second.begin(); - if(firstData->label != label) { - for(auto data : itEntry->second) { + if (firstData->label != label) { + for (auto data : itEntry->second) { data->label = label; auto displayName = QString::fromUtf8(label); - for(auto item : data->items) + for (auto item : data->items) item->setText(0, displayName); } } return; } - if(&prop == &obj->Label2) { - const char *label = obj->Label2.getValue(); + if (&prop == &obj->Label2) { + const char* label = obj->Label2.getValue(); auto firstData = *itEntry->second.begin(); - if(firstData->label2 != label) { - for(auto data : itEntry->second) { + if (firstData->label2 != label) { + for (auto data : itEntry->second) { data->label2 = label; auto displayName = QString::fromUtf8(label); - for(auto item : data->items) + for (auto item : data->items) item->setText(1, displayName); } } return; } - auto &s = ChangedObjects[obj]; - if(prop.testStatus(App::Property::Output) - || prop.testStatus(App::Property::NoRecompute)) + auto& s = ChangedObjects[obj]; + if (prop.testStatus(App::Property::Output) + || prop.testStatus(App::Property::NoRecompute)) { s.set(CS_Output); } } -void TreeWidget::updateChildren(App::DocumentObject *obj, - const std::set &dataSet, bool propOutput, bool force) +void TreeWidget::updateChildren(App::DocumentObject* obj, + const std::set& dataSet, bool propOutput, bool force) { bool childrenChanged = false; std::vector children; bool removeChildrenFromRoot = true; DocumentObjectDataPtr found; - for(auto data : dataSet) { - if(!found) { + for (auto data : dataSet) { + if (!found) { found = data; childrenChanged = found->updateChildren(force); removeChildrenFromRoot = found->viewObject->canRemoveChildrenFromRoot(); - if(!childrenChanged && found->removeChildrenFromRoot==removeChildrenFromRoot) + if (!childrenChanged && found->removeChildrenFromRoot == removeChildrenFromRoot) return; - }else if(childrenChanged) + } + else if (childrenChanged) data->updateChildren(found); data->removeChildrenFromRoot = removeChildrenFromRoot; DocumentItem* docItem = data->docItem; - for(auto item : data->items) - docItem->populateItem(item,true); + for (auto item : data->items) + docItem->populateItem(item, true); } - if(force) + if (force) return; - if(childrenChanged && propOutput) { + if (childrenChanged && propOutput) { // When a property is marked as output, it will not touch its object, // and thus, its property change will not be propagated through // recomputation. So we have to manually check for each links here. - for(auto link : App::GetApplication().getLinksTo(obj,App::GetLinkRecursive)) { - if(ChangedObjects.count(link)) + for (auto link : App::GetApplication().getLinksTo(obj, App::GetLinkRecursive)) { + if (ChangedObjects.count(link)) continue; std::vector linkedChildren; DocumentObjectDataPtr found; auto it = ObjectTable.find(link); - if(it == ObjectTable.end()) + if (it == ObjectTable.end()) continue; - for(auto data : it->second) { - if(!found) { + for (auto data : it->second) { + if (!found) { found = data; - if(!found->updateChildren(false)) + if (!found->updateChildren(false)) break; } data->updateChildren(found); DocumentItem* docItem = data->docItem; - for(auto item : data->items) - docItem->populateItem(item,true); + for (auto item : data->items) + docItem->populateItem(item, true); } } } - if(childrenChanged) { - if(!selectTimer->isActive()) + if (childrenChanged) { + if (!selectTimer->isActive()) onSelectionChanged(SelectionChanges()); //if the item is in a GeoFeatureGroup we may need to update that too, as the claim children //of the geofeaturegroup depends on what the childs claim auto grp = App::GeoFeatureGroupExtension::getGroupOfObject(obj); - if(grp && !ChangedObjects.count(grp)) { + if (grp && !ChangedObjects.count(grp)) { auto iter = ObjectTable.find(grp); - if(iter!=ObjectTable.end()) - updateChildren(grp,iter->second,true,false); + if (iter != ObjectTable.end()) + updateChildren(grp, iter->second, true, false); } } } -void DocumentItem::slotHighlightObject (const Gui::ViewProviderDocumentObject& obj, - const Gui::HighlightMode& high, bool set, const App::DocumentObject *parent, const char *subname) +void DocumentItem::slotHighlightObject(const Gui::ViewProviderDocumentObject& obj, + const Gui::HighlightMode& high, bool set, const App::DocumentObject* parent, const char* subname) { getTree()->_updateStatus(false); - if(parent && parent->getDocument()!=document()->getDocument()) { + if (parent && parent->getDocument() != document()->getDocument()) { auto it = getTree()->DocumentMap.find(Application::Instance->getDocument(parent->getDocument())); - if(it!=getTree()->DocumentMap.end()) - it->second->slotHighlightObject(obj,high,set,parent,subname); + if (it != getTree()->DocumentMap.end()) + it->second->slotHighlightObject(obj, high, set, parent, subname); return; } - FOREACH_ITEM(item,obj) - if(parent) { - App::DocumentObject *topParent = 0; + FOREACH_ITEM(item, obj) + if (parent) { + App::DocumentObject* topParent = 0; std::ostringstream ss; - item->getSubName(ss,topParent); - if(!topParent) { - if(parent!=obj.getObject()) + item->getSubName(ss, topParent); + if (!topParent) { + if (parent != obj.getObject()) continue; } } - item->setHighlight(set,high); - if(parent) - return; + item->setHighlight(set, high); + if (parent) + return; END_FOREACH_ITEM } -static unsigned int countExpandedItem(const QTreeWidgetItem *item) { +static unsigned int countExpandedItem(const QTreeWidgetItem* item) { unsigned int size = 0; - for(int i=0,count=item->childCount();ichildCount(); i < count; ++i) { auto citem = item->child(i); - if(citem->type()!=TreeWidget::ObjectType || !citem->isExpanded()) + if (citem->type() != TreeWidget::ObjectType || !citem->isExpanded()) continue; auto obj = static_cast(citem)->object()->getObject(); - if(obj->getNameInDocument()) + if (obj->getNameInDocument()) size += strlen(obj->getNameInDocument()) + countExpandedItem(citem); } return size; @@ -3862,179 +3915,181 @@ unsigned int DocumentItem::getMemSize(void) const { return countExpandedItem(this); } -static void saveExpandedItem(Base::Writer &writer, const QTreeWidgetItem *item) { +static void saveExpandedItem(Base::Writer& writer, const QTreeWidgetItem* item) { int itemCount = 0; - for(int i=0,count=item->childCount();ichildCount(); i < count; ++i) { auto citem = item->child(i); - if(citem->type()!=TreeWidget::ObjectType || !citem->isExpanded()) + if (citem->type() != TreeWidget::ObjectType || !citem->isExpanded()) continue; auto obj = static_cast(citem)->object()->getObject(); - if(obj->getNameInDocument()) + if (obj->getNameInDocument()) ++itemCount; } - if(!itemCount) { + if (!itemCount) { writer.Stream() << "/>" << std::endl; return; } - writer.Stream() << " count=\"" << itemCount << "\">" <" << std::endl; writer.incInd(); - for(int i=0,count=item->childCount();ichildCount(); i < count; ++i) { auto citem = item->child(i); - if(citem->type()!=TreeWidget::ObjectType || !citem->isExpanded()) + if (citem->type() != TreeWidget::ObjectType || !citem->isExpanded()) continue; auto obj = static_cast(citem)->object()->getObject(); - if(obj->getNameInDocument()) { + if (obj->getNameInDocument()) { writer.Stream() << writer.ind() << "getNameInDocument() << "\""; - saveExpandedItem(writer,static_cast(citem)); + saveExpandedItem(writer, static_cast(citem)); } } writer.decInd(); writer.Stream() << writer.ind() << "" << std::endl; } -void DocumentItem::Save (Base::Writer &writer) const { +void DocumentItem::Save(Base::Writer& writer) const { writer.Stream() << writer.ind() << "restore(reader); - for(auto inst : TreeWidget::Instances) { - if(inst!=getTree()) { + for (auto inst : TreeWidget::Instances) { + if (inst != getTree()) { auto docItem = inst->getDocumentItem(document()); - if(docItem) + if (docItem) docItem->_ExpandInfo = _ExpandInfo; } } } -void DocumentItem::restoreItemExpansion(const ExpandInfoPtr &info, DocumentObjectItem *item) { +void DocumentItem::restoreItemExpansion(const ExpandInfoPtr& info, DocumentObjectItem* item) { item->setExpanded(true); - if(!info) + if (!info) return; - for(int i=0,count=item->childCount();ichildCount(); i < count; ++i) { auto citem = item->child(i); - if(citem->type() != TreeWidget::ObjectType) + if (citem->type() != TreeWidget::ObjectType) continue; auto obj = static_cast(citem)->object()->getObject(); - if(!obj->getNameInDocument()) + if (!obj->getNameInDocument()) continue; auto it = info->find(obj->getNameInDocument()); - if(it != info->end()) - restoreItemExpansion(it->second,static_cast(citem)); + if (it != info->end()) + restoreItemExpansion(it->second, static_cast(citem)); } } -void DocumentItem::slotExpandObject (const Gui::ViewProviderDocumentObject& obj, - const Gui::TreeItemMode& mode, const App::DocumentObject *parent, const char *subname) +void DocumentItem::slotExpandObject(const Gui::ViewProviderDocumentObject& obj, + const Gui::TreeItemMode& mode, const App::DocumentObject* parent, const char* subname) { getTree()->_updateStatus(false); if ((mode == TreeItemMode::ExpandItem || - mode == TreeItemMode::ExpandPath) && + mode == TreeItemMode::ExpandPath) && obj.getDocument()->getDocument()->testStatus(App::Document::Restoring)) { if (!_ExpandInfo) _ExpandInfo.reset(new ExpandInfo); - _ExpandInfo->emplace(std::string("*") + obj.getObject()->getNameInDocument(),ExpandInfoPtr()); + _ExpandInfo->emplace(std::string("*") + obj.getObject()->getNameInDocument(), ExpandInfoPtr()); return; } - if (parent && parent->getDocument()!=document()->getDocument()) { + if (parent && parent->getDocument() != document()->getDocument()) { auto it = getTree()->DocumentMap.find(Application::Instance->getDocument(parent->getDocument())); - if (it!=getTree()->DocumentMap.end()) - it->second->slotExpandObject(obj,mode,parent,subname); + if (it != getTree()->DocumentMap.end()) + it->second->slotExpandObject(obj, mode, parent, subname); return; } - FOREACH_ITEM(item,obj) + FOREACH_ITEM(item, obj) // All document object items must always have a parent, either another // object item or document item. If not, then there is a bug somewhere // else. assert(item->parent()); - switch (mode) { - case TreeItemMode::ExpandPath: - if(!parent) { - QTreeWidgetItem* parentItem = item->parent(); - while (parentItem) { - parentItem->setExpanded(true); - parentItem = parentItem->parent(); - } - item->setExpanded(true); - break; + switch (mode) { + case TreeItemMode::ExpandPath: + if (!parent) { + QTreeWidgetItem* parentItem = item->parent(); + while (parentItem) { + parentItem->setExpanded(true); + parentItem = parentItem->parent(); } - // fall through - case TreeItemMode::ExpandItem: - if(!parent) { - if(item->parent()->isExpanded()) - item->setExpanded(true); - }else{ - App::DocumentObject *topParent = 0; - std::ostringstream ss; - item->getSubName(ss,topParent); - if(!topParent) { - if(parent!=obj.getObject()) - continue; - }else if(topParent!=parent) - continue; - showItem(item,false,true); - item->setExpanded(true); - } - break; - case TreeItemMode::CollapseItem: - item->setExpanded(false); - break; - case TreeItemMode::ToggleItem: - if (item->isExpanded()) - item->setExpanded(false); - else - item->setExpanded(true); - break; - - default: + item->setExpanded(true); break; } - if(item->isExpanded()) - populateItem(item); - if(parent) - return; + // fall through + case TreeItemMode::ExpandItem: + if (!parent) { + if (item->parent()->isExpanded()) + item->setExpanded(true); + } + else { + App::DocumentObject* topParent = 0; + std::ostringstream ss; + item->getSubName(ss, topParent); + if (!topParent) { + if (parent != obj.getObject()) + continue; + } + else if (topParent != parent) + continue; + showItem(item, false, true); + item->setExpanded(true); + } + break; + case TreeItemMode::CollapseItem: + item->setExpanded(false); + break; + case TreeItemMode::ToggleItem: + if (item->isExpanded()) + item->setExpanded(false); + else + item->setExpanded(true); + break; + + default: + break; + } + if (item->isExpanded()) + populateItem(item); + if (parent) + return; END_FOREACH_ITEM } void DocumentItem::slotScrollToObject(const Gui::ViewProviderDocumentObject& obj) { - if(!obj.getObject() || !obj.getObject()->getNameInDocument()) + if (!obj.getObject() || !obj.getObject()->getNameInDocument()) return; auto it = ObjectMap.find(obj.getObject()); - if(it == ObjectMap.end() || it->second->items.empty()) + if (it == ObjectMap.end() || it->second->items.empty()) return; auto item = it->second->rootItem; - if(!item) + if (!item) item = *it->second->items.begin(); getTree()->_updateStatus(false); getTree()->scrollToItem(item); } -void DocumentItem::slotRecomputedObject(const App::DocumentObject &obj) { - if(obj.isValid()) +void DocumentItem::slotRecomputedObject(const App::DocumentObject& obj) { + if (obj.isValid()) return; - slotRecomputed(*obj.getDocument(), {const_cast(&obj)}); + slotRecomputed(*obj.getDocument(), { const_cast(&obj) }); } -void DocumentItem::slotRecomputed(const App::Document &, const std::vector &objs) { +void DocumentItem::slotRecomputed(const App::Document&, const std::vector& objs) { auto tree = getTree(); - for(auto obj : objs) { - if(!obj->isValid()) + for (auto obj : objs) { + if (!obj->isValid()) tree->ChangedObjects[obj].set(TreeWidget::CS_Error); } - if(tree->ChangedObjects.size()) + if (tree->ChangedObjects.size()) tree->_updateStatus(); } @@ -4060,11 +4115,11 @@ Gui::Document* DocumentItem::document() const void DocumentItem::testStatus(void) { - for(const auto &v : ObjectMap) + for (const auto& v : ObjectMap) v.second->testStatus(); } -void DocumentItem::setData (int column, int role, const QVariant & value) +void DocumentItem::setData(int column, int role, const QVariant& value) { if (role == Qt::EditRole) { QString label = value.toString(); @@ -4074,93 +4129,94 @@ void DocumentItem::setData (int column, int role, const QVariant & value) QTreeWidgetItem::setData(column, role, value); } -void DocumentItem::clearSelection(DocumentObjectItem *exclude) +void DocumentItem::clearSelection(DocumentObjectItem* exclude) { // Block signals here otherwise we get a recursion and quadratic runtime bool ok = treeWidget()->blockSignals(true); FOREACH_ITEM_ALL(item); - if(item==exclude) { - if(item->selected>0) - item->selected = -1; - else - item->selected = 0; - updateItemSelection(item); - }else{ + if (item == exclude) { + if (item->selected > 0) + item->selected = -1; + else item->selected = 0; - item->mySubs.clear(); - item->setSelected(false); - item->setCheckState(false); - } + updateItemSelection(item); + } + else { + item->selected = 0; + item->mySubs.clear(); + item->setSelected(false); + item->setCheckState(false); + } END_FOREACH_ITEM; treeWidget()->blockSignals(ok); } -void DocumentItem::updateSelection(QTreeWidgetItem *ti, bool unselect) { - for(int i=0,count=ti->childCount();ichildCount(); i < count; ++i) { auto child = ti->child(i); - if(child && child->type()==TreeWidget::ObjectType) { + if (child && child->type() == TreeWidget::ObjectType) { auto childItem = static_cast(child); if (unselect) { childItem->setSelected(false); childItem->setCheckState(false); } updateItemSelection(childItem); - if(unselect && childItem->isGroup()) { + if (unselect && childItem->isGroup()) { // If the child item being force unselected by its group parent // is itself a group, propagate the unselection to its own // children - updateSelection(childItem,true); + updateSelection(childItem, true); } } } - if(unselect) return; - for(int i=0,count=ti->childCount();ichildCount(); i < count; ++i) updateSelection(ti->child(i)); } -void DocumentItem::updateItemSelection(DocumentObjectItem *item) { +void DocumentItem::updateItemSelection(DocumentObjectItem* item) { bool selected = item->isSelected(); bool checked = item->checkState(0) == Qt::Checked; - if(selected && !checked) + if (selected && !checked) item->setCheckState(true); - if(!selected && checked) + if (!selected && checked) item->setCheckState(false); - if((selected && item->selected>0) || (!selected && !item->selected)) { + if ((selected && item->selected > 0) || (!selected && !item->selected)) { return; } - if(item->selected != -1) + if (item->selected != -1) item->mySubs.clear(); item->selected = selected; auto obj = item->object()->getObject(); - if(!obj || !obj->getNameInDocument()) + if (!obj || !obj->getNameInDocument()) return; std::ostringstream str; - App::DocumentObject *topParent = 0; - item->getSubName(str,topParent); - if(topParent) { - if(topParent->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())) { + App::DocumentObject* topParent = 0; + item->getSubName(str, topParent); + if (topParent) { + if (topParent->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())) { // remove legacy selection, i.e. those without subname Gui::Selection().rmvSelection(obj->getDocument()->getName(), - obj->getNameInDocument(),0); + obj->getNameInDocument(), 0); } - if(!obj->redirectSubName(str,topParent,0)) + if (!obj->redirectSubName(str, topParent, 0)) str << obj->getNameInDocument() << '.'; obj = topParent; } - const char *objname = obj->getNameInDocument(); - const char *docname = obj->getDocument()->getName(); - const auto &subname = str.str(); + const char* objname = obj->getNameInDocument(); + const char* docname = obj->getDocument()->getName(); + const auto& subname = str.str(); - if(subname.size()) { + if (subname.size()) { auto parentItem = item->getParentItem(); assert(parentItem); - if(selected && parentItem->selected) { + if (selected && parentItem->selected) { // When a group item is selected, all its children objects are // highlighted in the 3D view. So, when an item of some group is // newly selected, we must force unselect its parent in order to @@ -4177,7 +4233,7 @@ void DocumentItem::updateItemSelection(DocumentObjectItem *item) { } } - if(selected && item->isGroup()) { + if (selected && item->isGroup()) { // Same reasoning as above. When a group item is newly selected, We // choose to force unselect all its children to void messing up the // selection highlight @@ -4188,20 +4244,20 @@ void DocumentItem::updateItemSelection(DocumentObjectItem *item) { // updateSelection(item,true); } - if(!selected) { - Gui::Selection().rmvSelection(docname,objname,subname.c_str()); + if (!selected) { + Gui::Selection().rmvSelection(docname, objname, subname.c_str()); return; } selected = false; - if(item->mySubs.size()) { - for(auto &sub : item->mySubs) { - if(Gui::Selection().addSelection(docname,objname,(subname+sub).c_str())) + if (item->mySubs.size()) { + for (auto& sub : item->mySubs) { + if (Gui::Selection().addSelection(docname, objname, (subname + sub).c_str())) selected = true; } } - if(!selected) { + if (!selected) { item->mySubs.clear(); - if(!Gui::Selection().addSelection(docname,objname,subname.c_str())) { + if (!Gui::Selection().addSelection(docname, objname, subname.c_str())) { item->selected = 0; item->setSelected(false); item->setCheckState(false); @@ -4211,97 +4267,97 @@ void DocumentItem::updateItemSelection(DocumentObjectItem *item) { getTree()->syncView(item->object()); } -App::DocumentObject *DocumentItem::getTopParent(App::DocumentObject *obj, std::string &subname) { +App::DocumentObject* DocumentItem::getTopParent(App::DocumentObject* obj, std::string& subname) { auto it = ObjectMap.find(obj); - if(it == ObjectMap.end() || it->second->items.empty()) + if (it == ObjectMap.end() || it->second->items.empty()) return 0; // already a top parent - if(it->second->rootItem) + if (it->second->rootItem) return obj; - for(auto item : it->second->items) { + for (auto item : it->second->items) { // non group object do not provide a coordinate system, hence its // claimed child is still in the global coordinate space, so the // child can still be considered a top level object - if(!item->isParentGroup()) + if (!item->isParentGroup()) return obj; } // If no top level item, find an item that is closest to the top level - std::multimap items; - for(auto item : it->second->items) { - int i=0; - for(auto parent=item->parent();parent;++i,parent=parent->parent()) { - if(parent->isHidden()) + std::multimap items; + for (auto item : it->second->items) { + int i = 0; + for (auto parent = item->parent(); parent; ++i, parent = parent->parent()) { + if (parent->isHidden()) i += 1000; ++i; } - items.emplace(i,item); + items.emplace(i, item); } - App::DocumentObject *topParent = 0; + App::DocumentObject* topParent = 0; std::ostringstream ss; - items.begin()->second->getSubName(ss,topParent); - if(!topParent) { + items.begin()->second->getSubName(ss, topParent); + if (!topParent) { // this shouldn't happen FC_WARN("No top parent for " << obj->getFullName() << '.' << subname); return obj; } ss << obj->getNameInDocument() << '.' << subname; FC_LOG("Subname correction " << obj->getFullName() << '.' << subname - << " -> " << topParent->getFullName() << '.' << ss.str()); + << " -> " << topParent->getFullName() << '.' << ss.str()); subname = ss.str(); return topParent; } -DocumentObjectItem *DocumentItem::findItemByObject( - bool sync, App::DocumentObject *obj, const char *subname, bool select) +DocumentObjectItem* DocumentItem::findItemByObject( + bool sync, App::DocumentObject* obj, const char* subname, bool select) { - if(!subname) + if (!subname) subname = ""; auto it = ObjectMap.find(obj); - if(it == ObjectMap.end() || it->second->items.empty()) + if (it == ObjectMap.end() || it->second->items.empty()) return 0; // prefer top level item of this object - if(it->second->rootItem) - return findItem(sync,it->second->rootItem,subname,select); + if (it->second->rootItem) + return findItem(sync, it->second->rootItem, subname, select); - for(auto item : it->second->items) { + for (auto item : it->second->items) { // non group object do not provide a coordinate system, hence its // claimed child is still in the global coordinate space, so the // child can still be considered a top level object - if(!item->isParentGroup()) - return findItem(sync,item,subname,select); + if (!item->isParentGroup()) + return findItem(sync, item, subname, select); } // If no top level item, find an item that is closest to the top level - std::multimap items; - for(auto item : it->second->items) { - int i=0; - for(auto parent=item->parent();parent;++i,parent=parent->parent()) + std::multimap items; + for (auto item : it->second->items) { + int i = 0; + for (auto parent = item->parent(); parent; ++i, parent = parent->parent()) ++i; - items.emplace(i,item); + items.emplace(i, item); } - for(auto &v : items) { - auto item = findItem(sync,v.second,subname,select); - if(item) + for (auto& v : items) { + auto item = findItem(sync, v.second, subname, select); + if (item) return item; } return 0; } -DocumentObjectItem *DocumentItem::findItem( - bool sync, DocumentObjectItem *item, const char *subname, bool select) +DocumentObjectItem* DocumentItem::findItem( + bool sync, DocumentObjectItem* item, const char* subname, bool select) { - if(item->isHidden()) + if (item->isHidden()) item->setHidden(false); - if(!subname || *subname==0) { - if(select) { - item->selected+=2; + if (!subname || *subname == 0) { + if (select) { + item->selected += 2; item->mySubs.clear(); } return item; @@ -4310,113 +4366,114 @@ DocumentObjectItem *DocumentItem::findItem( TREE_TRACE("find next " << subname); // try to find the next level object name - const char *nextsub = 0; - const char *dot = 0; - if((dot=strchr(subname,'.'))) - nextsub = dot+1; + const char* nextsub = 0; + const char* dot = 0; + if ((dot = strchr(subname, '.'))) + nextsub = dot + 1; else { - if(select) { - item->selected+=2; - if(std::find(item->mySubs.begin(),item->mySubs.end(),subname)==item->mySubs.end()) + if (select) { + item->selected += 2; + if (std::find(item->mySubs.begin(), item->mySubs.end(), subname) == item->mySubs.end()) item->mySubs.push_back(subname); } return item; } - std::string name(subname,nextsub-subname); + std::string name(subname, nextsub - subname); auto obj = item->object()->getObject(); auto subObj = obj->getSubObject(name.c_str()); - if(!subObj || subObj==obj) { - if(!subObj && !getTree()->searchDoc) + if (!subObj || subObj == obj) { + if (!subObj && !getTree()->searchDoc) TREE_LOG("sub object not found " << item->getName() << '.' << name.c_str()); - if(select) { + if (select) { item->selected += 2; - if(std::find(item->mySubs.begin(),item->mySubs.end(),subname)==item->mySubs.end()) + if (std::find(item->mySubs.begin(), item->mySubs.end(), subname) == item->mySubs.end()) item->mySubs.push_back(subname); } return item; } - if(select) + if (select) item->mySubs.clear(); - if(!item->populated && sync) { + if (!item->populated && sync) { //force populate the item item->populated = true; - populateItem(item,true); + populateItem(item, true); } - for(int i=0,count=item->childCount();ichildCount(); i < count; ++i) { auto ti = item->child(i); - if(!ti || ti->type()!=TreeWidget::ObjectType) continue; + if (!ti || ti->type() != TreeWidget::ObjectType) continue; auto child = static_cast(ti); - if(child->object()->getObject() == subObj) - return findItem(sync,child,nextsub,select); + if (child->object()->getObject() == subObj) + return findItem(sync, child, nextsub, select); } // The sub object is not found. This could happen for geo group, since its // children may be in more than one hierarchy down. bool found = false; - DocumentObjectItem *res=0; + DocumentObjectItem* res = 0; auto it = ObjectMap.find(subObj); - if(it != ObjectMap.end()) { - for(auto child : it->second->items) { - if(child->isChildOfItem(item)) { + if (it != ObjectMap.end()) { + for (auto child : it->second->items) { + if (child->isChildOfItem(item)) { found = true; - res = findItem(sync,child,nextsub,select); - if(!select) + res = findItem(sync, child, nextsub, select); + if (!select) return res; } } } - if(select && !found) { + if (select && !found) { // The sub object is still not found. Maybe it is a non-object sub-element. // Select the current object instead. TREE_TRACE("element " << subname << " not found"); - item->selected+=2; - if(std::find(item->mySubs.begin(),item->mySubs.end(),subname)==item->mySubs.end()) + item->selected += 2; + if (std::find(item->mySubs.begin(), item->mySubs.end(), subname) == item->mySubs.end()) item->mySubs.push_back(subname); } return res; } void DocumentItem::selectItems(SelectionReason reason) { - const auto &sels = Selection().getSelection(pDocument->getDocument()->getName(),false); + const auto& sels = Selection().getSelection(pDocument->getDocument()->getName(), false); - bool sync = (sels.size()>50 || reason==SR_SELECT)?false:true; + bool sync = (sels.size() > 50 || reason == SR_SELECT) ? false : true; - for(const auto &sel : sels) - findItemByObject(sync,sel.pObject,sel.SubName,true); + for (const auto& sel : sels) + findItemByObject(sync, sel.pObject, sel.SubName, true); - DocumentObjectItem *newSelect = 0; - DocumentObjectItem *oldSelect = 0; + DocumentObjectItem* newSelect = 0; + DocumentObjectItem* oldSelect = 0; FOREACH_ITEM_ALL(item) - if(item->selected == 1) { + if (item->selected == 1) { // this means it is the old selection and is not in the current // selection item->selected = 0; item->mySubs.clear(); item->setSelected(false); item->setCheckState(false); - }else if(item->selected) { - if(sync) { - if(item->selected==2 && showItem(item,false,reason==SR_FORCE_EXPAND)) { + } + else if (item->selected) { + if (sync) { + if (item->selected == 2 && showItem(item, false, reason == SR_FORCE_EXPAND)) { // This means newly selected and can auto expand - if(!newSelect) + if (!newSelect) newSelect = item; } - if(!newSelect && !oldSelect && !item->isHidden()) { + if (!newSelect && !oldSelect && !item->isHidden()) { bool visible = true; - for(auto parent=item->parent();parent;parent=parent->parent()) { - if(!parent->isExpanded() || parent->isHidden()) { + for (auto parent = item->parent(); parent; parent = parent->parent()) { + if (!parent->isExpanded() || parent->isHidden()) { visible = false; break; } } - if(visible) + if (visible) oldSelect = item; } } @@ -4426,38 +4483,38 @@ void DocumentItem::selectItems(SelectionReason reason) { } END_FOREACH_ITEM; - if(sync) { - if(!newSelect) + if (sync) { + if (!newSelect) newSelect = oldSelect; else getTree()->syncView(newSelect->object()); - if(newSelect) + if (newSelect) getTree()->scrollToItem(newSelect); } } -void DocumentItem::populateParents(const ViewProvider *vp, ViewParentMap &parentMap) { +void DocumentItem::populateParents(const ViewProvider* vp, ViewParentMap& parentMap) { auto it = parentMap.find(vp); - if(it == parentMap.end()) return; - for(auto parent : it->second) { + if (it == parentMap.end()) return; + for (auto parent : it->second) { auto it = ObjectMap.find(parent->getObject()); - if(it==ObjectMap.end()) + if (it == ObjectMap.end()) continue; - populateParents(parent,parentMap); - for(auto item : it->second->items) { - if(!item->isHidden() && !item->populated) { + populateParents(parent, parentMap); + for (auto item : it->second->items) { + if (!item->isHidden() && !item->populated) { item->populated = true; - populateItem(item,true); + populateItem(item, true); } } } } -void DocumentItem::selectAllInstances(const ViewProviderDocumentObject &vpd) { +void DocumentItem::selectAllInstances(const ViewProviderDocumentObject& vpd) { ViewParentMap parentMap; auto pObject = vpd.getObject(); - if(ObjectMap.find(pObject) == ObjectMap.end()) + if (ObjectMap.find(pObject) == ObjectMap.end()) return; bool lock = getTree()->blockConnection(true); @@ -4466,27 +4523,27 @@ void DocumentItem::selectAllInstances(const ViewProviderDocumentObject &vpd) { // provider, i.e. all appearance of the object inside all its parent items // // Build a map of object to all its parent - for(auto &v : ObjectMap) { - if(v.second->viewObject == &vpd) continue; - for(auto child : v.second->viewObject->claimChildren()) { + for (auto& v : ObjectMap) { + if (v.second->viewObject == &vpd) continue; + for (auto child : v.second->viewObject->claimChildren()) { auto vp = getViewProvider(child); - if(!vp) continue; + if (!vp) continue; parentMap[vp].push_back(v.second->viewObject); } } // now make sure all parent items are populated. In order to do that, we // need to populate the oldest parent first - populateParents(&vpd,parentMap); + populateParents(&vpd, parentMap); - DocumentObjectItem *first = 0; - FOREACH_ITEM(item,vpd); - if(showItem(item,true) && !first) - first = item; + DocumentObjectItem* first = 0; + FOREACH_ITEM(item, vpd); + if (showItem(item, true) && !first) + first = item; END_FOREACH_ITEM; getTree()->blockConnection(lock); - if(first) { + if (first) { treeWidget()->scrollToItem(first); updateSelection(); } @@ -4500,44 +4557,45 @@ void DocumentItem::setShowHidden(bool show) { pDocument->getDocument()->ShowHidden.setValue(show); } -bool DocumentItem::showItem(DocumentObjectItem *item, bool select, bool force) { +bool DocumentItem::showItem(DocumentObjectItem* item, bool select, bool force) { auto parent = item->parent(); - if(item->isHidden()) { - if(!force) + if (item->isHidden()) { + if (!force) return false; item->setHidden(false); } - if(parent->type()==TreeWidget::ObjectType) { - if(!showItem(static_cast(parent),false)) + if (parent->type() == TreeWidget::ObjectType) { + if (!showItem(static_cast(parent), false)) return false; auto pitem = static_cast(parent); - if(force || !pitem->object()->getObject()->testStatus(App::NoAutoExpand)) + if (force || !pitem->object()->getObject()->testStatus(App::NoAutoExpand)) parent->setExpanded(true); - else if(!select) + else if (!select) return false; - }else + } + else parent->setExpanded(true); - if(select) { + if (select) { item->setSelected(true); item->setCheckState(true); } return true; } -void DocumentItem::updateItemsVisibility(QTreeWidgetItem *item, bool show) { - if(item->type() == TreeWidget::ObjectType) { +void DocumentItem::updateItemsVisibility(QTreeWidgetItem* item, bool show) { + if (item->type() == TreeWidget::ObjectType) { auto objitem = static_cast(item); objitem->setHidden(!show && !objitem->object()->showInTree()); } - for(int i=0;ichildCount();++i) - updateItemsVisibility(item->child(i),show); + for (int i = 0; i < item->childCount(); ++i) + updateItemsVisibility(item->child(i), show); } void DocumentItem::updateSelection() { bool lock = getTree()->blockConnection(true); - updateSelection(this,false); + updateSelection(this, false); getTree()->blockConnection(lock); } @@ -4545,9 +4603,9 @@ void DocumentItem::updateSelection() { static int countItems; -DocumentObjectItem::DocumentObjectItem(DocumentItem *ownerDocItem, DocumentObjectDataPtr data) +DocumentObjectItem::DocumentObjectItem(DocumentItem* ownerDocItem, DocumentObjectDataPtr data) : QTreeWidgetItem(TreeWidget::ObjectType) - , myOwner(ownerDocItem), myData(data), previousStatus(-1),selected(0),populated(false) + , myOwner(ownerDocItem), myData(data), previousStatus(-1), selected(0), populated(false) { setFlags(flags() | Qt::ItemIsEditable | Qt::ItemIsUserCheckable); setCheckState(false); @@ -4562,17 +4620,17 @@ DocumentObjectItem::~DocumentObjectItem() --countItems; TREE_LOG("Delete item: " << countItems << ", " << object()->getObject()->getFullName()); auto it = myData->items.find(this); - if(it == myData->items.end()) + if (it == myData->items.end()) assert(0); else myData->items.erase(it); - if(myData->rootItem == this) + if (myData->rootItem == this) myData->rootItem = 0; - if(myOwner && myData->items.empty()) { + if (myOwner && myData->items.empty()) { auto it = myOwner->_ParentMap.find(object()->getObject()); - if(it!=myOwner->_ParentMap.end() && it->second.size()) { + if (it != myOwner->_ParentMap.end() && it->second.size()) { myOwner->PopulateObjects.push_back(*it->second.begin()); myOwner->getTree()->_updateStatus(); } @@ -4580,12 +4638,12 @@ DocumentObjectItem::~DocumentObjectItem() } void DocumentObjectItem::restoreBackground() { - this->setBackground(0,this->bgBrush); + this->setBackground(0, this->bgBrush); } void DocumentObjectItem::setHighlight(bool set, Gui::HighlightMode high) { QFont f = this->font(0); - auto highlight = [=](const QColor& col){ + auto highlight = [=](const QColor& col) { if (set) this->setBackground(0, col); else @@ -4607,27 +4665,27 @@ void DocumentObjectItem::setHighlight(bool set, Gui::HighlightMode high) { f.setOverline(set); break; case HighlightMode::Blue: - highlight(QColor(200,200,255)); + highlight(QColor(200, 200, 255)); break; case HighlightMode::LightBlue: - highlight(QColor(230,230,255)); + highlight(QColor(230, 230, 255)); break; case HighlightMode::UserDefined: { - QColor color(230,230,255); + QColor color(230, 230, 255); if (set) { ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/TreeView"); - bool bold = hGrp->GetBool("TreeActiveBold",true); - bool italic = hGrp->GetBool("TreeActiveItalic",false); - bool underlined = hGrp->GetBool("TreeActiveUnderlined",false); - bool overlined = hGrp->GetBool("TreeActiveOverlined",false); + bool bold = hGrp->GetBool("TreeActiveBold", true); + bool italic = hGrp->GetBool("TreeActiveItalic", false); + bool underlined = hGrp->GetBool("TreeActiveUnderlined", false); + bool overlined = hGrp->GetBool("TreeActiveOverlined", false); f.setBold(bold); f.setItalic(italic); f.setUnderline(underlined); f.setOverline(overlined); - unsigned long col = hGrp->GetUnsigned("TreeActiveColor",3873898495); - color = QColor((col >> 24) & 0xff,(col >> 16) & 0xff,(col >> 8) & 0xff); + unsigned long col = hGrp->GetUnsigned("TreeActiveColor", 3873898495); + color = QColor((col >> 24) & 0xff, (col >> 16) & 0xff, (col >> 8) & 0xff); } else { f.setBold(false); @@ -4640,10 +4698,10 @@ void DocumentObjectItem::setHighlight(bool set, Gui::HighlightMode high) { default: break; } - this->setFont(0,f); + this->setFont(0, f); } -const char *DocumentObjectItem::getTreeName() const +const char* DocumentObjectItem::getTreeName() const { return myData->getTreeName(); } @@ -4655,30 +4713,30 @@ Gui::ViewProviderDocumentObject* DocumentObjectItem::object() const void DocumentObjectItem::testStatus(bool resetStatus) { - QIcon icon,icon2; - testStatus(resetStatus,icon,icon2); + QIcon icon, icon2; + testStatus(resetStatus, icon, icon2); } -void DocumentObjectItem::testStatus(bool resetStatus, QIcon &icon1, QIcon &icon2) +void DocumentObjectItem::testStatus(bool resetStatus, QIcon& icon1, QIcon& icon2) { App::DocumentObject* pObject = object()->getObject(); int visible = -1; auto parentItem = getParentItem(); - if(parentItem) { + if (parentItem) { Timing(testStatus1); auto parent = parentItem->object()->getObject(); - auto ext = parent->getExtensionByType(true,false); - if(!ext) + auto ext = parent->getExtensionByType(true, false); + if (!ext) visible = parent->isElementVisible(pObject->getNameInDocument()); else { // We are dealing with a plain group. It has special handling when // linked, which allows it to have indpenedent visibility control. // We need to go up the hierarchy and see if there is any link to // it. - for(auto pp=parentItem->getParentItem();pp;pp=pp->getParentItem()) { + for (auto pp = parentItem->getParentItem(); pp; pp = pp->getParentItem()) { auto obj = pp->object()->getObject(); - if(!obj->hasExtension(App::GroupExtension::getExtensionClassTypeId(),false)) { + if (!obj->hasExtension(App::GroupExtension::getExtensionClassTypeId(), false)) { visible = pp->object()->getObject()->isElementVisible(pObject->getNameInDocument()); break; } @@ -4688,27 +4746,27 @@ void DocumentObjectItem::testStatus(bool resetStatus, QIcon &icon1, QIcon &icon2 Timing(testStatus2); - if(visible<0) - visible = object()->isShow()?1:0; + if (visible < 0) + visible = object()->isShow() ? 1 : 0; auto obj = object()->getObject(); auto linked = obj->getLinkedObject(false); - bool external = object()->getDocument()!=getOwnerDocument()->document() || - (linked && linked->getDocument()!=obj->getDocument()); + bool external = object()->getDocument() != getOwnerDocument()->document() || + (linked && linked->getDocument() != obj->getDocument()); int currentStatus = - ((external?0:1)<<4) | + ((external ? 0 : 1) << 4) | ((object()->showInTree() ? 0 : 1) << 3) | - ((pObject->isError() ? 1 : 0) << 2) | - ((pObject->isTouched()||pObject->mustExecute()== 1 ? 1 : 0) << 1) | - (visible ? 1 : 0); + ((pObject->isError() ? 1 : 0) << 2) | + ((pObject->isTouched() || pObject->mustExecute() == 1 ? 1 : 0) << 1) | + (visible ? 1 : 0); TimingStop(testStatus2); - if (!resetStatus && previousStatus==currentStatus) + if (!resetStatus && previousStatus == currentStatus) return; - _Timing(1,testStatus3); + _Timing(1, testStatus3); previousStatus = currentStatus; @@ -4722,29 +4780,29 @@ void DocumentObjectItem::testStatus(bool resetStatus, QIcon &icon1, QIcon &icon2 // to black which will lead to unreadable text if the system background // hss already a dark color. // However, it works if we set the appropriate role to an empty QVariant(). - this->setData(0, Qt::ForegroundRole,QVariant()); + this->setData(0, Qt::ForegroundRole, QVariant()); } else { // invisible QStyleOptionViewItem opt; // it can happen that a tree item is not attached to the tree widget (#0003025) if (this->treeWidget()) opt.initFrom(this->treeWidget()); - this->setForeground(0, opt.palette.color(QPalette::Disabled,QPalette::Text)); + this->setForeground(0, opt.palette.color(QPalette::Disabled, QPalette::Text)); mode = QIcon::Disabled; } - _TimingStop(1,testStatus3); + _TimingStop(1, testStatus3); - QIcon &icon = mode==QIcon::Normal?icon1:icon2; + QIcon& icon = mode == QIcon::Normal ? icon1 : icon2; - if(icon.isNull()) { + if (icon.isNull()) { Timing(getIcon); QPixmap px; if (currentStatus & 4) { static QPixmap pxError; - if(pxError.isNull()) { - // object is in error state - const char * const feature_error_xpm[]={ + if (pxError.isNull()) { + // object is in error state + const char* const feature_error_xpm[] = { "9 9 3 1", ". c None", "# c #ff0000", @@ -4757,16 +4815,16 @@ void DocumentObjectItem::testStatus(bool resetStatus, QIcon &icon1, QIcon &icon2 "#########", ".##aaa##.", ".##aaa##.", - "...###..."}; + "...###..." }; pxError = QPixmap(feature_error_xpm); } px = pxError; } else if (currentStatus & 2) { static QPixmap pxRecompute; - if(pxRecompute.isNull()) { + if (pxRecompute.isNull()) { // object must be recomputed - const char * const feature_recompute_xpm[]={ + const char* const feature_recompute_xpm[] = { "9 9 3 1", ". c None", "# c #0000ff", @@ -4779,7 +4837,7 @@ void DocumentObjectItem::testStatus(bool resetStatus, QIcon &icon1, QIcon &icon2 "#aaaa####", ".#aa####.", ".#######.", - "...###..."}; + "...###..." }; pxRecompute = QPixmap(feature_recompute_xpm); } px = pxRecompute; @@ -4790,23 +4848,24 @@ void DocumentObjectItem::testStatus(bool resetStatus, QIcon &icon1, QIcon &icon2 int w = getTree()->viewOptions().decorationSize.width(); - QPixmap pxOn,pxOff; + QPixmap pxOn, pxOff; // if needed show small pixmap inside if (!px.isNull()) { pxOff = BitmapFactory().merge(icon_org.pixmap(w, w, mode, QIcon::Off), - px,BitmapFactoryInst::TopRight); - pxOn = BitmapFactory().merge(icon_org.pixmap(w, w, mode, QIcon::On ), - px,BitmapFactoryInst::TopRight); - } else { + px, BitmapFactoryInst::TopRight); + pxOn = BitmapFactory().merge(icon_org.pixmap(w, w, mode, QIcon::On), + px, BitmapFactoryInst::TopRight); + } + else { pxOff = icon_org.pixmap(w, w, mode, QIcon::Off); pxOn = icon_org.pixmap(w, w, mode, QIcon::On); } - if(currentStatus & 8) {// hidden item + if (currentStatus & 8) {// hidden item static QPixmap pxHidden; - if(pxHidden.isNull()) { - const char * const feature_hidden_xpm[]={ + if (pxHidden.isNull()) { + const char* const feature_hidden_xpm[] = { "9 7 3 1", ". c None", "# c #000000", @@ -4817,17 +4876,17 @@ void DocumentObjectItem::testStatus(bool resetStatus, QIcon &icon1, QIcon &icon2 "#aa###aa#", ".#a###a#.", "..#aaa#..", - "...###..."}; + "...###..." }; pxHidden = QPixmap(feature_hidden_xpm); } pxOff = BitmapFactory().merge(pxOff, pxHidden, BitmapFactoryInst::TopLeft); pxOn = BitmapFactory().merge(pxOn, pxHidden, BitmapFactoryInst::TopLeft); } - if(external) {// external item + if (external) {// external item static QPixmap pxExternal; - if(pxExternal.isNull()) { - const char * const feature_external_xpm[]={ + if (pxExternal.isNull()) { + const char* const feature_external_xpm[] = { "7 7 3 1", ". c None", "# c #000000", @@ -4838,7 +4897,7 @@ void DocumentObjectItem::testStatus(bool resetStatus, QIcon &icon1, QIcon &icon2 "..##aa#", "..#aa##", ".#aa##.", - "..###.."}; + "..###.." }; pxExternal = QPixmap(feature_external_xpm); } pxOff = BitmapFactory().merge(pxOff, pxExternal, BitmapFactoryInst::BottomRight); @@ -4852,7 +4911,7 @@ void DocumentObjectItem::testStatus(bool resetStatus, QIcon &icon1, QIcon &icon2 } - _Timing(2,setIcon); + _Timing(2, setIcon); this->setIcon(0, icon); } @@ -4866,12 +4925,12 @@ void DocumentObjectItem::displayStatusInfo() info += TreeWidget::tr(" (but must be executed)"); QString status = TreeWidget::tr("%1, Internal name: %2") - .arg(info, QString::fromLatin1(Obj->getNameInDocument())); + .arg(info, QString::fromLatin1(Obj->getNameInDocument())); if (!Obj->isError()) getMainWindow()->showMessage(status); else { - getMainWindow()->showStatus(MainWindow::Err,status); + getMainWindow()->showStatus(MainWindow::Err, status); QTreeWidget* tree = this->treeWidget(); QPoint pos = tree->visualItemRect(this).topRight(); QToolTip::showText(tree->mapToGlobal(pos), info); @@ -4880,20 +4939,20 @@ void DocumentObjectItem::displayStatusInfo() void DocumentObjectItem::setExpandedStatus(bool on) { - if(getOwnerDocument()->document() == object()->getDocument()) + if (getOwnerDocument()->document() == object()->getDocument()) object()->getObject()->setStatus(App::Expand, on); } -void DocumentObjectItem::setData (int column, int role, const QVariant & value) +void DocumentObjectItem::setData(int column, int role, const QVariant& value) { QVariant myValue(value); - if (role == Qt::EditRole && column<=1) { + if (role == Qt::EditRole && column <= 1) { auto obj = object()->getObject(); - auto &label = column?obj->Label2:obj->Label; + auto& label = column ? obj->Label2 : obj->Label; std::ostringstream ss; ss << "Change " << getName() << '.' << label.getName(); App::AutoTransaction committer(ss.str().c_str()); - label.setValue((const char *)value.toString().toUtf8()); + label.setValue((const char*)value.toString().toUtf8()); myValue = QString::fromUtf8(label.getValue()); } QTreeWidgetItem::setData(column, role, myValue); @@ -4901,26 +4960,26 @@ void DocumentObjectItem::setData (int column, int role, const QVariant & value) bool DocumentObjectItem::isChildOfItem(DocumentObjectItem* item) { - for(auto pitem=parent();pitem;pitem=pitem->parent()) - if(pitem == item) + for (auto pitem = parent(); pitem; pitem = pitem->parent()) + if (pitem == item) return true; return false; } -bool DocumentObjectItem::requiredAtRoot(bool excludeSelf) const{ - if(myData->rootItem || object()->getDocument()!=getOwnerDocument()->document()) +bool DocumentObjectItem::requiredAtRoot(bool excludeSelf) const { + if (myData->rootItem || object()->getDocument() != getOwnerDocument()->document()) return false; bool checkMap = true; - for(auto item : myData->items) { - if(excludeSelf && item == this) continue; + for (auto item : myData->items) { + if (excludeSelf && item == this) continue; auto pi = item->getParentItem(); - if(!pi || pi->myData->removeChildrenFromRoot) + if (!pi || pi->myData->removeChildrenFromRoot) return false; checkMap = false; } - if(checkMap && myOwner) { + if (checkMap && myOwner) { auto it = myOwner->_ParentMap.find(object()->getObject()); - if(it!=myOwner->_ParentMap.end()) { + if (it != myOwner->_ParentMap.end()) { // Reaching here means all items of this corresponding object is // going to be deleted, but the object itself is not deleted and // still being referred to by some parent item that is not expanded @@ -4933,8 +4992,8 @@ bool DocumentObjectItem::requiredAtRoot(bool excludeSelf) const{ // expand its parent item. It only causes minor problems, such as, // tree scroll to object command won't work properly. - for(auto parent : it->second) { - if(getOwnerDocument()->populateObject(parent)) + for (auto parent : it->second) { + if (getOwnerDocument()->populateObject(parent)) return false; } } @@ -4945,7 +5004,7 @@ bool DocumentObjectItem::requiredAtRoot(bool excludeSelf) const{ bool DocumentObjectItem::isLink() const { auto obj = object()->getObject(); auto linked = obj->getLinkedObject(false); - return linked && obj!=linked; + return linked && obj != linked; } bool DocumentObjectItem::isLinkFinal() const { @@ -4970,33 +5029,33 @@ enum GroupType { int DocumentObjectItem::isGroup() const { auto obj = object()->getObject(); auto linked = obj->getLinkedObject(true); - if(linked && linked->hasExtension( - App::GeoFeatureGroupExtension::getExtensionClassTypeId())) + if (linked && linked->hasExtension( + App::GeoFeatureGroupExtension::getExtensionClassTypeId())) return PartGroup; - if(obj->hasChildElement()) + if (obj->hasChildElement()) return LinkGroup; - if(obj->hasExtension(App::GroupExtension::getExtensionClassTypeId(),false)) { - for(auto parent=getParentItem();parent;parent=parent->getParentItem()) { + if (obj->hasExtension(App::GroupExtension::getExtensionClassTypeId(), false)) { + for (auto parent = getParentItem(); parent; parent = parent->getParentItem()) { auto pobj = parent->object()->getObject(); - if(pobj->hasExtension(App::GroupExtension::getExtensionClassTypeId(),false)) + if (pobj->hasExtension(App::GroupExtension::getExtensionClassTypeId(), false)) continue; - if(pobj->isElementVisible(obj->getNameInDocument())>=0) + if (pobj->isElementVisible(obj->getNameInDocument()) >= 0) return LinkGroup; } } return NotGroup; } -bool DocumentItem::isObjectShowable(App::DocumentObject *obj) { +bool DocumentItem::isObjectShowable(App::DocumentObject* obj) { auto itParents = _ParentMap.find(obj); - if(itParents == _ParentMap.end() || itParents->second.empty()) + if (itParents == _ParentMap.end() || itParents->second.empty()) return true; bool showable = true; - for(auto parent : itParents->second) { - if(parent->getDocument() != obj->getDocument()) + for (auto parent : itParents->second) { + if (parent->getDocument() != obj->getDocument()) continue; - if(!parent->hasChildElement() - && parent->getLinkedObject(false)==parent) + if (!parent->hasChildElement() + && parent->getLinkedObject(false) == parent) return true; showable = false; } @@ -5005,30 +5064,30 @@ bool DocumentItem::isObjectShowable(App::DocumentObject *obj) { int DocumentObjectItem::isParentGroup() const { auto pi = getParentItem(); - return pi?pi->isGroup():0; + return pi ? pi->isGroup() : 0; } -DocumentObjectItem *DocumentObjectItem::getParentItem() const{ - if(parent()->type()!=TreeWidget::ObjectType) +DocumentObjectItem* DocumentObjectItem::getParentItem() const { + if (parent()->type() != TreeWidget::ObjectType) return 0; return static_cast(parent()); } -const char *DocumentObjectItem::getName() const { - const char *name = object()->getObject()->getNameInDocument(); - return name?name:""; +const char* DocumentObjectItem::getName() const { + const char* name = object()->getObject()->getNameInDocument(); + return name ? name : ""; } -int DocumentObjectItem::getSubName(std::ostringstream &str, App::DocumentObject *&topParent) const +int DocumentObjectItem::getSubName(std::ostringstream& str, App::DocumentObject*& topParent) const { auto parent = getParentItem(); - if(!parent) + if (!parent) return NotGroup; - int ret = parent->getSubName(str,topParent); - if(ret != SuperGroup) { + int ret = parent->getSubName(str, topParent); + if (ret != SuperGroup) { int group = parent->isGroup(); - if(group == NotGroup) { - if(ret!=PartGroup) { + if (group == NotGroup) { + if (ret != PartGroup) { // Handle this situation, // // LinkGroup @@ -5048,74 +5107,74 @@ int DocumentObjectItem::getSubName(std::ostringstream &str, App::DocumentObject } auto obj = parent->object()->getObject(); - if(!obj || !obj->getNameInDocument()) { + if (!obj || !obj->getNameInDocument()) { topParent = 0; str.str(""); return NotGroup; } - if(!topParent) + if (!topParent) topParent = obj; - else if(!obj->redirectSubName(str,topParent,object()->getObject())) + else if (!obj->redirectSubName(str, topParent, object()->getObject())) str << obj->getNameInDocument() << '.'; return ret; } -App::DocumentObject *DocumentObjectItem::getFullSubName( - std::ostringstream &str, DocumentObjectItem *parent) const +App::DocumentObject* DocumentObjectItem::getFullSubName( + std::ostringstream& str, DocumentObjectItem* parent) const { auto pi = getParentItem(); - if(this==parent || !pi || (!parent && !pi->isGroup())) + if (this == parent || !pi || (!parent && !pi->isGroup())) return object()->getObject(); - auto ret = pi->getFullSubName(str,parent); + auto ret = pi->getFullSubName(str, parent); str << getName() << '.'; return ret; } -App::DocumentObject *DocumentObjectItem::getRelativeParent( - std::ostringstream &str, DocumentObjectItem *cousin, - App::DocumentObject **topParent, std::string *topSubname) const +App::DocumentObject* DocumentObjectItem::getRelativeParent( + std::ostringstream& str, DocumentObjectItem* cousin, + App::DocumentObject** topParent, std::string* topSubname) const { std::ostringstream str2; - App::DocumentObject *top=0,*top2=0; - getSubName(str,top); - if(topParent) + App::DocumentObject* top = 0, * top2 = 0; + getSubName(str, top); + if (topParent) *topParent = top; - if(!top) + if (!top) return 0; - if(topSubname) + if (topSubname) *topSubname = str.str() + getName() + '.'; - cousin->getSubName(str2,top2); - if(top!=top2) { + cousin->getSubName(str2, top2); + if (top != top2) { str << getName() << '.'; return top; } auto subname = str.str(); auto subname2 = str2.str(); - const char *sub = subname.c_str(); - const char *sub2 = subname2.c_str(); - while(1) { - const char *dot = strchr(sub,'.'); - if(!dot) { + const char* sub = subname.c_str(); + const char* sub2 = subname2.c_str(); + while (1) { + const char* dot = strchr(sub, '.'); + if (!dot) { str.str(""); return 0; } - const char *dot2 = strchr(sub2,'.'); - if(!dot2 || dot-sub!=dot2-sub2 || strncmp(sub,sub2,dot-sub)!=0) { - auto substr = subname.substr(0,dot-subname.c_str()+1); + const char* dot2 = strchr(sub2, '.'); + if (!dot2 || dot - sub != dot2 - sub2 || strncmp(sub, sub2, dot - sub) != 0) { + auto substr = subname.substr(0, dot - subname.c_str() + 1); auto ret = top->getSubObject(substr.c_str()); - if(!top) { + if (!top) { FC_ERR("invalid subname " << top->getFullName() << '.' << substr); str.str(""); return 0; } str.str(""); - str << dot+1 << getName() << '.'; + str << dot + 1 << getName() << '.'; return ret; } - sub = dot+1; - sub2 = dot2+1; + sub = dot + 1; + sub2 = dot2 + 1; } str.str(""); return 0; @@ -5128,15 +5187,15 @@ void DocumentObjectItem::setCheckState(bool checked) { setData(0, Qt::CheckStateRole, QVariant()); } -DocumentItem *DocumentObjectItem::getParentDocument() const { +DocumentItem* DocumentObjectItem::getParentDocument() const { return getTree()->getDocumentItem(object()->getDocument()); } -DocumentItem *DocumentObjectItem::getOwnerDocument() const { +DocumentItem* DocumentObjectItem::getOwnerDocument() const { return myOwner; } -TreeWidget *DocumentObjectItem::getTree() const{ +TreeWidget* DocumentObjectItem::getTree() const { return static_cast(treeWidget()); } From 632af47a0d137bffe625762799a8c21a2ed75748 Mon Sep 17 00:00:00 2001 From: Brent Roetger Date: Mon, 29 Nov 2021 20:17:24 -0600 Subject: [PATCH 125/133] Added SpaceNavigator defaults --- src/Gui/3Dconnexion/3DConnexion.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Gui/3Dconnexion/3DConnexion.xml b/src/Gui/3Dconnexion/3DConnexion.xml index b35fa02e77..46f2add5b0 100644 --- a/src/Gui/3Dconnexion/3DConnexion.xml +++ b/src/Gui/3Dconnexion/3DConnexion.xml @@ -35,6 +35,13 @@ + + + + + + + From d3a0bf018fdd6d70f6a232746ae4daf6aad85c03 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 4 Dec 2021 23:36:11 +0100 Subject: [PATCH 126/133] Spreadsheet: issue 0002957: spreadsheet direct printing --- src/Mod/Spreadsheet/Gui/SheetTableView.cpp | 72 +++++++++++++++++++- src/Mod/Spreadsheet/Gui/SheetTableView.h | 1 + src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp | 74 ++++++++++++++++++--- src/Mod/Spreadsheet/Gui/SpreadsheetView.h | 8 +++ 4 files changed, 144 insertions(+), 11 deletions(-) diff --git a/src/Mod/Spreadsheet/Gui/SheetTableView.cpp b/src/Mod/Spreadsheet/Gui/SheetTableView.cpp index e65365c3eb..7a99207cb8 100644 --- a/src/Mod/Spreadsheet/Gui/SheetTableView.cpp +++ b/src/Mod/Spreadsheet/Gui/SheetTableView.cpp @@ -30,7 +30,9 @@ # include # include # include +# include #endif +# include #include #include @@ -887,16 +889,18 @@ void SheetTableView::edit ( const QModelIndex & index ) QTableView::edit(index); } -void SheetTableView::contextMenuEvent(QContextMenuEvent *) { +void SheetTableView::contextMenuEvent(QContextMenuEvent *) +{ const QMimeData* mimeData = QApplication::clipboard()->mimeData(); - if(!selectionModel()->hasSelection()) { + if (!selectionModel()->hasSelection()) { actionCut->setEnabled(false); actionCopy->setEnabled(false); actionDel->setEnabled(false); actionPaste->setEnabled(false); actionSplit->setEnabled(false); actionMerge->setEnabled(false); - }else{ + } + else { actionPaste->setEnabled(mimeData && (mimeData->hasText() || mimeData->hasText())); actionCut->setEnabled(true); actionCopy->setEnabled(true); @@ -908,4 +912,66 @@ void SheetTableView::contextMenuEvent(QContextMenuEvent *) { contextMenu->exec(QCursor::pos()); } +QString SheetTableView::toHtml() const +{ + std::set cells = sheet->getCells()->getUsedCells(); + int rowCount = 1; + int colCount = 1; + for (const auto& it : cells) { + rowCount = std::max(rowCount, it.row()); + colCount = std::max(colCount, it.col()); + } + + std::unique_ptr doc(new QTextDocument); + doc->setDocumentMargin(10); + QTextCursor cursor(doc.get()); + + cursor.movePosition(QTextCursor::Start); + + QTextTableFormat tableFormat; + tableFormat.setCellSpacing(0.0); + tableFormat.setCellPadding(2.0); + + QTextCharFormat boldFormat; + QFont boldFont = boldFormat.font(); + boldFont.setBold(true); + boldFormat.setFont(boldFont); + + QColor bgColor; + bgColor.setNamedColor(QLatin1String("#f0f0f0")); + QTextCharFormat bgFormat; + bgFormat.setBackground(QBrush(bgColor)); + + QTextTable *table = cursor.insertTable(rowCount + 2, colCount + 2, tableFormat); + for (int row = 0; row < rowCount + 1; row++) { + QTextTableCell headerCell = table->cellAt(row+1, 0); + headerCell.setFormat(bgFormat); + QTextCursor headerCellCursor = headerCell.firstCursorPosition(); + QString data = model()->headerData(row, Qt::Vertical).toString(); + headerCellCursor.insertText(data, boldFormat); + } + for (int col = 0; col < colCount + 1; col++) { + QTextTableCell headerCell = table->cellAt(0, col+1); + headerCell.setFormat(bgFormat); + QTextCursor headerCellCursor = headerCell.firstCursorPosition(); + QTextBlockFormat blockFormat = headerCellCursor.blockFormat(); + blockFormat.setAlignment(Qt::AlignHCenter); + headerCellCursor.setBlockFormat(blockFormat); + QString data = model()->headerData(col, Qt::Horizontal).toString(); + headerCellCursor.insertText(data, boldFormat); + } + + for (const auto& it : cells) { + QTextCharFormat cellFormat; + QTextTableCell cell = table->cellAt(it.row() + 1, it.col() + 1); + QTextCursor cellCursor = cell.firstCursorPosition(); + QString data = model()->data(model()->index(it.row(), it.col())).toString().simplified(); + cellCursor.insertText(data, cellFormat); + } + + cursor.movePosition(QTextCursor::End); + cursor.insertBlock(); + return doc->toHtml(); +} + #include "moc_SheetTableView.cpp" diff --git a/src/Mod/Spreadsheet/Gui/SheetTableView.h b/src/Mod/Spreadsheet/Gui/SheetTableView.h index 840a4961e2..b8e6c62522 100644 --- a/src/Mod/Spreadsheet/Gui/SheetTableView.h +++ b/src/Mod/Spreadsheet/Gui/SheetTableView.h @@ -58,6 +58,7 @@ public: void edit(const QModelIndex &index); void setSheet(Spreadsheet::Sheet *_sheet); std::vector selectedRanges() const; + QString toHtml() const; public Q_SLOTS: void mergeCells(); diff --git a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp index 3595268f2d..2a9a7a2886 100644 --- a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp +++ b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp @@ -26,10 +26,14 @@ # include # include # include +# include +# include +# include # include # include # include # include +# include # include # include # include @@ -46,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -191,22 +196,75 @@ bool SheetView::onHasMsg(const char *pMsg) const App::Document* doc = getAppDocument(); return doc && doc->getAvailableUndos() > 0; } - else if (strcmp("Redo",pMsg) == 0) { + if (strcmp("Redo",pMsg) == 0) { App::Document* doc = getAppDocument(); return doc && doc->getAvailableRedos() > 0; } - else if (strcmp("Save",pMsg) == 0) + if (strcmp("Save",pMsg) == 0) return true; - else if (strcmp("SaveAs",pMsg) == 0) + if (strcmp("SaveAs",pMsg) == 0) return true; - else if (strcmp("Cut",pMsg) == 0) + if (strcmp("Cut",pMsg) == 0) return true; - else if (strcmp("Copy",pMsg) == 0) + if (strcmp("Copy",pMsg) == 0) return true; - else if (strcmp("Paste",pMsg) == 0) + if (strcmp("Paste",pMsg) == 0) return true; - else - return false; + if (strcmp(pMsg, "Print") == 0) + return true; + if (strcmp(pMsg, "PrintPreview") == 0) + return true; + if (strcmp(pMsg, "PrintPdf") == 0) + return true; + + return false; +} + +/** + * Shows the printer dialog. + */ +void SheetView::print() +{ + QPrinter printer(QPrinter::ScreenResolution); + printer.setFullPage(true); + QPrintDialog dlg(&printer, this); + if (dlg.exec() == QDialog::Accepted) { + print(&printer); + } +} + +void SheetView::printPreview() +{ + QPrinter printer(QPrinter::ScreenResolution); + QPrintPreviewDialog dlg(&printer, this); + connect(&dlg, SIGNAL(paintRequested (QPrinter *)), + this, SLOT(print(QPrinter *))); + dlg.exec(); +} + +void SheetView::print(QPrinter* printer) +{ +#if 0 + ui->cells->render(printer); +#endif + std::unique_ptr document = std::make_unique(); + document->setHtml(ui->cells->toHtml()); + document->print(printer); +} + +/** + * Prints the document into a Pdf file. + */ +void SheetView::printPdf() +{ + QString filename = FileDialog::getSaveFileName(this, tr("Export PDF"), QString(), + QString::fromLatin1("%1 (*.pdf)").arg(tr("PDF file"))); + if (!filename.isEmpty()) { + QPrinter printer(QPrinter::ScreenResolution); + printer.setOutputFormat(QPrinter::PdfFormat); + printer.setOutputFileName(filename); + print(&printer); + } } void SheetView::setCurrentCell(QString str) diff --git a/src/Mod/Spreadsheet/Gui/SpreadsheetView.h b/src/Mod/Spreadsheet/Gui/SpreadsheetView.h index ec96b81d06..46d6665a6c 100644 --- a/src/Mod/Spreadsheet/Gui/SpreadsheetView.h +++ b/src/Mod/Spreadsheet/Gui/SpreadsheetView.h @@ -66,6 +66,14 @@ public: bool onMsg(const char* pMsg,const char** ppReturn); bool onHasMsg(const char* pMsg) const; + /** @name Printing */ + //@{ + void print(); + void printPdf(); + void printPreview(); + void print(QPrinter*); + //@} + void updateCell(const App::Property * prop); Spreadsheet::Sheet * getSheet() { return sheet; } From 67f8a4c61c19e7a69a43c4e11668eea1de5886b9 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 5 Dec 2021 12:16:54 +0100 Subject: [PATCH 127/133] Spreadsheet: fix format of table cells when used for printing, by default use landscape orientation --- src/Mod/Spreadsheet/Gui/SheetTableView.cpp | 65 ++++++++++++++++++++- src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp | 3 + 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/Mod/Spreadsheet/Gui/SheetTableView.cpp b/src/Mod/Spreadsheet/Gui/SheetTableView.cpp index 7a99207cb8..d5f079138e 100644 --- a/src/Mod/Spreadsheet/Gui/SheetTableView.cpp +++ b/src/Mod/Spreadsheet/Gui/SheetTableView.cpp @@ -931,6 +931,12 @@ QString SheetTableView::toHtml() const QTextTableFormat tableFormat; tableFormat.setCellSpacing(0.0); tableFormat.setCellPadding(2.0); + QVector constraints; + for (int col = 0; col < colCount + 1; col++) { + constraints.append(QTextLength(QTextLength::FixedLength, sheet->getColumnWidth(col))); + } + constraints.prepend(QTextLength(QTextLength::FixedLength, 30.0)); + tableFormat.setColumnWidthConstraints(constraints); QTextCharFormat boldFormat; QFont boldFont = boldFormat.font(); @@ -943,6 +949,8 @@ QString SheetTableView::toHtml() const bgFormat.setBackground(QBrush(bgColor)); QTextTable *table = cursor.insertTable(rowCount + 2, colCount + 2, tableFormat); + + // The header cells of the rows for (int row = 0; row < rowCount + 1; row++) { QTextTableCell headerCell = table->cellAt(row+1, 0); headerCell.setFormat(bgFormat); @@ -950,6 +958,8 @@ QString SheetTableView::toHtml() const QString data = model()->headerData(row, Qt::Vertical).toString(); headerCellCursor.insertText(data, boldFormat); } + + // The header cells of the columns for (int col = 0; col < colCount + 1; col++) { QTextTableCell headerCell = table->cellAt(0, col+1); headerCell.setFormat(bgFormat); @@ -961,11 +971,64 @@ QString SheetTableView::toHtml() const headerCellCursor.insertText(data, boldFormat); } + // The cells for (const auto& it : cells) { + if (sheet->isMergedCell(it)) { + int rows, cols; + sheet->getSpans(it, rows, cols); + table->mergeCells(it.row() + 1, it.col() + 1, rows, cols); + } + QModelIndex index = model()->index(it.row(), it.col()); + QTextCharFormat cellFormat; QTextTableCell cell = table->cellAt(it.row() + 1, it.col() + 1); + + // font + QVariant font = model()->data(index, Qt::FontRole); + if (font.isValid()) { + cellFormat.setFont(font.value()); + } + + // foreground + QVariant fgColor = model()->data(index, Qt::ForegroundRole); + if (fgColor.isValid()) { + cellFormat.setForeground(QBrush(fgColor.value())); + } + + // background + QVariant cbgClor = model()->data(index, Qt::BackgroundRole); + if (cbgClor.isValid()) { + QTextCharFormat bgFormat; + bgFormat.setBackground(QBrush(cbgClor.value())); + cell.setFormat(bgFormat); + } + QTextCursor cellCursor = cell.firstCursorPosition(); - QString data = model()->data(model()->index(it.row(), it.col())).toString().simplified(); + + // alignment + QVariant align = model()->data(index, Qt::TextAlignmentRole); + if (align.isValid()) { + Qt::Alignment alignment = static_cast(align.toInt()); + QTextBlockFormat blockFormat = cellCursor.blockFormat(); + blockFormat.setAlignment(alignment); + cellCursor.setBlockFormat(blockFormat); + + // This doesn't seem to have any effect on single cells but works if several + // cells are merged + QTextCharFormat::VerticalAlignment valign = QTextCharFormat::AlignMiddle; + QTextCharFormat format = cell.format(); + if (alignment & Qt::AlignTop) { + valign = QTextCharFormat::AlignTop; + } + else if (alignment & Qt::AlignBottom) { + valign = QTextCharFormat::AlignBottom; + } + format.setVerticalAlignment(valign); + cell.setFormat(format); + } + + // text + QString data = model()->data(index).toString().simplified(); cellCursor.insertText(data, cellFormat); } diff --git a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp index 2a9a7a2886..36b444b4c5 100644 --- a/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp +++ b/src/Mod/Spreadsheet/Gui/SpreadsheetView.cpp @@ -226,6 +226,7 @@ bool SheetView::onHasMsg(const char *pMsg) const void SheetView::print() { QPrinter printer(QPrinter::ScreenResolution); + printer.setOrientation(QPrinter::Landscape); printer.setFullPage(true); QPrintDialog dlg(&printer, this); if (dlg.exec() == QDialog::Accepted) { @@ -236,6 +237,7 @@ void SheetView::print() void SheetView::printPreview() { QPrinter printer(QPrinter::ScreenResolution); + printer.setOrientation(QPrinter::Landscape); QPrintPreviewDialog dlg(&printer, this); connect(&dlg, SIGNAL(paintRequested (QPrinter *)), this, SLOT(print(QPrinter *))); @@ -261,6 +263,7 @@ void SheetView::printPdf() QString::fromLatin1("%1 (*.pdf)").arg(tr("PDF file"))); if (!filename.isEmpty()) { QPrinter printer(QPrinter::ScreenResolution); + printer.setOrientation(QPrinter::Landscape); printer.setOutputFormat(QPrinter::PdfFormat); printer.setOutputFileName(filename); print(&printer); From 1af3755a175fa11d9d04ee51582d14848d8b45d0 Mon Sep 17 00:00:00 2001 From: Uwe Date: Sun, 5 Dec 2021 19:21:27 +0100 Subject: [PATCH 128/133] [PD] add missing tooltips for Helix dialog --- src/Mod/PartDesign/Gui/TaskHelixParameters.ui | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.ui b/src/Mod/PartDesign/Gui/TaskHelixParameters.ui index 4dc02dbf7d..ff22ee13b6 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.ui @@ -43,6 +43,9 @@ + + Axis the helix winds around + Base X axis @@ -93,6 +96,9 @@ + + Parameter set defining the helix + Pitch-Height-Angle @@ -128,6 +134,9 @@ + + Axial distance between two turns + false @@ -155,6 +164,9 @@ + + Height of helix + false @@ -182,6 +194,9 @@ + + Number of turns + false @@ -206,6 +221,9 @@ + + Angle of the cone that forms a hull around the helix. + false @@ -230,12 +248,15 @@ - Growth: + Radial growth: + + Radial growth of helix per turn + false @@ -251,6 +272,9 @@ true + + Sets turning direction to left handed + Left handed @@ -261,6 +285,9 @@ true + + Reverses the Axis direction + Reversed @@ -268,6 +295,9 @@ + + the result will be the intersection of helix and the preexisting body + Remove outside of profile From d2dc6ca7dd9359568b3c24dc86bafdcd1ffe6d10 Mon Sep 17 00:00:00 2001 From: Uwe Date: Sun, 5 Dec 2021 21:28:52 +0100 Subject: [PATCH 129/133] [PD] rewrite a Helix function rewrite the function to check if helix might intersect itself to make it better readable/understandable --- src/Mod/PartDesign/App/FeatureHelix.cpp | 41 +++++++++++++------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureHelix.cpp b/src/Mod/PartDesign/App/FeatureHelix.cpp index ce56c7fd45..aee780be08 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.cpp +++ b/src/Mod/PartDesign/App/FeatureHelix.cpp @@ -471,35 +471,36 @@ TopoDS_Shape Helix::generateHelixPath(void) // this function calculates self intersection safe pitch based on the profile bounding box. double Helix::safePitch() { - Base::Vector3d v = Axis.getValue(); - Base::Vector3d n = getProfileNormal(); - Base::Vector3d s = v.Cross(n); // pointing towards the desired helix start point. - if (s.IsNull()) - return Precision::Confusion(); // if the axis orthogonal to the profile, any pitch >0 is safe - - // Below is an approximation. It is possible to do the general way by solving for the pitch - // where the helix is self intersecting. + Base::Vector3d axis = Axis.getValue(); + Base::Vector3d start = axis.Cross(getProfileNormal()); // pointing towards the helix start point + if (start.IsNull()) + return Precision::Confusion(); // if the axis orthogonal to the profile, any pitch > 0 is safe double angle = Angle.getValue() / 180.0 * M_PI; - + gp_Dir direction(axis.x, axis.y, axis.z); + gp_Dir directionStart(start.x, start.y, start.z); TopoDS_Shape sketchshape = getVerifiedFace(); - Bnd_Box bb; - BRepBndLib::Add(sketchshape, bb); + Bnd_Box boundingBox; + BRepBndLib::Add(sketchshape, boundingBox); + // get boundary and dimensions of boundingBox double Xmin, Ymin, Zmin, Xmax, Ymax, Zmax; - bb.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax); - + boundingBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax); double X = Xmax - Xmin, Y = Ymax - Ymin, Z = Zmax - Zmin; + gp_Vec boundingBoxVector(X, Y, Z); - gp_Dir dir(v.x, v.y, v.z); - gp_Vec bbvec(X, Y, Z); + // Below is an approximation becaue since we take the bounding box it is + // impossible to calculate it precisely. For example a circle has as bounding + // box a square and thus results in a larger pitch than really necessary - double p0 = bbvec * dir; // safe pitch if angle=0 + // minimal safe pitch if the angle is 0 + double p0 = boundingBoxVector * direction; - gp_Dir dir_s(s.x, s.y, s.z); - - if (tan(abs(angle)) * p0 > abs(bbvec * dir_s)) - return abs(bbvec * dir_s) / tan(abs(angle)); + // if the angle is so large that the distange perpendicular to p0 + // between two turns is larger than the bounding box size in this direction + // the pitch can be smaller than p0 + if (tan(abs(angle)) * p0 > abs(boundingBoxVector * directionStart)) + return abs(boundingBoxVector * directionStart) / tan(abs(angle)); else return p0; } From 3f76c7869a083b21ddd9de2cf6976585bc37807d Mon Sep 17 00:00:00 2001 From: Uwe Date: Sun, 5 Dec 2021 21:59:06 +0100 Subject: [PATCH 130/133] [PD] Helix: improve variable naming use unique variable names --- src/Mod/PartDesign/App/FeatureHelix.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureHelix.cpp b/src/Mod/PartDesign/App/FeatureHelix.cpp index aee780be08..7fb90f15cf 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.cpp +++ b/src/Mod/PartDesign/App/FeatureHelix.cpp @@ -471,14 +471,14 @@ TopoDS_Shape Helix::generateHelixPath(void) // this function calculates self intersection safe pitch based on the profile bounding box. double Helix::safePitch() { - Base::Vector3d axis = Axis.getValue(); - Base::Vector3d start = axis.Cross(getProfileNormal()); // pointing towards the helix start point - if (start.IsNull()) + Base::Vector3d axisVec = Axis.getValue(); + Base::Vector3d startVec = axisVec.Cross(getProfileNormal()); // pointing towards the helix start point + if (startVec.IsNull()) return Precision::Confusion(); // if the axis orthogonal to the profile, any pitch > 0 is safe double angle = Angle.getValue() / 180.0 * M_PI; - gp_Dir direction(axis.x, axis.y, axis.z); - gp_Dir directionStart(start.x, start.y, start.z); + gp_Dir direction(axisVec.x, axisVec.y, axisVec.z); + gp_Dir directionStart(startVec.x, startVec.y, startVec.z); TopoDS_Shape sketchshape = getVerifiedFace(); Bnd_Box boundingBox; BRepBndLib::Add(sketchshape, boundingBox); @@ -487,20 +487,20 @@ double Helix::safePitch() double Xmin, Ymin, Zmin, Xmax, Ymax, Zmax; boundingBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax); double X = Xmax - Xmin, Y = Ymax - Ymin, Z = Zmax - Zmin; - gp_Vec boundingBoxVector(X, Y, Z); + gp_Vec boundingBoxVec(X, Y, Z); // Below is an approximation becaue since we take the bounding box it is // impossible to calculate it precisely. For example a circle has as bounding // box a square and thus results in a larger pitch than really necessary // minimal safe pitch if the angle is 0 - double p0 = boundingBoxVector * direction; + double p0 = boundingBoxVec * direction; // if the angle is so large that the distange perpendicular to p0 // between two turns is larger than the bounding box size in this direction // the pitch can be smaller than p0 - if (tan(abs(angle)) * p0 > abs(boundingBoxVector * directionStart)) - return abs(boundingBoxVector * directionStart) / tan(abs(angle)); + if (tan(abs(angle)) * p0 > abs(boundingBoxVec * directionStart)) + return abs(boundingBoxVec * directionStart) / tan(abs(angle)); else return p0; } From 3cef5da1ad1a7139be3be36af912447036972b26 Mon Sep 17 00:00:00 2001 From: Uwe Date: Mon, 6 Dec 2021 02:40:34 +0100 Subject: [PATCH 131/133] [PD] fix division by zero in Helix - when a helix is defined in the growth mode it can have a pitch of zero This commit fixes the resulting division by zero by directly setting the known turns --- src/Mod/PartDesign/Gui/TaskHelixParameters.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp index 58d4fc45c4..f6af96849b 100644 --- a/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskHelixParameters.cpp @@ -475,7 +475,7 @@ void TaskHelixParameters::onModeChanged(int index) ui->pitch->setValue(propPitch->getValue()); ui->height->setValue(propHeight->getValue()); - ui->turns->setValue((propHeight->getValue()) / (propPitch->getValue())); + ui->turns->setValue(propTurns->getValue()); recomputeFeature(); updateUI(); From 382b38f2bd061bd0d9b51396370f4f28c1e2a126 Mon Sep 17 00:00:00 2001 From: luz paz Date: Sun, 5 Dec 2021 11:24:14 -0500 Subject: [PATCH 132/133] Use correct name `spacemouse` so it's uniform and searchable in our code Make all mentions of `spacemouse` in the code a single word (with no whitespace) so we can parse the source code more accurately to find mentions of it if necessary. --- conda/build.sh | 2 +- src/Gui/CommandView.cpp | 2 +- src/Gui/GestureNavigationStyle.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/conda/build.sh b/conda/build.sh index bb409f7292..f8e271f76d 100755 --- a/conda/build.sh +++ b/conda/build.sh @@ -31,7 +31,7 @@ if [[ ${HOST} =~ "Darwin" ]]; then # install space-mouse if [ ! -d "/Library/Frameworks/3DconnexionClient.framework" ]; then - echo "Installing 3D connexion space mouse drivers." + echo "Installing 3D connexion spacemouse drivers." curl -o /tmp/3dFW.dmg -L 'https://download.3dconnexion.com/drivers/mac/10-6-6_360DF97D-ED08-4ccf-A55E-0BF905E58476/3DxWareMac_v10-6-6_r3234.dmg' hdiutil attach -readonly /tmp/3dFW.dmg sudo installer -package /Volumes/3Dconnexion\ Software/Install\ 3Dconnexion\ software.pkg -target / diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index ca75721871..f9bfed6a9d 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -203,7 +203,7 @@ Action * StdPerspectiveCamera::createAction(void) //=========================================================================== // The two commands below are provided for convenience so that they can be bound -// to a button of a space mouse +// to a button of a spacemouse //=========================================================================== // Std_ViewSaveCamera diff --git a/src/Gui/GestureNavigationStyle.cpp b/src/Gui/GestureNavigationStyle.cpp index 946efb1dcf..77676c00a8 100644 --- a/src/Gui/GestureNavigationStyle.cpp +++ b/src/Gui/GestureNavigationStyle.cpp @@ -53,7 +53,7 @@ * So, to avoid entering Tilt mode, the style implements its own tap-and-hold * detection, and a special Pan state for the state machine - StickyPanState. * - * This style wasn't tested with space mouse during development (I don't have one). + * This style wasn't tested with spacemouse during development (I don't have one). * * See also GestureNavigationStyle-state-machine-diagram.docx for a crude * diagram of the state machine. From 3f97cb660e4549d6fc891ba977ff9e467745dd50 Mon Sep 17 00:00:00 2001 From: Brent Roettger Date: Sun, 5 Dec 2021 21:09:39 -0600 Subject: [PATCH 133/133] Added back defaults for SpaceExplorer --- src/Gui/3Dconnexion/3DConnexion.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Gui/3Dconnexion/3DConnexion.xml b/src/Gui/3Dconnexion/3DConnexion.xml index 46f2add5b0..a3a635a3c2 100644 --- a/src/Gui/3Dconnexion/3DConnexion.xml +++ b/src/Gui/3Dconnexion/3DConnexion.xml @@ -35,6 +35,26 @@ + + + + + + + + + + + + + + + + + + + +