diff --git a/.github/workflows/actions/runCPPTests/action.yml b/.github/workflows/actions/runCPPTests/action.yml new file mode 100644 index 0000000000..ca33f90d6b --- /dev/null +++ b/.github/workflows/actions/runCPPTests/action.yml @@ -0,0 +1,62 @@ +# *************************************************************************** +# * Copyright (c) 2023 0penBrain * +# * Copyright (c) 2023 FreeCAD Project Association * +# * * +# * 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 * +# * * +# *************************************************************************** + +name: runCPPTests +description: "Run: C++ tests" + +inputs: + testCommand: + description: "Test command to be run" + required: true + testLogFile: + description: "Path for the command-line output of the tests" + required: true + reportFile: + description: "Report file" + required: true + +runs: + using: "composite" + steps: + - name: Run GTest unit tests + id: runGoogleTests + shell: bash + run: stdbuf -oL -eL ${{ inputs.testCommand }} |& tee -a ${{ inputs.testLogFile }} + - name: Parse test results + if: always() + shell: bash + run: | + result=$(sed -ne "/Global test environment tear-down/,/^$/{/^$/d;p}" ${{ inputs.testLogFile }}) + if [ $(echo $result | grep -F "[ FAILED ]") ] + then + echo "
:fire: GTest C++ unit test suite failed" >> ${{ inputs.reportFile }} + else + echo "
:heavy_check_mark: GTest C++ unit test suite succeeded" >> ${{ inputs.reportFile }} + fi + echo "" >> ${{ inputs.reportFile }} + echo "Results" >> ${{ inputs.reportFile }} + echo "" >> ${{ inputs.reportFile }} + echo '```' >> ${{ inputs.reportFile }} + echo "$result" >> ${{ inputs.reportFile }} + echo '```' >> ${{ inputs.reportFile }} + echo "
">> ${{ inputs.reportFile }} + echo "" >> ${{ inputs.reportFile }} diff --git a/.github/workflows/actions/runTests/action.yml b/.github/workflows/actions/runPythonTests/action.yml similarity index 96% rename from .github/workflows/actions/runTests/action.yml rename to .github/workflows/actions/runPythonTests/action.yml index 29e4aab55c..1396f1c117 100644 --- a/.github/workflows/actions/runTests/action.yml +++ b/.github/workflows/actions/runPythonTests/action.yml @@ -1,5 +1,5 @@ # *************************************************************************** -# * Copyright (c) 2023 0penBrain * +# * Copyright (c) 2023 0penBrain * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -19,15 +19,15 @@ # * * # *************************************************************************** -name: runTests -description: "Linux: run unit tests, generate log and report" +name: runPythonTests +description: "Linux: run Python tests, generate log and report" inputs: testDescription: description: "Test description text, will be used on report" required: true testCommand: - description: "Test command to be ran" + description: "Test command to be run" required: true logFile: description: "Path for log file" diff --git a/.github/workflows/sub_buildUbuntu2004.yml b/.github/workflows/sub_buildUbuntu2004.yml index 9e69cbc9fb..1a19ae7d5f 100644 --- a/.github/workflows/sub_buildUbuntu2004.yml +++ b/.github/workflows/sub_buildUbuntu2004.yml @@ -185,7 +185,7 @@ jobs: - name: FreeCAD CLI tests on build dir if: inputs.testOnBuildDir timeout-minutes: 10 - uses: ./.github/workflows/actions/runTests + uses: ./.github/workflows/actions/runPythonTests with: testDescription: "CLI tests on build dir" testCommand: ${{ env.builddir }}bin/FreeCADCmd -t 0 @@ -194,12 +194,19 @@ jobs: - name: FreeCAD GUI tests on build dir if: inputs.testOnBuildDir timeout-minutes: 15 - uses: ./.github/workflows/actions/runTests + uses: ./.github/workflows/actions/runPythonTests with: testDescription: "GUI tests on build dir" testCommand: xvfb-run ${{ env.builddir }}/bin/FreeCAD -t 0 logFile: ${{ env.logdir }}TestGUIBuild.log reportFile: ${{env.reportdir}}${{ env.reportfilename }} + - name: C++ unit tests + timeout-minutes: 1 + uses: ./.github/workflows/actions/runCPPTests + with: + testCommand: ${{ env.builddir }}/tests/Tests_run --gtest_output=json:${{env.reportdir}}gtest_results.json + testLogFile: ${{env.reportdir}}gtest_test_log.txt + reportFile: ${{env.reportdir}}${{ env.reportfilename }} - name: CMake Install uses: ./.github/workflows/actions/linux/install with: @@ -209,7 +216,7 @@ jobs: reportFile: ${{env.reportdir}}${{ env.reportfilename }} - name: FreeCAD CLI tests on install timeout-minutes: 10 - uses: ./.github/workflows/actions/runTests + uses: ./.github/workflows/actions/runPythonTests with: testDescription: "CLI tests on install" testCommand: FreeCADCmd -t 0 @@ -217,7 +224,7 @@ jobs: reportFile: ${{env.reportdir}}${{ env.reportfilename }} - name: FreeCAD GUI tests on install timeout-minutes: 15 - uses: ./.github/workflows/actions/runTests + uses: ./.github/workflows/actions/runPythonTests with: testDescription: "GUI tests on install" testCommand: xvfb-run FreeCAD -t 0 diff --git a/.github/workflows/sub_buildUbuntu2204.yml b/.github/workflows/sub_buildUbuntu2204.yml index 90d37dabf6..f9699aeb4f 100644 --- a/.github/workflows/sub_buildUbuntu2204.yml +++ b/.github/workflows/sub_buildUbuntu2204.yml @@ -1,5 +1,5 @@ # *************************************************************************** -# * Copyright (c) 2023 0penBrain * +# * Copyright (c) 2023 0penBrain * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -194,7 +194,7 @@ jobs: - name: FreeCAD CLI tests on build dir if: inputs.testOnBuildDir timeout-minutes: 10 - uses: ./.github/workflows/actions/runTests + uses: ./.github/workflows/actions/runPythonTests with: testDescription: "CLI tests on build dir" testCommand: ${{ env.builddir }}bin/FreeCADCmd -t 0 @@ -203,12 +203,19 @@ jobs: - name: FreeCAD GUI tests on build dir if: inputs.testOnBuildDir timeout-minutes: 15 - uses: ./.github/workflows/actions/runTests + uses: ./.github/workflows/actions/runPythonTests with: testDescription: "GUI tests on build dir" testCommand: xvfb-run ${{ env.builddir }}/bin/FreeCAD -t 0 logFile: ${{ env.logdir }}TestGUIBuild.log reportFile: ${{env.reportdir}}${{ env.reportfilename }} + - name: C++ unit tests + timeout-minutes: 1 + uses: ./.github/workflows/actions/runCPPTests + with: + testCommand: ${{ env.builddir }}/tests/Tests_run --gtest_output=json:${{env.reportdir}}gtest_results.json + testLogFile: ${{env.reportdir}}gtest_test_log.txt + reportFile: ${{env.reportdir}}${{ env.reportfilename }} - name: CMake Install uses: ./.github/workflows/actions/linux/install with: @@ -218,7 +225,7 @@ jobs: reportFile: ${{env.reportdir}}${{ env.reportfilename }} - name: FreeCAD CLI tests on install timeout-minutes: 10 - uses: ./.github/workflows/actions/runTests + uses: ./.github/workflows/actions/runPythonTests with: testDescription: "CLI tests on install" testCommand: FreeCADCmd -t 0 @@ -226,7 +233,7 @@ jobs: reportFile: ${{env.reportdir}}${{ env.reportfilename }} - name: FreeCAD GUI tests on install timeout-minutes: 15 - uses: ./.github/workflows/actions/runTests + uses: ./.github/workflows/actions/runPythonTests with: testDescription: "GUI tests on install" testCommand: xvfb-run FreeCAD -t 0 diff --git a/.github/workflows/sub_lint.yml b/.github/workflows/sub_lint.yml index 83738ba26b..5ec623ec2f 100644 --- a/.github/workflows/sub_lint.yml +++ b/.github/workflows/sub_lint.yml @@ -39,7 +39,7 @@ on: type: string required: true checkLineendings: - default: true + default: false type: boolean required: false lineendingsFailSilent: diff --git a/src/Base/Tools.cpp b/src/Base/Tools.cpp index 32a02708fb..f3385132c5 100644 --- a/src/Base/Tools.cpp +++ b/src/Base/Tools.cpp @@ -154,6 +154,8 @@ std::string Base::Tools::addNumber(const std::string& name, unsigned int num, in std::string Base::Tools::getIdentifier(const std::string& name) { + if (name.empty()) + return "_"; // check for first character whether it's a digit std::string CleanName = name; if (!CleanName.empty() && CleanName[0] >= 48 && CleanName[0] <= 57) diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 077af9fafb..b3685d4a35 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -41,6 +41,8 @@ # include #endif +#include + #include #include #include @@ -1670,6 +1672,18 @@ Gui::PreferencePackManager* Application::prefPackManager() //************************************************************************** // Init, Destruct and singleton +namespace { +void setCategoryFilterRules() +{ + QString filter; + QTextStream stream(&filter); + stream << "qt.qpa.xcb.warning=false\n"; + stream << "qt.qpa.mime.warning=false\n"; + stream.flush(); + QLoggingCategory::setFilterRules(filter); +} +} + using _qt_msg_handler_old = void (*)(QtMsgType, const QMessageLogContext &, const QString &); _qt_msg_handler_old old_qtmsg_handler = nullptr; @@ -1755,6 +1769,7 @@ void Application::initApplication() initTypes(); new Base::ScriptProducer( "FreeCADGuiInit", FreeCADGuiInit ); init_resources(); + setCategoryFilterRules(); old_qtmsg_handler = qInstallMessageHandler(messageHandler); init = true; } diff --git a/src/Mod/Draft/Resources/Draft.qrc b/src/Mod/Draft/Resources/Draft.qrc index 1df9126aaa..7907e7423e 100644 --- a/src/Mod/Draft/Resources/Draft.qrc +++ b/src/Mod/Draft/Resources/Draft.qrc @@ -49,6 +49,7 @@ icons/Draft_Join.svg icons/Draft_Label.svg icons/Draft_Layer.svg + icons/Draft_LayerManager.svg icons/Draft_Line.svg icons/Draft_LinkArray.svg icons/Draft_Lock.svg @@ -191,5 +192,6 @@ ui/dialog_AnnotationStyleEditor.ui ui/TaskPanel_SetStyle.ui ui/dialogHatch.ui + ui/dialogLayers.ui diff --git a/src/Mod/Draft/Resources/icons/Draft_LayerManager.svg b/src/Mod/Draft/Resources/icons/Draft_LayerManager.svg new file mode 100644 index 0000000000..34134c781f --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Draft_LayerManager.svg @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/ui/dialogLayers.ui b/src/Mod/Draft/Resources/ui/dialogLayers.ui new file mode 100644 index 0000000000..32c1468231 --- /dev/null +++ b/src/Mod/Draft/Resources/ui/dialogLayers.ui @@ -0,0 +1,94 @@ + + + Dialog + + + + 0 + 0 + 667 + 320 + + + + Layers manager + + + + + + true + + + + + + + + + New + + + + + + + Delete + + + + + + + Select all + + + + + + + Toggle on/off + + + + + + + Isolate + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + OK + + + + + + + + + + diff --git a/src/Mod/Draft/draftguitools/gui_base_original.py b/src/Mod/Draft/draftguitools/gui_base_original.py index 69430e3a5c..1b58a33d9b 100644 --- a/src/Mod/Draft/draftguitools/gui_base_original.py +++ b/src/Mod/Draft/draftguitools/gui_base_original.py @@ -148,7 +148,7 @@ class DraftTool: if utils.get_param("showPlaneTracker", False): self.planetrack = trackers.PlaneTracker() if hasattr(Gui, "Snapper"): - Gui.Snapper.setTrackers() + Gui.Snapper.setTrackers(tool=True) _msg("{}".format(16*"-")) _msg("GuiCommand: {}".format(self.featureName)) diff --git a/src/Mod/Draft/draftguitools/gui_grid.py b/src/Mod/Draft/draftguitools/gui_grid.py index 835a98cd2d..0173dd8dc2 100644 --- a/src/Mod/Draft/draftguitools/gui_grid.py +++ b/src/Mod/Draft/draftguitools/gui_grid.py @@ -66,7 +66,7 @@ class ToggleGrid(gui_base.GuiCommandSimplest): super(ToggleGrid, self).Activated() if hasattr(Gui, "Snapper"): - Gui.Snapper.setTrackers() + Gui.Snapper.setTrackers(tool=True) if Gui.Snapper.grid: if Gui.Snapper.grid.Visible: Gui.Snapper.grid.off() diff --git a/src/Mod/Draft/draftguitools/gui_layers.py b/src/Mod/Draft/draftguitools/gui_layers.py index ab66fa7347..432e754c7f 100644 --- a/src/Mod/Draft/draftguitools/gui_layers.py +++ b/src/Mod/Draft/draftguitools/gui_layers.py @@ -30,7 +30,10 @@ # @{ from PySide.QtCore import QT_TRANSLATE_NOOP +import os +import FreeCAD import FreeCADGui as Gui +import Draft import Draft_rc import draftguitools.gui_base as gui_base @@ -40,6 +43,18 @@ from draftutils.translate import translate bool(Draft_rc.__name__) +def getColorIcon(color): + + "returns a QtGui.QIcon from a color 3-float tuple" + + from PySide import QtCore,QtGui + c = QtGui.QColor(int(color[0]*255),int(color[1]*255),int(color[2]*255)) + im = QtGui.QImage(48,48,QtGui.QImage.Format_ARGB32) + im.fill(c) + px = QtGui.QPixmap.fromImage(im) + return QtGui.QIcon(px) + + class Layer(gui_base.GuiCommandSimplest): """GuiCommand to create a Layer object in the document.""" @@ -66,6 +81,435 @@ class Layer(gui_base.GuiCommandSimplest): self.doc.commitTransaction() +class LayerManager: + + """GuiCommand that displays a Layers manager dialog""" + + def GetResources(self): + + return {'Pixmap' : 'Draft_LayerManager', + 'MenuText': QT_TRANSLATE_NOOP("Draft_LayerManager", "Manage layers..."), + 'ToolTip' : QT_TRANSLATE_NOOP("Draft_LayerManager", "Set/modify the different layers of this document")} + + def Activated(self): + + from PySide import QtCore, QtGui + + # store changes to be committed + self.deleteList = [] + + # create the dialog + self.dialog = Gui.PySideUic.loadUi(":/ui/dialogLayers.ui") + + # set nice icons + self.dialog.setWindowIcon(QtGui.QIcon(":/icons/Draft_Layer.svg")) + self.dialog.buttonNew.setIcon(QtGui.QIcon(":/icons/document-new.svg")) + self.dialog.buttonDelete.setIcon(QtGui.QIcon(":/icons/delete.svg")) + self.dialog.buttonSelectAll.setIcon(QtGui.QIcon(":/icons/edit-select-all.svg")) + self.dialog.buttonToggle.setIcon(QtGui.QIcon(":/icons/dagViewVisible.svg")) + self.dialog.buttonIsolate.setIcon(QtGui.QIcon(":/icons/view-refresh.svg")) + self.dialog.buttonCancel.setIcon(QtGui.QIcon(":/icons/edit_Cancel.svg")) + self.dialog.buttonOK.setIcon(QtGui.QIcon(":/icons/edit_OK.svg")) + + # restore window geometry from stored state + pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + w = pref.GetInt("LayersManagerWidth",640) + h = pref.GetInt("LayersManagerHeight",320) + self.dialog.resize(w,h) + + # center the dialog over FreeCAD window + mw = Gui.getMainWindow() + self.dialog.move(mw.frameGeometry().topLeft() + mw.rect().center() - self.dialog.rect().center()) + + # connect signals/slots + self.dialog.buttonNew.clicked.connect(self.addItem) + self.dialog.buttonDelete.clicked.connect(self.onDelete) + self.dialog.buttonSelectAll.clicked.connect(self.dialog.tree.selectAll) + self.dialog.buttonToggle.clicked.connect(self.onToggle) + self.dialog.buttonCancel.clicked.connect(self.dialog.reject) + self.dialog.buttonIsolate.clicked.connect(self.onIsolate) + self.dialog.buttonOK.clicked.connect(self.accept) + self.dialog.rejected.connect(self.reject) + + # set the model up + self.model = QtGui.QStandardItemModel() + self.dialog.tree.setModel(self.model) + self.dialog.tree.setUniformRowHeights(True) + self.dialog.tree.setItemDelegate(Layers_Delegate()) + self.dialog.tree.setItemsExpandable(False) + self.dialog.tree.setRootIsDecorated(False) # removes spacing in first column + self.dialog.tree.setSelectionMode(QtGui.QTreeView.ExtendedSelection) # allow to select many + + # fill the tree view + self.update() + + # rock 'n roll!!! + self.dialog.exec_() + + def accept(self): + + "when OK button is pressed" + + changed = False + + # delete layers + for name in self.deleteList: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + FreeCAD.ActiveDocument.removeObject(name) + + # apply changes + for row in range(self.model.rowCount()): + + # get or create layer + name = self.model.item(row,1).toolTip() + obj = None + if name: + obj = FreeCAD.ActiveDocument.getObject(name) + if not obj: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj = Draft.make_layer() + + # visibility + checked = True if self.model.item(row,0).checkState() == QtCore.Qt.Checked else False + if checked != obj.ViewObject.Visibility: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.Visibility = checked + + # label + label = self.model.item(row,1).text() + if label: + if obj.Label != label: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.Label = label + + # line width + width = self.model.item(row,2).data(QtCore.Qt.DisplayRole) + if width: + if obj.ViewObject.LineWidth != width: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.LineWidth = width + + # draw style + style = self.model.item(row,3).text() + if style: + if obj.ViewObject.DrawStyle != style: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.DrawStyle = style + + # line color + color = self.model.item(row,4).data(QtCore.Qt.UserRole) + if color: + if obj.ViewObject.LineColor[3:] != color: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.LineColor = color + + # shape color + color = self.model.item(row,5).data(QtCore.Qt.UserRole) + if color: + if obj.ViewObject.ShapeColor[3:] != color: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.ShapeColor = color + + # transparency + transparency = self.model.item(row,6).data(QtCore.Qt.DisplayRole) + if transparency: + if obj.ViewObject.Transparency != transparency: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.Transparency = transparency + + # line print color + color = self.model.item(row,7).data(QtCore.Qt.UserRole) + if color: + if not "LinePrintColor" in obj.ViewObject.PropertiesList: + if hasattr(obj.ViewObject.Proxy,"set_properties"): + obj.ViewObject.Proxy.set_properties(obj.ViewObject) + if "LinePrintColor" in obj.ViewObject.PropertiesList: + if obj.ViewObject.LinePrintColor[3:] != color: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.LinePrintColor = color + + # recompute + if changed: + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + + # exit + self.dialog.reject() + + def reject(self): + + "when Cancel button is pressed or dialog is closed" + + # save dialog size + pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + pref.SetInt("LayersManagerWidth",self.dialog.width()) + pref.SetInt("LayersManagerHeight",self.dialog.height()) + + return True + + def update(self): + + "rebuild the model from document contents" + + self.model.clear() + + # set header + self.model.setHorizontalHeaderLabels([translate("Draft","On"), + translate("Draft","Name"), + translate("Draft","Line width"), + translate("Draft","Draw style"), + translate("Draft","Line color"), + translate("Draft","Face color"), + translate("Draft","Transparency"), + translate("Draft","Line print color")]) + self.dialog.tree.header().setDefaultSectionSize(72) + self.dialog.tree.setColumnWidth(0,32) # on/off column + self.dialog.tree.setColumnWidth(1,128) # name column + + # populate + objs = [obj for obj in FreeCAD.ActiveDocument.Objects if Draft.getType(obj) == "Layer"] + objs.sort(key=lambda o:o.Label) + for obj in objs: + self.addItem(obj) + + def addItem(self,obj=None): + + "adds a row to the model" + + from PySide import QtCore, QtGui + + # create row with default values + onItem = QtGui.QStandardItem() + onItem.setCheckable(True) + onItem.setCheckState(QtCore.Qt.Checked) + nameItem = QtGui.QStandardItem(translate("Draft","New Layer")) + widthItem = QtGui.QStandardItem() + widthItem.setData(self.getPref("DefaultShapeLineWidth",2,"Integer"),QtCore.Qt.DisplayRole) + styleItem = QtGui.QStandardItem("Solid") + lineColorItem = QtGui.QStandardItem() + lineColorItem.setData(self.getPref("DefaultShapeLineColor",421075455),QtCore.Qt.UserRole) + shapeColorItem = QtGui.QStandardItem() + shapeColorItem.setData(self.getPref("DefaultShapeColor",3435973887),QtCore.Qt.UserRole) + transparencyItem = QtGui.QStandardItem() + transparencyItem.setData(0,QtCore.Qt.DisplayRole) + linePrintColorItem = QtGui.QStandardItem() + linePrintColorItem.setData(self.getPref("DefaultPrintColor",0),QtCore.Qt.UserRole) + + # populate with object data + if obj: + onItem.setCheckState(QtCore.Qt.Checked if obj.ViewObject.Visibility else QtCore.Qt.Unchecked) + nameItem.setText(obj.Label) + nameItem.setToolTip(obj.Name) + widthItem.setData(obj.ViewObject.LineWidth,QtCore.Qt.DisplayRole) + styleItem.setText(obj.ViewObject.DrawStyle) + lineColorItem.setData(obj.ViewObject.LineColor[:3],QtCore.Qt.UserRole) + shapeColorItem.setData(obj.ViewObject.ShapeColor[:3],QtCore.Qt.UserRole) + transparencyItem.setData(obj.ViewObject.Transparency,QtCore.Qt.DisplayRole) + if hasattr(obj.ViewObject,"LinePrintColor"): + linePrintColorItem.setData(obj.ViewObject.LinePrintColor[:3],QtCore.Qt.UserRole) + lineColorItem.setIcon(getColorIcon(lineColorItem.data(QtCore.Qt.UserRole))) + shapeColorItem.setIcon(getColorIcon(shapeColorItem.data(QtCore.Qt.UserRole))) + linePrintColorItem.setIcon(getColorIcon(linePrintColorItem.data(QtCore.Qt.UserRole))) + + # append row + self.model.appendRow([onItem, + nameItem, + widthItem, + styleItem, + lineColorItem, + shapeColorItem, + transparencyItem, + linePrintColorItem]) + + def getPref(self,value,default,valuetype="Unsigned"): + + "retrieves a view pref value" + + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View") + if valuetype == "Unsigned": + c = p.GetUnsigned(value,default) + r = float((c>>24)&0xFF)/255.0 + g = float((c>>16)&0xFF)/255.0 + b = float((c>>8)&0xFF)/255.0 + return (r,g,b,) + elif valuetype == "Integer": + return p.GetInt(value,default) + + def onDelete(self): + + "delete selected rows" + + rows = [] + for index in self.dialog.tree.selectedIndexes(): + if not index.row() in rows: + rows.append(index.row()) + + # append layer name to the delete list + if index.column() == 1: + name = self.model.itemFromIndex(index).toolTip() + if name: + if not name in self.deleteList: + self.deleteList.append(name) + + # delete rows starting from the lowest, to not alter row indexes while deleting + rows.sort() + rows.reverse() + for row in rows: + self.model.takeRow(row) + + def onToggle(self): + + "toggle selected layers on/off" + + from PySide import QtCore, QtGui + + state = None + for index in self.dialog.tree.selectedIndexes(): + if index.column() == 0: + # get state from first selected row + if state is None: + if self.model.itemFromIndex(index).checkState() == QtCore.Qt.Checked: + state = QtCore.Qt.Unchecked + else: + state = QtCore.Qt.Checked + self.model.itemFromIndex(index).setCheckState(state) + + def onIsolate(self): + + "isolates the selected layers (turns all the others off" + + from PySide import QtCore, QtGui + + onrows = [] + for index in self.dialog.tree.selectedIndexes(): + if not index.row() in onrows: + onrows.append(index.row()) + for row in range(self.model.rowCount()): + if not row in onrows: + self.model.item(row,0).setCheckState(QtCore.Qt.Unchecked) + + +if FreeCAD.GuiUp: + + from PySide import QtCore, QtGui + + class Layers_Delegate(QtGui.QStyledItemDelegate): + + "model delegate" + + def __init__(self, parent=None, *args): + + QtGui.QStyledItemDelegate.__init__(self, parent, *args) + # setEditorData() is triggered several times. + # But we want to show the color dialog only the first time + self.first = True + + def createEditor(self,parent,option,index): + + if index.column() == 0: # Layer on/off + editor = QtGui.QCheckBox(parent) + if index.column() == 1: # Layer name + editor = QtGui.QLineEdit(parent) + elif index.column() == 2: # Line width + editor = QtGui.QSpinBox(parent) + editor.setMaximum(99) + elif index.column() == 3: # Line style + editor = QtGui.QComboBox(parent) + editor.addItems(["Solid","Dashed","Dotted","Dashdot"]) + elif index.column() == 4: # Line color + editor = QtGui.QLineEdit(parent) + self.first = True + elif index.column() == 5: # Shape color + editor = QtGui.QLineEdit(parent) + self.first = True + elif index.column() == 6: # Transparency + editor = QtGui.QSpinBox(parent) + editor.setMaximum(100) + elif index.column() == 7: # Line print color + editor = QtGui.QLineEdit(parent) + self.first = True + return editor + + def setEditorData(self, editor, index): + + if index.column() == 0: # Layer on/off + editor.setChecked(index.data()) + elif index.column() == 1: # Layer name + editor.setText(index.data()) + elif index.column() == 2: # Line width + editor.setValue(index.data()) + elif index.column() == 3: # Line style + editor.setCurrentIndex(["Solid","Dashed","Dotted","Dashdot"].index(index.data())) + elif index.column() == 4: # Line color + editor.setText(str(index.data(QtCore.Qt.UserRole))) + if self.first: + c = index.data(QtCore.Qt.UserRole) + color = QtGui.QColorDialog.getColor(QtGui.QColor(int(c[0]*255),int(c[1]*255),int(c[2]*255))) + editor.setText(str(color.getRgbF())) + self.first = False + elif index.column() == 5: # Shape color + editor.setText(str(index.data(QtCore.Qt.UserRole))) + if self.first: + c = index.data(QtCore.Qt.UserRole) + color = QtGui.QColorDialog.getColor(QtGui.QColor(int(c[0]*255),int(c[1]*255),int(c[2]*255))) + editor.setText(str(color.getRgbF())) + self.first = False + elif index.column() == 6: # Transparency + editor.setValue(index.data()) + elif index.column() == 7: # Line print color + editor.setText(str(index.data(QtCore.Qt.UserRole))) + if self.first: + c = index.data(QtCore.Qt.UserRole) + color = QtGui.QColorDialog.getColor(QtGui.QColor(int(c[0]*255),int(c[1]*255),int(c[2]*255))) + editor.setText(str(color.getRgbF())) + self.first = False + + def setModelData(self, editor, model, index): + + if index.column() == 0: # Layer on/off + model.setData(index,editor.isChecked()) + elif index.column() == 1: # Layer name + model.setData(index,editor.text()) + elif index.column() == 2: # Line width + model.setData(index,editor.value()) + elif index.column() == 3: # Line style + model.setData(index,["Solid","Dashed","Dotted","Dashdot"][editor.currentIndex()]) + elif index.column() == 4: # Line color + model.setData(index,eval(editor.text()),QtCore.Qt.UserRole) + model.itemFromIndex(index).setIcon(getColorIcon(eval(editor.text()))) + elif index.column() == 5: # Shape color + model.setData(index,eval(editor.text()),QtCore.Qt.UserRole) + model.itemFromIndex(index).setIcon(getColorIcon(eval(editor.text()))) + elif index.column() == 6: # Transparency + model.setData(index,editor.value()) + elif index.column() == 7: # Line prin color + model.setData(index,eval(editor.text()),QtCore.Qt.UserRole) + model.itemFromIndex(index).setIcon(getColorIcon(eval(editor.text()))) + + + + Gui.addCommand('Draft_Layer', Layer()) +Gui.addCommand('Draft_LayerManager', LayerManager()) ## @} diff --git a/src/Mod/Draft/draftguitools/gui_lines.py b/src/Mod/Draft/draftguitools/gui_lines.py index cfe5f607bd..274ccfe3b3 100644 --- a/src/Mod/Draft/draftguitools/gui_lines.py +++ b/src/Mod/Draft/draftguitools/gui_lines.py @@ -139,7 +139,7 @@ class Line(gui_base_original.Creator): if self.oldWP: App.DraftWorkingPlane.setFromParameters(self.oldWP) if hasattr(Gui, "Snapper"): - Gui.Snapper.setGrid() + Gui.Snapper.setGrid(tool=True) Gui.Snapper.restack() self.oldWP = None diff --git a/src/Mod/Draft/draftguitools/gui_snapper.py b/src/Mod/Draft/draftguitools/gui_snapper.py index a373e9e65a..171b531c3d 100644 --- a/src/Mod/Draft/draftguitools/gui_snapper.py +++ b/src/Mod/Draft/draftguitools/gui_snapper.py @@ -1594,15 +1594,15 @@ class Snapper: self.toolbar.toggleViewAction().setVisible(False) - def setGrid(self): + def setGrid(self, tool=False): """Set the grid, if visible.""" self.setTrackers() if self.grid and (not self.forceGridOff): if self.grid.Visible: - self.grid.set() + self.grid.set(tool) - def setTrackers(self): + def setTrackers(self, tool=False): """Set the trackers.""" v = Draft.get3DView() if v and (v != self.activeview): @@ -1620,7 +1620,10 @@ class Snapper: else: if Draft.getParam("grid", True): self.grid = trackers.gridTracker() - self.grid.on() + if Draft.getParam("alwaysShowGrid", True) or tool: + self.grid.on() + else: + self.grid.off() else: self.grid = None self.tracker = trackers.snapTracker() @@ -1651,7 +1654,7 @@ class Snapper: self.activeview = v if self.grid and (not self.forceGridOff): - self.grid.set() + self.grid.set(tool) def addHoldPoint(self): diff --git a/src/Mod/Draft/draftguitools/gui_trackers.py b/src/Mod/Draft/draftguitools/gui_trackers.py index a2ebb17b17..577ae5c13b 100644 --- a/src/Mod/Draft/draftguitools/gui_trackers.py +++ b/src/Mod/Draft/draftguitools/gui_trackers.py @@ -1216,7 +1216,7 @@ class gridTracker(Tracker): self.numlines = Draft.getParam("gridSize", 100) self.update() - def set(self): + def set(self,tool=False): """Move and rotate the grid according to the current working plane.""" self.reset() Q = FreeCAD.DraftWorkingPlane.getRotation().Rotation.Q @@ -1225,7 +1225,8 @@ class gridTracker(Tracker): self.trans.translation.setValue([P.x, P.y, P.z]) self.displayHumanFigure() self.setAxesColor() - self.on() + if tool: + self.on() def getClosestNode(self, point): """Return the closest node from the given point.""" diff --git a/src/Mod/Draft/draftutils/init_tools.py b/src/Mod/Draft/draftutils/init_tools.py index 49b401719c..82a7114f0c 100644 --- a/src/Mod/Draft/draftutils/init_tools.py +++ b/src/Mod/Draft/draftutils/init_tools.py @@ -112,6 +112,7 @@ def get_draft_utility_commands_menu(): "Draft_ApplyStyle", "Separator", "Draft_Layer", + "Draft_LayerManager", "Draft_AddNamedGroup", "Draft_AddToGroup", "Draft_SelectGroup", @@ -130,7 +131,7 @@ def get_draft_utility_commands_menu(): def get_draft_utility_commands_toolbar(): """Return the utility commands list for the toolbar.""" - return ["Draft_Layer", + return ["Draft_LayerManager", "Draft_AddNamedGroup", "Draft_AddToGroup", "Draft_SelectGroup", diff --git a/src/Mod/Fem/Gui/ViewProviderAnalysis.cpp b/src/Mod/Fem/Gui/ViewProviderAnalysis.cpp index 7b8a387cc5..6cf3adb674 100644 --- a/src/Mod/Fem/Gui/ViewProviderAnalysis.cpp +++ b/src/Mod/Fem/Gui/ViewProviderAnalysis.cpp @@ -31,6 +31,7 @@ # include #endif +#include #include #include #include @@ -38,6 +39,8 @@ #include #include #include +#include +#include #include #include #include @@ -251,15 +254,40 @@ void ViewProviderFemAnalysis::dropObject(App::DocumentObject *obj) bool ViewProviderFemAnalysis::onDelete(const std::vector &) { - // warn the user if the object has childs - + // warn the user if the object has unselected children auto objs = claimChildren(); + return checkSelectedChildren(objs, this->getDocument(), "analysis"); +} + +bool ViewProviderFemAnalysis::checkSelectedChildren(const std::vector objs, + Gui::Document* docGui, std::string objectName) +{ + // warn the user if the object has unselected children if (!objs.empty()) { + // check if all children are in the selection + bool found = false; + auto selectionList = Gui::Selection().getSelectionEx(docGui->getDocument()->getName()); + for (auto child : objs) { + found = false; + for (Gui::SelectionObject selection : selectionList) { + if (std::string(child->getNameInDocument()) + == std::string(selection.getFeatName())) { + found = true; + break; + } + } + if (!found) + break; + } + if (found)// all children are selected too + return true; + // generate dialog QString bodyMessage; QTextStream bodyMessageStream(&bodyMessage); bodyMessageStream << qApp->translate("Std_Delete", - "The analysis is not empty, therefore the\nfollowing referencing objects might be lost:"); + ("The " + objectName + " is not empty, therefore the\nfollowing " + "referencing objects might be lost:").c_str()); bodyMessageStream << '\n'; for (auto ObjIterator : objs) bodyMessageStream << '\n' << QString::fromUtf8(ObjIterator->Label.getValue()); diff --git a/src/Mod/Fem/Gui/ViewProviderAnalysis.h b/src/Mod/Fem/Gui/ViewProviderAnalysis.h index e993a8b2dc..4f62db2a8d 100644 --- a/src/Mod/Fem/Gui/ViewProviderAnalysis.h +++ b/src/Mod/Fem/Gui/ViewProviderAnalysis.h @@ -52,10 +52,10 @@ class FemGuiExport ViewProviderFemAnalysis : public Gui::ViewProviderDocumentObj PROPERTY_HEADER_WITH_OVERRIDE(FemGui::ViewProviderAnalysis); public: - /// constructor. + /// constructor ViewProviderFemAnalysis(); - /// destructor. + /// destructor ~ViewProviderFemAnalysis() override; void attach(App::DocumentObject*) override; @@ -63,17 +63,19 @@ public: std::vector claimChildren()const override; - // handling when object is deleted + /// handling when object is deleted bool onDelete(const std::vector&) override; - /// Asks the view provider if the given object can be deleted. + /// warning on deletion when there are children + static bool checkSelectedChildren(const std::vector objs, + Gui::Document* docGui, std::string objectName); + /// asks the view provider if the given object can be deleted bool canDelete(App::DocumentObject* obj) const override; - //virtual std::vector claimChildren3D(void)const; void setupContextMenu(QMenu*, QObject*, const char*) override; - /// A list of all possible display modes + /// list of all possible display modes std::vector getDisplayModes() const override; - // shows solid in the tree + /// shows solid in the tree bool isShow() const override { return Visibility.getValue(); } diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostFunction.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostFunction.cpp index 5eff14d080..a4a0e1b089 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostFunction.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemPostFunction.cpp @@ -56,6 +56,7 @@ #include "ViewProviderFemPostFunction.h" #include "FemSettings.h" #include "TaskPostBoxes.h" +#include "ViewProviderAnalysis.h" #include "ui_BoxWidget.h" #include "ui_CylinderWidget.h" @@ -133,32 +134,10 @@ void ViewProviderFemPostFunctionProvider::updateSize() bool ViewProviderFemPostFunctionProvider::onDelete(const std::vector&) { - // warn the user if the object has childs - + // warn the user if the object has unselected children auto objs = claimChildren(); - if (!objs.empty()) - { - // generate dialog - QString bodyMessage; - QTextStream bodyMessageStream(&bodyMessage); - bodyMessageStream << qApp->translate("Std_Delete", - "The functions list is not empty, therefore the\nfollowing referencing objects might be lost:"); - bodyMessageStream << '\n'; - for (auto ObjIterator : objs) - bodyMessageStream << '\n' << QString::fromUtf8(ObjIterator->Label.getValue()); - bodyMessageStream << "\n\n" << QObject::tr("Are you sure you want to continue?"); - // show and evaluate the dialog - int DialogResult = QMessageBox::warning(Gui::getMainWindow(), - qApp->translate("Std_Delete", "Object dependencies"), bodyMessage, - QMessageBox::Yes, QMessageBox::No); - if (DialogResult == QMessageBox::Yes) - return true; - else - return false; - } - else { - return true; - } + return ViewProviderFemAnalysis::checkSelectedChildren( + objs, this->getDocument(), "functions list"); } bool ViewProviderFemPostFunctionProvider::canDelete(App::DocumentObject* obj) const @@ -178,7 +157,6 @@ PROPERTY_SOURCE(FemGui::ViewProviderFemPostFunction, Gui::ViewProviderDocumentOb ViewProviderFemPostFunction::ViewProviderFemPostFunction() : m_manip(nullptr), m_autoscale(false), m_isDragging(false), m_autoRecompute(false) { - ADD_PROPERTY_TYPE(AutoScaleFactorX, (1), "AutoScale", App::Prop_Hidden, "Automatic scaling factor"); ADD_PROPERTY_TYPE(AutoScaleFactorY, (1), "AutoScale", App::Prop_Hidden, "Automatic scaling factor"); ADD_PROPERTY_TYPE(AutoScaleFactorZ, (1), "AutoScale", App::Prop_Hidden, "Automatic scaling factor"); @@ -186,9 +164,6 @@ ViewProviderFemPostFunction::ViewProviderFemPostFunction() m_geometrySeperator = new SoSeparator(); m_geometrySeperator->ref(); - m_transform = new SoTransform(); - m_transform->ref(); - m_scale = new SoScale(); m_scale->ref(); m_scale->scaleFactor = SbVec3f(1, 1, 1); @@ -199,7 +174,6 @@ ViewProviderFemPostFunction::~ViewProviderFemPostFunction() m_geometrySeperator->unref(); m_manip->unref(); m_scale->unref(); - //transform is unref'd when it is replaced by the dragger } void ViewProviderFemPostFunction::attach(App::DocumentObject* pcObj) @@ -211,7 +185,7 @@ void ViewProviderFemPostFunction::attach(App::DocumentObject* pcObj) color->diffuseColor.setValue(0, 0, 1); color->transparency.setValue(0.5); - m_transform = new SoTransform; + SoTransform* transform = new SoTransform(); m_manip = setupManipulator(); m_manip->ref(); @@ -220,7 +194,7 @@ void ViewProviderFemPostFunction::attach(App::DocumentObject* pcObj) pcEditNode->ref(); pcEditNode->addChild(color); - pcEditNode->addChild(m_transform); + pcEditNode->addChild(transform); pcEditNode->addChild(m_geometrySeperator); m_geometrySeperator->insertChild(m_scale, 0); @@ -232,7 +206,7 @@ void ViewProviderFemPostFunction::attach(App::DocumentObject* pcObj) SoSearchAction sa; sa.setInterest(SoSearchAction::FIRST); sa.setSearchingAll(FALSE); - sa.setNode(m_transform); + sa.setNode(transform); sa.apply(pcEditNode); SoPath* path = sa.getPath(); if (path) { diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostFunction.h b/src/Mod/Fem/Gui/ViewProviderFemPostFunction.h index 8987510891..7775e4ff20 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostFunction.h +++ b/src/Mod/Fem/Gui/ViewProviderFemPostFunction.h @@ -140,7 +140,6 @@ protected: SoTransformManip* getManipulator() {return m_manip;} SoSeparator* getGeometryNode() {return m_geometrySeperator;} SoScale* getScaleNode() {return m_scale;} - SoTransform* getTransformNode() {return m_transform;} private: static void dragStartCallback(void * data, SoDragger * d); @@ -150,7 +149,6 @@ private: SoSeparator* m_geometrySeperator; SoTransformManip* m_manip; SoScale* m_scale; - SoTransform* m_transform; bool m_autoscale, m_isDragging, m_autoRecompute; }; diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp index ce952cd086..65969063da 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp @@ -62,6 +62,7 @@ #include "ViewProviderFemPostObject.h" #include "TaskPostBoxes.h" +#include "ViewProviderAnalysis.h" using namespace FemGui; @@ -836,8 +837,8 @@ void ViewProviderFemPostObject::setupTaskDialog(TaskDlgPost* dlg) dlg->appendBox(new TaskPostDisplay(this)); } -void ViewProviderFemPostObject::unsetEdit(int ModNum) { - +void ViewProviderFemPostObject::unsetEdit(int ModNum) +{ if (ModNum == ViewProvider::Default) { // and update the pad //getSketchObject()->getDocument()->recompute(); @@ -903,33 +904,9 @@ void ViewProviderFemPostObject::OnChange(Base::Subject< int >& /*rCaller*/, int bool ViewProviderFemPostObject::onDelete(const std::vector&) { - // warn the user if the object has childs - + // warn the user if the object has unselected children auto objs = claimChildren(); - if (!objs.empty()) - { - // generate dialog - QString bodyMessage; - QTextStream bodyMessageStream(&bodyMessage); - bodyMessageStream << qApp->translate("Std_Delete", - "The pipeline is not empty, therefore the\nfollowing " - "referencing objects might be lost:"); - bodyMessageStream << '\n'; - for (auto ObjIterator : objs) - bodyMessageStream << '\n' << QString::fromUtf8(ObjIterator->Label.getValue()); - bodyMessageStream << "\n\n" << QObject::tr("Are you sure you want to continue?"); - // show and evaluate the dialog - int DialogResult = QMessageBox::warning(Gui::getMainWindow(), - qApp->translate("Std_Delete", "Object dependencies"), bodyMessage, - QMessageBox::Yes, QMessageBox::No); - if (DialogResult == QMessageBox::Yes) - return true; - else - return false; - } - else { - return true; - } + return ViewProviderFemAnalysis::checkSelectedChildren(objs, this->getDocument(), "pipeline"); } bool ViewProviderFemPostObject::canDelete(App::DocumentObject* obj) const diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp index e3d015967d..770f7a4fd4 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemPostPipeline.cpp @@ -133,7 +133,6 @@ void ViewProviderFemPostPipeline::onSelectionChanged(const Gui::SelectionChanges void ViewProviderFemPostPipeline::updateColorBars() { - // take all visible childs and update its shape coloring auto children = claimChildren(); for (auto& child : children) { diff --git a/src/Mod/Fem/Gui/ViewProviderSolver.cpp b/src/Mod/Fem/Gui/ViewProviderSolver.cpp index 3eabd41722..d69125f49a 100644 --- a/src/Mod/Fem/Gui/ViewProviderSolver.cpp +++ b/src/Mod/Fem/Gui/ViewProviderSolver.cpp @@ -32,6 +32,7 @@ #include #include "ViewProviderSolver.h" +#include "ViewProviderAnalysis.h" using namespace FemGui; @@ -44,9 +45,7 @@ ViewProviderSolver::ViewProviderSolver() } ViewProviderSolver::~ViewProviderSolver() -{ - -} +{} std::vector ViewProviderSolver::getDisplayModes() const { @@ -55,32 +54,9 @@ std::vector ViewProviderSolver::getDisplayModes() const bool ViewProviderSolver::onDelete(const std::vector&) { - // warn the user if the object has childs - + // warn the user if the object has unselected children auto objs = claimChildren(); - if (!objs.empty()) - { - // generate dialog - QString bodyMessage; - QTextStream bodyMessageStream(&bodyMessage); - bodyMessageStream << qApp->translate("Std_Delete", - "The solver is not empty, therefore the\nfollowing referencing objects might be lost:"); - bodyMessageStream << '\n'; - for (auto ObjIterator : objs) - bodyMessageStream << '\n' << QString::fromUtf8(ObjIterator->Label.getValue()); - bodyMessageStream << "\n\n" << QObject::tr("Are you sure you want to continue?"); - // show and evaluate the dialog - int DialogResult = QMessageBox::warning(Gui::getMainWindow(), - qApp->translate("Std_Delete", "Object dependencies"), bodyMessage, - QMessageBox::Yes, QMessageBox::No); - if (DialogResult == QMessageBox::Yes) - return true; - else - return false; - } - else { - return true; - } + return ViewProviderFemAnalysis::checkSelectedChildren(objs, this->getDocument(), "solver"); } bool ViewProviderSolver::canDelete(App::DocumentObject* obj) const diff --git a/src/Mod/Fem/ObjectsFem.py b/src/Mod/Fem/ObjectsFem.py index 5f3bfd94d1..91e9378d07 100644 --- a/src/Mod/Fem/ObjectsFem.py +++ b/src/Mod/Fem/ObjectsFem.py @@ -742,8 +742,13 @@ def makePostVtkResult( ): """makePostVtkResult(document, base_result, [name]): creates a FEM post processing result object (vtk based) to hold FEM results""" - obj = doc.addObject("Fem::FemPostPipeline", name) + Pipeline_Name = "Pipeline_" + name + obj = doc.addObject("Fem::FemPostPipeline", Pipeline_Name) obj.load(base_result) + if FreeCAD.GuiUp: + obj.ViewObject.SelectionStyle = "BoundBox" + # to assure the user sees something, set the default to Surface + obj.ViewObject.DisplayMode = "Surface" return obj diff --git a/src/Mod/Fem/feminout/importCcxFrdResults.py b/src/Mod/Fem/feminout/importCcxFrdResults.py index 99e4042f6f..7e6f9238fb 100644 --- a/src/Mod/Fem/feminout/importCcxFrdResults.py +++ b/src/Mod/Fem/feminout/importCcxFrdResults.py @@ -81,11 +81,6 @@ def importFrd( if len(m["Nodes"]) > 0: mesh = importToolsFem.make_femmesh(m) - result_mesh_object = ObjectsFem.makeMeshResult( - doc, - "ResultMesh" - ) - result_mesh_object.FemMesh = mesh res_mesh_is_compacted = False nodenumbers_for_compacted_mesh = [] @@ -107,9 +102,7 @@ def importFrd( .format(result_name_prefix, eigenmode_number) ) elif number_of_increments > 1: - if result_analysis_type == "buckling": - results_name = ( "{}BucklingFactor_{}_Results" .format(result_name_prefix, step_time) @@ -119,7 +112,6 @@ def importFrd( "{}Time_{}_Results" .format(result_name_prefix, step_time) ) - else: results_name = ( "{}Results" @@ -127,6 +119,9 @@ def importFrd( ) res_obj = ObjectsFem.makeResultMechanical(doc, results_name) + # create result mesh + result_mesh_object = ObjectsFem.makeMeshResult(doc, results_name + "_Mesh") + result_mesh_object.FemMesh = mesh res_obj.Mesh = result_mesh_object res_obj = importToolsFem.fill_femresult_mechanical(res_obj, result_set) if analysis: @@ -193,6 +188,31 @@ def importFrd( # fill Stats res_obj = resulttools.fill_femresult_stats(res_obj) + # create a results pipeline if not already existing + pipeline_name = "Pipeline_" + results_name + pipeline_obj = doc.getObject(pipeline_name) + if pipeline_obj is None: + pipeline_obj = ObjectsFem.makePostVtkResult(doc, res_obj, results_name) + pipeline_visibility = True + if analysis: + analysis.addObject(pipeline_obj) + else: + if FreeCAD.GuiUp: + # store pipeline visibility because pipeline_obj.load makes the + # pipeline always visible + pipeline_visibility = pipeline_obj.ViewObject.Visibility + pipeline_obj.load(res_obj) + # update the pipeline + pipeline_obj.recomputeChildren() + pipeline_obj.recompute() + if FreeCAD.GuiUp: + pipeline_obj.ViewObject.updateColorBars() + # make results mesh invisible, will be made visible + # later in task_solver_ccxtools.py + res_obj.Mesh.ViewObject.Visibility = False + # restore pipeline visibility + pipeline_obj.ViewObject.Visibility = pipeline_visibility + else: error_message = ( "Nodes, but no results found in frd file. " diff --git a/src/Mod/Fem/femtaskpanels/task_result_mechanical.py b/src/Mod/Fem/femtaskpanels/task_result_mechanical.py index 9b92c9891e..799ec748c2 100644 --- a/src/Mod/Fem/femtaskpanels/task_result_mechanical.py +++ b/src/Mod/Fem/femtaskpanels/task_result_mechanical.py @@ -65,11 +65,6 @@ class _TaskPanel: # if Mesh and result are in active analysis # activate the result mesh object self.mesh_obj.ViewObject.show() - # hide pipeline if any - CCX_pipeline = FreeCADGui.ActiveDocument.getObject("SolverCCXResult") - if CCX_pipeline is not None: - self.pipeline_visibility = CCX_pipeline.Visibility - CCX_pipeline.hide() ui_path = FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/" self.result_widget = FreeCADGui.PySideUic.loadUi(ui_path + "ResultShow.ui") @@ -195,12 +190,6 @@ class _TaskPanel: self.result_widget.sb_displacement_factor_max.setValue(10. * scale_factor) self.result_widget.sb_displacement_factor.setValue(scale_factor) - def __del__(self): - # restore visibility - CCX_pipeline = FreeCADGui.ActiveDocument.getObject("SolverCCXResult") - if self.pipeline_visibility and CCX_pipeline is not None: - CCX_pipeline.Visibility = self.pipeline_visibility - def restore_result_dialog(self): try: rt = FreeCAD.FEM_dialog["results_type"] diff --git a/src/Mod/Fem/femtaskpanels/task_solver_ccxtools.py b/src/Mod/Fem/femtaskpanels/task_solver_ccxtools.py index 5e749aa98f..6a25f7b2d0 100644 --- a/src/Mod/Fem/femtaskpanels/task_solver_ccxtools.py +++ b/src/Mod/Fem/femtaskpanels/task_solver_ccxtools.py @@ -78,7 +78,7 @@ class _TaskPanel: self.CCX_mesh_visibility = False # store visibility of possibly existing mesh object - CCX_mesh = self.fea.analysis.Document.getObject("ResultMesh") + CCX_mesh = self.fea.analysis.Document.getObject("CCX_Results_Mesh") if CCX_mesh is not None: self.CCX_mesh_visibility = CCX_mesh.ViewObject.Visibility @@ -249,8 +249,6 @@ class _TaskPanel: # print("calculixFinished(), exit code: {}".format(exitCode)) FreeCAD.Console.PrintLog("calculix state: {}\n".format(self.Calculix.state())) - had_errors = False - # Restore previous cwd QtCore.QDir.setCurrent(self.cwd) @@ -260,7 +258,6 @@ class _TaskPanel: self.calculixNoError() else: self.calculixError() - had_errors = True self.form.pb_run_ccx.setText("Re-run CalculiX") self.femConsoleMessage("Loading result sets...") @@ -290,47 +287,15 @@ class _TaskPanel: self.fea.load_results() except Exception: FreeCAD.Console.PrintError("loading results failed\n") - had_errors = True QApplication.restoreOverrideCursor() self.form.l_time.setText("Time: {0:4.1f}: ".format(time.time() - self.Start)) - # create a results pipeline from the just created results object - if not had_errors: - CCX_results = self.fea.analysis.Document.getObject("CCX_Results") - # safe guard - if CCX_results is None: - return - # check if there is already a pipeline - self.CCX_pipeline = self.fea.analysis.Document.getObject("SolverCCXResult") - if self.CCX_pipeline is None: - try: - self._createResults() - except Exception: - FreeCAD.Console.PrintError("Results pipeline could not be created\n") - had_errors = True - self.CCX_pipeline.load(CCX_results) - self.CCX_pipeline.recomputeChildren() - self.fea.analysis.Document.recompute() - # recompute() updated the result mesh data - # but not the shape and bar coloring - self.CCX_pipeline.ViewObject.updateColorBars() - # restore mesh object visibility - CCX_mesh = self.fea.analysis.Document.getObject("ResultMesh") - if CCX_mesh is not None: - CCX_mesh.ViewObject.Visibility = self.CCX_mesh_visibility - else: - FreeCAD.Console.PrintError("\nNo result pipeline was created.\n") - - def _createResults(self): - self.CCX_pipeline = self.fea.analysis.Document.addObject( - "Fem::FemPostPipeline", "SolverCCXResult") - self.CCX_pipeline.Label = "SolverCCXResult" - self.CCX_pipeline.ViewObject.SelectionStyle = "BoundBox" - self.fea.analysis.addObject(self.CCX_pipeline) - # to assure the user sees something, set the default to Surface - self.CCX_pipeline.ViewObject.DisplayMode = "Surface" - + # restore mesh object visibility + CCX_mesh = self.fea.analysis.Document.getObject("ResultMesh") + if CCX_mesh is not None: + CCX_mesh.ViewObject.Visibility = self.CCX_mesh_visibility + def choose_working_dir(self): wd = QtGui.QFileDialog.getExistingDirectory(None, "Choose CalculiX working directory", self.fea.working_dir) diff --git a/src/Mod/Fem/femtest/app/test_object.py b/src/Mod/Fem/femtest/app/test_object.py index 87011ac19a..a0123a499a 100644 --- a/src/Mod/Fem/femtest/app/test_object.py +++ b/src/Mod/Fem/femtest/app/test_object.py @@ -86,7 +86,7 @@ class TestObjectCreate(unittest.TestCase): # thus they should not be counted # solver children: equations --> 8 # gmsh mesh children: group, region, boundary layer --> 3 - # resule children: mesh result --> 1 + # result children: mesh result --> 1 # post pipeline children: region, scalar, cut, wrap --> 5 # analysis itself is not in analysis group --> 1 # thus: -18 diff --git a/src/Mod/Path/PathTests/boxtest.fcstd b/src/Mod/Path/PathTests/boxtest.fcstd index 185ca0bea1..e0b39cbc5a 100644 Binary files a/src/Mod/Path/PathTests/boxtest.fcstd and b/src/Mod/Path/PathTests/boxtest.fcstd differ diff --git a/src/Mod/Path/PathTests/boxtest1.fcstd b/src/Mod/Path/PathTests/boxtest1.fcstd index 3fabd30289..d150419bef 100644 Binary files a/src/Mod/Path/PathTests/boxtest1.fcstd and b/src/Mod/Path/PathTests/boxtest1.fcstd differ diff --git a/src/Mod/Path/PathTests/drill_test1.FCStd b/src/Mod/Path/PathTests/drill_test1.FCStd index 382a4fa2cf..7a82630b52 100644 Binary files a/src/Mod/Path/PathTests/drill_test1.FCStd and b/src/Mod/Path/PathTests/drill_test1.FCStd differ diff --git a/src/Mod/Path/PathTests/test_adaptive.fcstd b/src/Mod/Path/PathTests/test_adaptive.fcstd index 7af4b06f81..f12d004b0b 100644 Binary files a/src/Mod/Path/PathTests/test_adaptive.fcstd and b/src/Mod/Path/PathTests/test_adaptive.fcstd differ diff --git a/src/Mod/Path/Tools/Shape/chamfer.fcstd b/src/Mod/Path/Tools/Shape/chamfer.fcstd index 23d60b34a3..27b346c4cf 100644 Binary files a/src/Mod/Path/Tools/Shape/chamfer.fcstd and b/src/Mod/Path/Tools/Shape/chamfer.fcstd differ diff --git a/src/Mod/Path/Tools/Shape/dovetail.fcstd b/src/Mod/Path/Tools/Shape/dovetail.fcstd index a94300cedf..7f8e8d808f 100644 Binary files a/src/Mod/Path/Tools/Shape/dovetail.fcstd and b/src/Mod/Path/Tools/Shape/dovetail.fcstd differ diff --git a/src/Mod/Path/Tools/Shape/probe.fcstd b/src/Mod/Path/Tools/Shape/probe.fcstd index b58bb0a33b..b070e744f1 100644 Binary files a/src/Mod/Path/Tools/Shape/probe.fcstd and b/src/Mod/Path/Tools/Shape/probe.fcstd differ diff --git a/src/Mod/Path/Tools/Shape/slittingsaw.fcstd b/src/Mod/Path/Tools/Shape/slittingsaw.fcstd index aecf93d874..7b8cf8b2a2 100644 Binary files a/src/Mod/Path/Tools/Shape/slittingsaw.fcstd and b/src/Mod/Path/Tools/Shape/slittingsaw.fcstd differ diff --git a/src/Mod/TechDraw/App/DimensionFormatter.cpp b/src/Mod/TechDraw/App/DimensionFormatter.cpp index 2caea690b5..0291f7ca33 100644 --- a/src/Mod/TechDraw/App/DimensionFormatter.cpp +++ b/src/Mod/TechDraw/App/DimensionFormatter.cpp @@ -22,6 +22,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include #endif @@ -320,12 +321,26 @@ QString DimensionFormatter::formatValueToSpec(double value, QString formatSpecif formattedValue.replace(QRegularExpression(QStringLiteral("([0-9][0-9]*\\.[0-9]*[1-9])00*$")), QStringLiteral("\\1")); formattedValue.replace(QRegularExpression(QStringLiteral("([0-9][0-9]*)\\.0*$")), QStringLiteral("\\1")); } else { - formattedValue = QString::asprintf(Base::Tools::toStdString(formatSpecifier).c_str(), value); + if (isNumericFormat(formatSpecifier)) { + formattedValue = QString::asprintf(Base::Tools::toStdString(formatSpecifier).c_str(), value); + } } return formattedValue; } +bool DimensionFormatter::isNumericFormat(QString formatSpecifier) +{ + QRegularExpression rxFormat(QStringLiteral("%[+-]?[0-9]*\\.*[0-9]*[aefgwAEFGW]")); //printf double format spec + QRegularExpressionMatch rxMatch; + int pos = formatSpecifier.indexOf(rxFormat, 0, &rxMatch); + if (pos != -1) { + return true; + } + return false; +} + +//TODO: similiar code here and above QStringList DimensionFormatter::getPrefixSuffixSpec(QString fSpec) { QStringList result; diff --git a/src/Mod/TechDraw/App/DimensionFormatter.h b/src/Mod/TechDraw/App/DimensionFormatter.h index e1d26f6e75..30c8c8b792 100644 --- a/src/Mod/TechDraw/App/DimensionFormatter.h +++ b/src/Mod/TechDraw/App/DimensionFormatter.h @@ -49,6 +49,7 @@ public: std::string getDefaultFormatSpec(bool isToleranceFormat) const; bool isTooSmall(double value, QString formatSpec); QString formatValueToSpec(double value, QString formatSpecifier); + bool isNumericFormat(QString formatSpecifier); private: DrawViewDimension* m_dimension; diff --git a/src/Mod/TechDraw/App/DrawComplexSection.cpp b/src/Mod/TechDraw/App/DrawComplexSection.cpp index db60ad0119..3dab553f1e 100644 --- a/src/Mod/TechDraw/App/DrawComplexSection.cpp +++ b/src/Mod/TechDraw/App/DrawComplexSection.cpp @@ -282,7 +282,7 @@ TopoDS_Shape DrawComplexSection::prepareShape(const TopoDS_Shape& cutShape, doub } -void DrawComplexSection::makeSectionCut(TopoDS_Shape& baseShape) +void DrawComplexSection::makeSectionCut(const TopoDS_Shape& baseShape) { // Base::Console().Message("DCS::makeSectionCut() - %s - baseShape.IsNull: %d\n", // getNameInDocument(), baseShape.IsNull()); @@ -295,7 +295,11 @@ void DrawComplexSection::makeSectionCut(TopoDS_Shape& baseShape) connectAlignWatcher = QObject::connect(&m_alignWatcher, &QFutureWatcherBase::finished, &m_alignWatcher, [this] { this->onSectionCutFinished(); }); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) m_alignFuture = QtConcurrent::run(this, &DrawComplexSection::makeAlignedPieces, baseShape); +#else + m_alignFuture = QtConcurrent::run(&DrawComplexSection::makeAlignedPieces, this, baseShape); +#endif m_alignWatcher.setFuture(m_alignFuture); waitingForAlign(true); } diff --git a/src/Mod/TechDraw/App/DrawComplexSection.h b/src/Mod/TechDraw/App/DrawComplexSection.h index d06e730c83..f5fc22624c 100644 --- a/src/Mod/TechDraw/App/DrawComplexSection.h +++ b/src/Mod/TechDraw/App/DrawComplexSection.h @@ -58,7 +58,7 @@ public: TopoDS_Compound alignSectionFaces(TopoDS_Shape faceIntersections) override; std::pair sectionLineEnds() override; - void makeSectionCut(TopoDS_Shape& baseShape) override; + void makeSectionCut(const TopoDS_Shape& baseShape) override; void waitingForAlign(bool s) { m_waitingForAlign = s; } bool waitingForAlign(void) const { return m_waitingForAlign; } diff --git a/src/Mod/TechDraw/App/DrawViewDetail.cpp b/src/Mod/TechDraw/App/DrawViewDetail.cpp index 20f42ee81e..fbcb8ba955 100644 --- a/src/Mod/TechDraw/App/DrawViewDetail.cpp +++ b/src/Mod/TechDraw/App/DrawViewDetail.cpp @@ -186,7 +186,11 @@ void DrawViewDetail::detailExec(TopoDS_Shape& shape, DrawViewPart* dvp, DrawView connectDetailWatcher = QObject::connect(&m_detailWatcher, &QFutureWatcherBase::finished, &m_detailWatcher, [this] { this->onMakeDetailFinished(); }); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) m_detailFuture = QtConcurrent::run(this, &DrawViewDetail::makeDetailShape, shape, dvp, dvs); +#else + m_detailFuture = QtConcurrent::run(&DrawViewDetail::makeDetailShape, this, shape, dvp, dvs); +#endif m_detailWatcher.setFuture(m_detailFuture); waitingForDetail(true); } @@ -194,7 +198,7 @@ void DrawViewDetail::detailExec(TopoDS_Shape& shape, DrawViewPart* dvp, DrawView //this runs in a separate thread since it can sometimes take a long time //make a common of the input shape and a cylinder (or prism depending on //the matting style) -void DrawViewDetail::makeDetailShape(TopoDS_Shape& shape, DrawViewPart* dvp, DrawViewSection* dvs) +void DrawViewDetail::makeDetailShape(const TopoDS_Shape& shape, DrawViewPart* dvp, DrawViewSection* dvs) { showProgressMessage(getNameInDocument(), "is making detail shape"); diff --git a/src/Mod/TechDraw/App/DrawViewDetail.h b/src/Mod/TechDraw/App/DrawViewDetail.h index 8873ad0af7..9fa099834b 100644 --- a/src/Mod/TechDraw/App/DrawViewDetail.h +++ b/src/Mod/TechDraw/App/DrawViewDetail.h @@ -73,7 +73,7 @@ public: void detailExec(TopoDS_Shape& s, DrawViewPart* baseView, DrawViewSection* sectionAlias); - void makeDetailShape(TopoDS_Shape& shape, + void makeDetailShape(const TopoDS_Shape& shape, DrawViewPart* dvp, DrawViewSection* dvs); void postHlrTasks(void) override; diff --git a/src/Mod/TechDraw/App/DrawViewPart.cpp b/src/Mod/TechDraw/App/DrawViewPart.cpp index 92090d5944..daf79c2beb 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.cpp +++ b/src/Mod/TechDraw/App/DrawViewPart.cpp @@ -390,7 +390,11 @@ TechDraw::GeometryObjectPtr DrawViewPart::buildGeometryObject(TopoDS_Shape& shap //https://github.com/KDE/clazy/blob/1.11/docs/checks/README-connect-3arg-lambda.md connectHlrWatcher = QObject::connect(&m_hlrWatcher, &QFutureWatcherBase::finished, &m_hlrWatcher, [this] { this->onHlrFinished(); }); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) m_hlrFuture = QtConcurrent::run(go.get(), &GeometryObject::projectShape, shape, viewAxis); +#else + m_hlrFuture = QtConcurrent::run(&GeometryObject::projectShape, go.get(), shape, viewAxis); +#endif m_hlrWatcher.setFuture(m_hlrFuture); waitingForHlr(true); } @@ -430,7 +434,11 @@ void DrawViewPart::onHlrFinished(void) connectFaceWatcher = QObject::connect(&m_faceWatcher, &QFutureWatcherBase::finished, &m_faceWatcher, [this] { this->onFacesFinished(); }); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) m_faceFuture = QtConcurrent::run(this, &DrawViewPart::extractFaces); +#else + m_faceFuture = QtConcurrent::run(&DrawViewPart::extractFaces, this); +#endif m_faceWatcher.setFuture(m_faceFuture); waitingForFaces(true); } diff --git a/src/Mod/TechDraw/App/DrawViewSection.cpp b/src/Mod/TechDraw/App/DrawViewSection.cpp index 27641c08ff..b8cbd47cca 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.cpp +++ b/src/Mod/TechDraw/App/DrawViewSection.cpp @@ -380,7 +380,11 @@ void DrawViewSection::sectionExec(TopoDS_Shape& baseShape) connectCutWatcher = QObject::connect(&m_cutWatcher, &QFutureWatcherBase::finished, &m_cutWatcher, [this] { this->onSectionCutFinished(); }); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) m_cutFuture = QtConcurrent::run(this, &DrawViewSection::makeSectionCut, baseShape); +#else + m_cutFuture = QtConcurrent::run(&DrawViewSection::makeSectionCut, this, baseShape); +#endif m_cutWatcher.setFuture(m_cutFuture); waitingForCut(true); } @@ -390,7 +394,7 @@ void DrawViewSection::sectionExec(TopoDS_Shape& baseShape) } } -void DrawViewSection::makeSectionCut(TopoDS_Shape& baseShape) +void DrawViewSection::makeSectionCut(const TopoDS_Shape& baseShape) { // Base::Console().Message("DVS::makeSectionCut() - %s - baseShape.IsNull: %d\n", // getNameInDocument(), baseShape.IsNull()); diff --git a/src/Mod/TechDraw/App/DrawViewSection.h b/src/Mod/TechDraw/App/DrawViewSection.h index f37313108f..d709b8f661 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.h +++ b/src/Mod/TechDraw/App/DrawViewSection.h @@ -116,7 +116,7 @@ public: short mustExecute() const override; void sectionExec(TopoDS_Shape& s); - virtual void makeSectionCut(TopoDS_Shape& baseShape); + virtual void makeSectionCut(const TopoDS_Shape& baseShape); void postHlrTasks(void) override; virtual void postSectionCutTasks(); void waitingForCut(bool s) { m_waitingForCut = s; } diff --git a/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp b/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp index 0248083f2a..e624d3df93 100644 --- a/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp +++ b/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp @@ -84,14 +84,13 @@ void loadTechDrawResource() // add fonts std::string fontDir = App::Application::getResourceDir() + "Mod/TechDraw/Resources/fonts/"; - QFontDatabase fontDB; std::vector fontsAll( {"osifont-lgpl3fe.ttf", "osifont-italic.ttf", "Y14.5-2018.ttf", "Y14.5-FreeCAD.ttf"}); for (auto& font : fontsAll) { QString fontFile = Base::Tools::fromStdString(fontDir + font); - int rc = fontDB.addApplicationFont(fontFile); + int rc = QFontDatabase::addApplicationFont(fontFile); if (rc < 0) { Base::Console().Warning( "TechDraw failed to load font file: %d from: %s\n", rc, qPrintable(fontFile)); diff --git a/src/Mod/TechDraw/Gui/QGIMatting.cpp b/src/Mod/TechDraw/Gui/QGIMatting.cpp index dc5c1994bd..e5a3e06d9f 100644 --- a/src/Mod/TechDraw/Gui/QGIMatting.cpp +++ b/src/Mod/TechDraw/Gui/QGIMatting.cpp @@ -41,7 +41,8 @@ using namespace TechDrawGui; QGIMatting::QGIMatting() : - m_radius(5.0) + m_radius(5.0), + m_fudge(1.01) // same as m_fudge in DrawViewDetail { setCacheMode(QGraphicsItem::NoCache); @@ -58,25 +59,48 @@ QGIMatting::QGIMatting() : m_border->setPen(m_pen); m_border->setBrush(m_brush); + m_mat = new QGraphicsPathItem(); + addToGroup(m_mat); + m_matPen.setColor(Qt::white); + m_matPen.setStyle(Qt::SolidLine); + m_matBrush.setStyle(Qt::SolidPattern); + m_matBrush.setColor(Qt::white); + m_mat->setPen(m_matPen); + m_mat->setBrush(m_matBrush); + setZValue(ZVALUE::MATTING); } void QGIMatting::draw() { prepareGeometryChange(); + double penWidth = Rez::guiX(TechDraw::LineGroup::getDefaultWidth("Graphic")); + double penWidth_2 = penWidth / 2.0; + m_pen.setWidthF(penWidth); + double matSize = m_radius * m_fudge + 2 * penWidth; // outer bound of mat + m_matPen.setWidthF(2.0 * penWidth); QPainterPath ppCut; + QPainterPath ppMat; if (getHoleStyle() == 0) { QRectF roundCutout (-m_radius, -m_radius, 2.0 * m_radius, 2.0 * m_radius); ppCut.addEllipse(roundCutout); + QRectF roundMat(-matSize, -matSize, 2.0 * matSize, 2.0 * matSize); + ppMat.addEllipse(roundMat); + ppMat.addEllipse(roundCutout.adjusted(-penWidth_2, -penWidth_2, penWidth_2, penWidth_2)); } else { double squareSize = m_radius; QRectF squareCutout (-squareSize, -squareSize, 2.0 * squareSize, 2.0 * squareSize); ppCut.addRect(squareCutout); + QRectF squareMat(-matSize, -matSize, 2.0 * matSize, 2.0 * matSize); + ppMat.addRect(squareMat); + ppMat.addRect(squareCutout.adjusted(-penWidth_2, -penWidth_2, penWidth_2, penWidth_2)); } - m_pen.setWidthF(Rez::guiX(TechDraw::LineGroup::getDefaultWidth("Graphic"))); m_border->setPen(m_pen); m_border->setPath(ppCut); m_border->setZValue(ZVALUE::MATTING); + m_mat->setPen(m_matPen); + m_mat->setPath(ppMat); + m_mat->setZValue(ZVALUE::MATTING - 1.0); } int QGIMatting::getHoleStyle() diff --git a/src/Mod/TechDraw/Gui/QGIMatting.h b/src/Mod/TechDraw/Gui/QGIMatting.h index 2fb1acb80a..5b3df6baa0 100644 --- a/src/Mod/TechDraw/Gui/QGIMatting.h +++ b/src/Mod/TechDraw/Gui/QGIMatting.h @@ -62,13 +62,17 @@ protected: double m_height; double m_width; double m_radius; + double m_fudge; int getHoleStyle(); QGraphicsPathItem* m_border; + QGraphicsPathItem* m_mat; private: QPen m_pen; QBrush m_brush; + QPen m_matPen; + QBrush m_matBrush; }; diff --git a/src/Mod/TechDraw/Gui/QGIView.cpp b/src/Mod/TechDraw/Gui/QGIView.cpp index c0398536f1..f8de2bcd14 100644 --- a/src/Mod/TechDraw/Gui/QGIView.cpp +++ b/src/Mod/TechDraw/Gui/QGIView.cpp @@ -545,21 +545,23 @@ QRectF QGIView::customChildrenBoundingRect() const int editablePathItemType = QGraphicsItem::UserType + 301; // TODO: Magic number warning int movableTextItemType = QGraphicsItem::UserType + 300; int weldingSymbolItemType = QGraphicsItem::UserType + 340; + int centerMarkItemType = QGraphicsItem::UserType + 171; QRectF result; - for (QList::iterator it = children.begin(); it != children.end(); ++it) { - if (!(*it)->isVisible()) { + for (auto& child : children) { + if (!child->isVisible()) { continue; } - if ( ((*it)->type() != dimItemType) && - ((*it)->type() != leaderItemType) && - ((*it)->type() != textLeaderItemType) && - ((*it)->type() != editablePathItemType) && - ((*it)->type() != movableTextItemType) && - ((*it)->type() != borderItemType) && - ((*it)->type() != labelItemType) && - ((*it)->type() != weldingSymbolItemType) && - ((*it)->type() != captionItemType) ) { - QRectF childRect = mapFromItem(*it, (*it)->boundingRect()).boundingRect(); + if ( (child->type() != dimItemType) && + (child->type() != leaderItemType) && + (child->type() != textLeaderItemType) && + (child->type() != editablePathItemType) && + (child->type() != movableTextItemType) && + (child->type() != borderItemType) && + (child->type() != labelItemType) && + (child->type() != weldingSymbolItemType) && + (child->type() != captionItemType) && + (child->type() != centerMarkItemType)) { + QRectF childRect = mapFromItem(child, child->boundingRect()).boundingRect(); result = result.united(childRect); //result = result.united((*it)->boundingRect()); } diff --git a/src/Mod/TechDraw/Gui/QGSPage.cpp b/src/Mod/TechDraw/Gui/QGSPage.cpp index a902f1b617..323f9e2bef 100644 --- a/src/Mod/TechDraw/Gui/QGSPage.cpp +++ b/src/Mod/TechDraw/Gui/QGSPage.cpp @@ -1259,7 +1259,9 @@ void QGSPage::postProcessXml(QTemporaryFile& temporaryFile, QString fileName, QS QTextStream stream(&outFile); stream.setGenerateByteOrderMark(false); +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) stream.setCodec("UTF-8"); +#endif stream << exportDoc.toByteArray(); outFile.close(); diff --git a/src/Mod/TechDraw/Gui/QGVPage.cpp b/src/Mod/TechDraw/Gui/QGVPage.cpp index fff8d2986f..91fbab93e5 100644 --- a/src/Mod/TechDraw/Gui/QGVPage.cpp +++ b/src/Mod/TechDraw/Gui/QGVPage.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -357,7 +356,6 @@ void QGVPage::setRenderer(RendererType type) if (m_renderer == OpenGL) { #ifndef QT_NO_OPENGL - // setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); //QGLWidget is obsolete setViewport(new QOpenGLWidget); setViewportUpdateMode(QGraphicsView::SmartViewportUpdate); #endif @@ -466,7 +464,11 @@ void QGVPage::kbPanScroll(int xMove, int yMove) } } +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) void QGVPage::enterEvent(QEvent* event) +#else +void QGVPage::enterEvent(QEnterEvent* event) +#endif { QGraphicsView::enterEvent(event); m_navStyle->handleEnterEvent(event); diff --git a/src/Mod/TechDraw/Gui/QGVPage.h b/src/Mod/TechDraw/Gui/QGVPage.h index 8dcf2a2533..780d845821 100644 --- a/src/Mod/TechDraw/Gui/QGVPage.h +++ b/src/Mod/TechDraw/Gui/QGVPage.h @@ -130,7 +130,11 @@ public Q_SLOTS: protected: void wheelEvent(QWheelEvent* event) override; void paintEvent(QPaintEvent* event) override; +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) void enterEvent(QEvent* event) override; +#else + void enterEvent(QEnterEvent* event) override; +#endif void leaveEvent(QEvent* event) override; void mousePressEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; diff --git a/src/Mod/TechDraw/Gui/mrichtextedit.cpp b/src/Mod/TechDraw/Gui/mrichtextedit.cpp index 6e2cbb06d0..b52a3b4f74 100644 --- a/src/Mod/TechDraw/Gui/mrichtextedit.cpp +++ b/src/Mod/TechDraw/Gui/mrichtextedit.cpp @@ -201,8 +201,7 @@ MRichTextEdit::MRichTextEdit(QWidget *parent, QString textIn) : QWidget(parent) // font size - QFontDatabase db; - const auto sizes = db.standardSizes(); + const auto sizes = QFontDatabase::standardSizes(); for(int size: sizes) { f_fontsize->addItem(QString::number(size)); } @@ -430,7 +429,11 @@ void MRichTextEdit::textStyle(int index) { } if (index == ParagraphMonospace) { fmt = cursor.charFormat(); +#if QT_VERSION < QT_VERSION_CHECK(5,13,0) fmt.setFontFamily(QString::fromUtf8("Monospace")); +#else + fmt.setFontFamilies(QStringList() << QString::fromUtf8("Monospace")); +#endif fmt.setFontStyleHint(QFont::Monospace); fmt.setFontFixedPitch(true); } diff --git a/src/Mod/TechDraw/TDTest/DrawViewDimensionTest.py b/src/Mod/TechDraw/TDTest/DrawViewDimensionTest.py index bba244cea4..4dab44f35b 100644 --- a/src/Mod/TechDraw/TDTest/DrawViewDimensionTest.py +++ b/src/Mod/TechDraw/TDTest/DrawViewDimensionTest.py @@ -1,68 +1,76 @@ import FreeCAD import unittest from .TechDrawTestUtilities import createPageWithSVGTemplate - +from PySide import QtCore class DrawViewDimensionTest(unittest.TestCase): def setUp(self): """Creates a page and 2 views""" - FreeCAD.newDocument("TDDim") - FreeCAD.setActiveDocument("TDDim") - FreeCAD.ActiveDocument = FreeCAD.getDocument("TDDim") + print("DVDTest.setUp()") + FreeCAD.newDocument("TDDimTest") + FreeCAD.setActiveDocument("TDDimTest") + FreeCAD.ActiveDocument = FreeCAD.getDocument("TDDimTest") + self.document = FreeCAD.ActiveDocument # make source feature - FreeCAD.ActiveDocument.addObject("Part::Box", "Box") - FreeCAD.ActiveDocument.addObject("Part::Sphere", "Sphere") + self.document.addObject("Part::Box", "Box") + self.document.addObject("Part::Sphere", "Sphere") # make a page - self.page = createPageWithSVGTemplate() + self.page = createPageWithSVGTemplate(self.document) self.page.Scale = 5.0 - # page.ViewObject.show() # unit tests run in console mode # make Views - self.view1 = FreeCAD.ActiveDocument.addObject("TechDraw::DrawViewPart", "View") - FreeCAD.ActiveDocument.View.Source = [FreeCAD.ActiveDocument.Box] + self.view = self.document.addObject("TechDraw::DrawViewPart", "View") + self.page.addView(self.view) + self.view.Source = [self.document.Box] + self.view.X = 30 + self.view.Y = 150 + + self.view1 = self.document.addObject("TechDraw::DrawViewPart", "View001") self.page.addView(self.view1) - self.view1.X = 30 + self.view1.Source = [self.document.Sphere] + self.view1.X = 220 self.view1.Y = 150 - self.view2 = FreeCAD.activeDocument().addObject( - "TechDraw::DrawViewPart", "View001" - ) - FreeCAD.activeDocument().View001.Source = [FreeCAD.activeDocument().Sphere] - self.page.addView(self.view2) - self.view2.X = 220 - self.view2.Y = 150 - FreeCAD.ActiveDocument.recompute() + + self.document.recompute() + + #wait for threads to complete before checking result + loop = QtCore.QEventLoop() + + timer = QtCore.QTimer() + timer.setSingleShot(True) + timer.timeout.connect(loop.quit) + + timer.start(5000) #5 second delay + loop.exec_() def tearDown(self): - FreeCAD.closeDocument("TDDim") + print("DVDTest.tearDown()") + FreeCAD.closeDocument("TDDimTest") def testLengthDimension(self): - """Tests if a length dimension can be added to view1""" + """Tests if a length dimension can be added to view""" # make length dimension print("making length dimension") - dimension = FreeCAD.ActiveDocument.addObject( - "TechDraw::DrawViewDimension", "Dimension" - ) - dimension.Type = "Distance" - dimension.References2D = [(self.view1, "Edge1")] - print("adding dim1 to page") + + dimension = self.document.addObject("TechDraw::DrawViewDimension", "Dimension") self.page.addView(dimension) + dimension.Type = "Distance" + dimension.References2D = [(self.view, "Edge1")] print("finished length dimension") - FreeCAD.ActiveDocument.recompute() + self.document.recompute() self.assertTrue("Up-to-date" in dimension.State) def testRadiusDimension(self): - """Tests if a radius dimension can be added to view2""" + """Tests if a radius dimension can be added to view1""" print("making radius dimension") - dimension = FreeCAD.ActiveDocument.addObject( - "TechDraw::DrawViewDimension", "Dimension001" - ) + dimension = self.document.addObject("TechDraw::DrawViewDimension", "Dimension001") + self.page.addView(dimension) dimension.Type = "Radius" dimension.MeasureType = "Projected" - dimension.References2D = [(self.view2, "Edge0")] - self.page.addView(dimension) - FreeCAD.ActiveDocument.recompute() + dimension.References2D = [(self.view1, "Edge0")] + self.document.recompute() self.assertTrue("Up-to-date" in dimension.State) diff --git a/src/Mod/TechDraw/TDTest/TechDrawTestUtilities.py b/src/Mod/TechDraw/TDTest/TechDrawTestUtilities.py index ec9ba48f26..b65a634645 100644 --- a/src/Mod/TechDraw/TDTest/TechDrawTestUtilities.py +++ b/src/Mod/TechDraw/TDTest/TechDrawTestUtilities.py @@ -2,13 +2,16 @@ import FreeCAD import os -def createPageWithSVGTemplate(): +def createPageWithSVGTemplate(doc=None): """Returns a page with an SVGTemplate added on the ActiveDocument""" path = os.path.dirname(os.path.abspath(__file__)) templateFileSpec = path + "/TestTemplate.svg" + + if not doc: + doc = FreeCAD.ActiveDocument - page = FreeCAD.ActiveDocument.addObject("TechDraw::DrawPage", "Page") - FreeCAD.ActiveDocument.addObject("TechDraw::DrawSVGTemplate", "Template") - FreeCAD.ActiveDocument.Template.Template = templateFileSpec - FreeCAD.ActiveDocument.Page.Template = FreeCAD.ActiveDocument.Template + page = doc.addObject("TechDraw::DrawPage", "Page") + doc.addObject("TechDraw::DrawSVGTemplate", "Template") + doc.Template.Template = templateFileSpec + doc.Page.Template = doc.Template return page diff --git a/src/Mod/TechDraw/TestTechDrawApp.py b/src/Mod/TechDraw/TestTechDrawApp.py index da99918af1..c547488327 100644 --- a/src/Mod/TechDraw/TestTechDrawApp.py +++ b/src/Mod/TechDraw/TestTechDrawApp.py @@ -24,7 +24,6 @@ from TDTest.DrawHatchTest import DrawHatchTest # noqa: F401 from TDTest.DrawViewAnnotationTest import DrawViewAnnotationTest # noqa: F401 from TDTest.DrawViewBalloonTest import DrawViewBalloonTest # noqa: F401 -from TDTest.DrawViewDimensionTest import DrawViewDimensionTest # noqa: F401 from TDTest.DrawViewImageTest import DrawViewImageTest # noqa: F401 from TDTest.DrawViewSymbolTest import DrawViewSymbolTest # noqa: F401 from TDTest.DrawProjectionGroupTest import DrawProjectionGroupTest # noqa: F401 diff --git a/src/Mod/TechDraw/TestTechDrawGui.py b/src/Mod/TechDraw/TestTechDrawGui.py index 46e729f91d..3c9d18d041 100644 --- a/src/Mod/TechDraw/TestTechDrawGui.py +++ b/src/Mod/TechDraw/TestTechDrawGui.py @@ -25,3 +25,5 @@ from TDTest.DrawViewSectionTest import DrawViewSectionTest # noqa: F401 from TDTest.DrawViewPartTest import DrawViewPartTest # noqa: F401 from TDTest.DrawViewDetailTest import DrawViewDetailTest # noqa: F401 +from TDTest.DrawViewDimensionTest import DrawViewDimensionTest # noqa: F401 + diff --git a/src/Tools/ImageTools/ImageConv/CmdLine.cpp b/src/Tools/ImageTools/ImageConv/CmdLine.cpp deleted file mode 100644 index 009d45e960..0000000000 --- a/src/Tools/ImageTools/ImageConv/CmdLine.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/*------------------------------------------------------ - CCmdLine - - A utility for parsing command lines. - - Copyright (C) 1999 Chris Losinger, Smaller Animals Software. - http://www.smalleranimals.com - - This software is provided 'as-is', without any express - or implied warranty. In no event will the authors be - held liable for any damages arising from the use of this software. - - Permission is granted to anyone to use this software - for any purpose, including commercial applications, and - to alter it and redistribute it freely, subject to the - following restrictions: - - 1. The origin of this software must not be misrepresented; - you must not claim that you wrote the original software. - If you use this software in a product, an acknowledgment - in the product documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, - and must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - See SACmds.h for more info. -------------------------------------------------------*/ - -// if you're using MFC, you'll need to un-comment this line -// #include "stdafx.h" - -#include "CmdLine.h" -#ifdef Q_WS_WIN -# include "crtdbg.h" -#endif - -/*------------------------------------------------------ - int CCmdLine::SplitLine(int argc, char **argv) - - parse the command line into switches and arguments - - returns number of switches found -------------------------------------------------------*/ -int CCmdLine::SplitLine(int argc, char **argv) -{ - clear(); - - StringType curParam; // current argv[x] - - // skip the exe name (start with i = 1) - for (int i = 1; i < argc; i++) - { - // if it's a switch, start a new CCmdLine - if (IsSwitch(argv[i])) - { - curParam = argv[i]; - - StringType arg; - - // look at next input string to see if it's a switch or an argument - if (i + 1 < argc) - { - if (!IsSwitch(argv[i + 1])) - { - // it's an argument, not a switch - arg = argv[i + 1]; - - // skip to next - i++; - } - else - { - arg = ""; - } - } - - // add it - CCmdParam cmd; - - // only add non-empty args - if (arg != "") - { - cmd.m_strings.push_back(arg); - } - - // add the CCmdParam to 'this' - pair res = insert(CCmdLine::value_type(curParam, cmd)); - - } - else - { - // it's not a new switch, so it must be more stuff for the last switch - - // ...let's add it - CCmdLine::iterator theIterator; - - // get an iterator for the current param - theIterator = find(curParam); - if (theIterator!=end()) - { - (*theIterator).second.m_strings.push_back(argv[i]); - } - else - { - // ?? - } - } - } - - return size(); -} - -/*------------------------------------------------------ - - protected member function - test a parameter to see if it's a switch : - - switches are of the form : -x - where 'x' is one or more characters. - the first character of a switch must be non-numeric! - -------------------------------------------------------*/ - -bool CCmdLine::IsSwitch(const char *pParam) -{ - if (pParam==NULL) - return false; - - // switches must non-empty - // must have at least one character after the '-' - int len = strlen(pParam); - if (len <= 1) - { - return false; - } - - // switches always start with '-' - if (pParam[0]=='-') - { - // allow negative numbers as arguments. - // ie., don't count them as switches -#ifdef Q_WS_WIN - return (!isdigit(pParam[1])); -#else - return true; -#endif - } - else - { - return false; - } -} - -/*------------------------------------------------------ - bool CCmdLine::HasSwitch(const char *pSwitch) - - was the switch found on the command line ? - - ex. if the command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5 - - call return - ---- ------ - cmdLine.HasSwitch("-a") true - cmdLine.HasSwitch("-z") false -------------------------------------------------------*/ - -bool CCmdLine::HasSwitch(const char *pSwitch) -{ - CCmdLine::iterator theIterator; - theIterator = find(pSwitch); - return (theIterator!=end()); -} - -/*------------------------------------------------------ - - StringType CCmdLine::GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault) - - fetch an argument associated with a switch . if the parameter at - index iIdx is not found, this will return the default that you - provide. - - example : - - command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5 - - call return - ---- ------ - cmdLine.GetSafeArgument("-a", 0, "zz") p1 - cmdLine.GetSafeArgument("-a", 1, "zz") p2 - cmdLine.GetSafeArgument("-b", 0, "zz") p4 - cmdLine.GetSafeArgument("-b", 1, "zz") zz - -------------------------------------------------------*/ - -StringType CCmdLine::GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault) -{ - StringType sRet; - - if (pDefault!=NULL) - sRet = pDefault; - - try - { - sRet = GetArgument(pSwitch, iIdx); - } - catch (...) - { - } - - return sRet; -} - -/*------------------------------------------------------ - - StringType CCmdLine::GetArgument(const char *pSwitch, int iIdx) - - fetch a argument associated with a switch. throws an exception - of (int)0, if the parameter at index iIdx is not found. - - example : - - command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5 - - call return - ---- ------ - cmdLine.GetArgument("-a", 0) p1 - cmdLine.GetArgument("-b", 1) throws (int)0, returns an empty string - -------------------------------------------------------*/ - -StringType CCmdLine::GetArgument(const char *pSwitch, int iIdx) -{ - if (HasSwitch(pSwitch)) - { - CCmdLine::iterator theIterator; - - theIterator = find(pSwitch); - if (theIterator!=end()) - { - if ((*theIterator).second.m_strings.size() > (unsigned)iIdx) - { - return (*theIterator).second.m_strings[iIdx]; - } - } - } - - throw (int)0; - - return ""; -} - -/*------------------------------------------------------ - int CCmdLine::GetArgumentCount(const char *pSwitch) - - returns the number of arguments found for a given switch. - - returns -1 if the switch was not found - -------------------------------------------------------*/ - -int CCmdLine::GetArgumentCount(const char *pSwitch) -{ - int iArgumentCount = -1; - - if (HasSwitch(pSwitch)) - { - CCmdLine::iterator theIterator; - - theIterator = find(pSwitch); - if (theIterator!=end()) - { - iArgumentCount = (*theIterator).second.m_strings.size(); - } - } - - return iArgumentCount; -} diff --git a/src/Tools/ImageTools/ImageConv/CmdLine.h b/src/Tools/ImageTools/ImageConv/CmdLine.h deleted file mode 100644 index 88a965a70b..0000000000 --- a/src/Tools/ImageTools/ImageConv/CmdLine.h +++ /dev/null @@ -1,235 +0,0 @@ -/*------------------------------------------------------ - CCmdLine - - A utility for parsing command lines. - - Copyright (C) 1999 Chris Losinger, Smaller Animals Software. - http://www.smalleranimals.com - - This software is provided 'as-is', without any express - or implied warranty. In no event will the authors be - held liable for any damages arising from the use of this software. - - Permission is granted to anyone to use this software - for any purpose, including commercial applications, and - to alter it and redistribute it freely, subject to the - following restrictions: - - 1. The origin of this software must not be misrepresented; - you must not claim that you wrote the original software. - If you use this software in a product, an acknowledgment - in the product documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, - and must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - ------------------------- - - Example : - - Our example application uses a command line that has two - required switches and two optional switches. The app should abort - if the required switches are not present and continue with default - values if the optional switches are not present. - - Sample command line : - MyApp.exe -p1 text1 text2 -p2 "this is a big argument" -opt1 -55 -opt2 - - Switches -p1 and -p2 are required. - p1 has two arguments and p2 has one. - - Switches -opt1 and -opt2 are optional. - opt1 requires a numeric argument. - opt2 has no arguments. - - Also, assume that the app displays a 'help' screen if the '-h' switch - is present on the command line. - - #include "CmdLine.h" - - void main(int argc, char **argv) - { - // our cmd line parser object - CCmdLine cmdLine; - - // parse argc,argv - if (cmdLine.SplitLine(argc, argv) < 1) - { - // no switches were given on the command line, abort - ASSERT(0); - exit(-1); - } - - // test for the 'help' case - if (cmdLine.HasSwitch("-h")) - { - show_help(); - exit(0); - } - - // get the required arguments - StringType p1_1, p1_2, p2_1; - try - { - // if any of these fail, we'll end up in the catch() block - p1_1 = cmdLine.GetArgument("-p1", 0); - p1_2 = cmdLine.GetArgument("-p1", 1); - p2_1 = cmdLine.GetArgument("-p2", 0); - - } - catch (...) - { - // one of the required arguments was missing, abort - ASSERT(0); - exit(-1); - } - - // get the optional parameters - - // convert to an int, default to '100' - int iOpt1Val = atoi(cmdLine.GetSafeArgument("-opt1", 0, 100)); - - // since opt2 has no arguments, just test for the presence of - // the '-opt2' switch - bool bOptVal2 = cmdLine.HasSwitch("-opt2"); - - .... and so on.... - - } - - If this class is used in an MFC application, StringType is CString, else - it uses the STL 'string' type. - - If this is an MFC app, you can use the __argc and __argv macros from - you CYourWinApp::InitInstance() function in place of the standard argc - and argv variables. - -------------------------------------------------------*/ -#ifndef SACMDSH -#define SACMDSH - - -#ifdef __AFX_H__ -// if we're using MFC, use CStrings -#define StringType CString -#else -// if we're not using MFC, use STL strings -#define StringType string -#endif - -// tell the compiler to shut up -#pragma warning(disable:4786) - -//#include // you may need this -#include -#include -#include -using namespace std ; - -// handy little container for our argument vector -struct CCmdParam -{ - vector m_strings; -}; - -// this class is actually a map of strings to vectors -using _CCmdLine = map; - -// the command line parser class -class CCmdLine : public _CCmdLine -{ - -public: - /*------------------------------------------------------ - int CCmdLine::SplitLine(int argc, char **argv) - - parse the command line into switches and arguments. - - returns number of switches found - ------------------------------------------------------*/ - int SplitLine(int argc, char **argv); - - /*------------------------------------------------------ - bool CCmdLine::HasSwitch(const char *pSwitch) - - was the switch found on the command line ? - - ex. if the command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5 - - call return - ---- ------ - cmdLine.HasSwitch("-a") true - cmdLine.HasSwitch("-z") false - ------------------------------------------------------*/ - bool HasSwitch(const char *pSwitch); - - /*------------------------------------------------------ - - StringType CCmdLine::GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault) - - fetch an argument associated with a switch . if the parameter at - index iIdx is not found, this will return the default that you - provide. - - example : - - command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5 - - call return - ---- ------ - cmdLine.GetSafeArgument("-a", 0, "zz") p1 - cmdLine.GetSafeArgument("-a", 1, "zz") p2 - cmdLine.GetSafeArgument("-b", 0, "zz") p4 - cmdLine.GetSafeArgument("-b", 1, "zz") zz - - ------------------------------------------------------*/ - - StringType GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault); - - /*------------------------------------------------------ - - StringType CCmdLine::GetArgument(const char *pSwitch, int iIdx) - - fetch a argument associated with a switch. throws an exception - of (int)0, if the parameter at index iIdx is not found. - - example : - - command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5 - - call return - ---- ------ - cmdLine.GetArgument("-a", 0) p1 - cmdLine.GetArgument("-b", 1) throws (int)0, returns an empty string - - ------------------------------------------------------*/ - StringType GetArgument(const char *pSwitch, int iIdx); - - /*------------------------------------------------------ - int CCmdLine::GetArgumentCount(const char *pSwitch) - - returns the number of arguments found for a given switch. - - returns -1 if the switch was not found - - ------------------------------------------------------*/ - int GetArgumentCount(const char *pSwitch); - -protected: - /*------------------------------------------------------ - - protected member function - test a parameter to see if it's a switch : - - switches are of the form : -x - where 'x' is one or more characters. - the first character of a switch must be non-numeric! - - ------------------------------------------------------*/ - bool IsSwitch(const char *pParam); -}; - -#endif diff --git a/src/Tools/ImageTools/ImageConv/ImageConv.pro b/src/Tools/ImageTools/ImageConv/ImageConv.pro deleted file mode 100644 index b702f57074..0000000000 --- a/src/Tools/ImageTools/ImageConv/ImageConv.pro +++ /dev/null @@ -1,9 +0,0 @@ -TEMPLATE = app -CONFIG += debug console -TARGET += -DEPENDPATH += . -INCLUDEPATH += . - -# Input -HEADERS += CmdLine.h imageconv.h -SOURCES += CmdLine.cpp imageconv.cpp main.cpp diff --git a/src/Tools/ImageTools/ImageConv/cmdline.htm b/src/Tools/ImageTools/ImageConv/cmdline.htm deleted file mode 100644 index 25a8363264..0000000000 --- a/src/Tools/ImageTools/ImageConv/cmdline.htm +++ /dev/null @@ -1,146 +0,0 @@ - - -

-CCmdLine - a class for parsing command line with or without MFC -


- - -This article was contributed by Chris Losinger. - - -

Environment: All - - -

- - -CCmdLine is a simple way to parse a command line into switches and arguments. -Ex : -
-

    -MyApp.exe -sw1 arg1 arg2 -sw2 arg3 -sw3 -sw4 -
-
-When using CCmdLine, "-sw1", "-sw2", "-sw3" and "-sw4" are switches and "arg1", "arg2" and "arg3" are arguments. -

-Parsing command lines with the standard C string functions (strlen, strcpy, etc.) or even -with the CString operators is a nightmare. But, CCmdLine makes it effortless. -

-CCmdLine was written for use with console apps, but can be easily used in -any application which requires command-line parsing. -

-CCmdLine uses STL for its collection classes, so it works in MFC -and non-MFC apps. If you are using this in an MFC app, the switches -and arguments will be returned as CStrings. If you are using this in a -non-MFC app, they will be returned as STL 'string's. -

-


-Example : - -Assume the application we're writing uses a command line that has two -required switches and two optional switches. The app should abort -if the required switches are not present and continue with default -values if the optional switches are not present. -
    -Sample command line : -
    -
    -  MyApp.exe -p1 text1 text2 -p2 "this is a big argument" -opt1 -55 -opt2
    -
    -Switches -p1 and -p2 are required. -
    -p1 has two arguments and p2 has one. -
    -
    -Switches -opt1 and -opt2 are optional. -
    -opt1 requires a numeric argument. -
    -opt2 has no arguments. -
    -
    -Also, assume that the app displays a 'help' screen if the '-h' switch -is present on the command line. -
-Here's how you can use CCmdLine to handle this : -
- -

-// if this is an MFC app, uncomment this line
-// #include "stdafx.h"
-
-#include "CmdLine.h"
-
-void main(int argc, char **argv)
-{
-  // our cmd line parser object
-  CCmdLine cmdLine;
-
-  // parse the command line
-  // use __argc and __argv, in MFC apps
-  if (cmdLine.SplitLine(argc, argv) < 1)
-  {
-     // no switches were given on the command line, abort
-     ASSERT(0);
-     exit(-1);
-  }
-
-  // test for the 'help' case
-  if (cmdLine.HasSwitch("-h"))
-  {
-     show_help();
-     exit(0);
-  }
-
-  // StringType is CString when using MFC, else STL's 'string'
-  StringType p1_1, p1_2, p2_1;
-
-  // get the required arguments
-  try
-  {  
-     // if any of these GetArgument calls fail, 
-     // we'll end up in the catch() block
-
-     // get the first -p1 argument
-     p1_1 = cmdLine.GetArgument("-p1", 0);
-
-     // get the second -p1 argument
-     p1_2 = cmdLine.GetArgument("-p1", 1);
-
-     // get the first -p2 argument
-     p2_1 = cmdLine.GetArgument("-p2", 0);
-
-  }
-  catch (...)
-  {
-     // one of the required arguments was missing, abort
-     ASSERT(0);
-     exit(-1);
-  }
-
-  // get the optional parameters
-
-  // GetSafeArgument does not throw exceptions, and allows for 
-  // the use of a default value, in case the switch is not found
-  // convert to an int, default to '100'
-  int iOpt1Val =    atoi( cmdLine.GetSafeArgument( "-opt1", 0, 100 ) );
-
-  // since opt2 has no arguments, just test for the presence of
-  // the '-opt2' switch
-  bool bOptSwitch2 =   cmdLine.HasSwitch("-opt2");
-
-  .... and so on....
-
-}
-
-
- - - -

Download source - 5 Kb - - - -

Date Posted: June 16, 1999 - - \ No newline at end of file diff --git a/src/Tools/ImageTools/ImageConv/imageconv.cpp b/src/Tools/ImageTools/ImageConv/imageconv.cpp deleted file mode 100644 index 99dc7df42c..0000000000 --- a/src/Tools/ImageTools/ImageConv/imageconv.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/*************************************************************************** - imageconv.cpp - description - ------------------- - begin : Die Apr 23 21:02:14 CEST 2002 - copyright : (C) 2002 by Werner Mayer - email : - ***************************************************************************/ - -/*************************************************************************** - * * - * This program 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. * - * Werner Mayer 2002 * - * * - ***************************************************************************/ - -#include "imageconv.h" -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -CCmdLineParser::CCmdLineParser(int argc, char** argv) -{ - SplitLine(argc, argv); -} - -CCmdParam CCmdLineParser::GetArgumentList(const char* pSwitch) -{ - if (HasSwitch(pSwitch)) - { - CCmdLineParser::iterator theIterator; - - theIterator = find(pSwitch); - if (theIterator!=end()) - { - return (*theIterator).second; - } - } - - CCmdParam param; - return param; -} - -// ------------------------------------------------------------ - -QString CImageConvApp::m_Executable = "ImageConv"; -QString CImageConvApp::m_BmpFactory = "BmpFactoryIcons.cpp"; - -CImageConvApp::CImageConvApp(const QString& sFile) -{ - m_bUpdate = false; - m_Output = sFile; - QString filter = "*.png;*.bmp;*.xbm;*.pnm;*.jpg;*.jpeg;*.mng;*.gif"; // not "*.xpm"! - m_Dir.setNameFilters(filter.split(';')); -} - -void CImageConvApp::SetOutputFile(const QString& sFile) -{ - m_Output = sFile; -} - -void CImageConvApp::SetNameFilters(const QStringList& nameFilter) -{ - m_Dir.setNameFilters(nameFilter); -} - -bool CImageConvApp::Save(const QString& fn) -{ - int iPos = fn.indexOf("."); - - QString ext = fn.mid(iPos+1); // extension of filename - QString name = fn.mid(0,iPos); // filename without extension - - if (!m_clPixmap.isNull()) - { - if (!fn.isEmpty()) - { - return m_clPixmap.save(fn, ext.toUpper().toLatin1()); - } - } - - return false; -} - -bool CImageConvApp::Load(const QString& fn) -{ - QByteArray ext = QImageReader::imageFormat(fn); - - if (!fn.isEmpty()) - return m_clPixmap.load( fn, ext); - - return false; -} - -const QPixmap& CImageConvApp::GetPixmap() const -{ - return m_clPixmap; -} - -bool CImageConvApp::ConvertToXPM(bool bAppendToFile) -{ - QStringList list = m_Dir.entryList(); - - // print to the console - cout << "Try converting to XPM..." << endl; - if (list.count() == 0) - { - cout << "Cannot find " << (const char*)m_Dir.nameFilters().join(" ").toLatin1() << endl; - return false; - } - - for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) - { - QByteArray ext = QImageReader::imageFormat(*it); - if (ext.isEmpty()) - continue; // no image format - - if (m_Output == *it) - continue; // if the file is the output file itself - - cout << "Converting " << (const char*)(*it).toLatin1() << " ..."; - - if (Load(*it) == true) - { - QString name(*it); - name.replace(name.indexOf(".")+1, 4, "xpm"); - - bool ok; - - QFileInfo fi(*it); - if (bAppendToFile) - ok = AppendToFile(fi.baseName()); - else - ok = Save(name); - - if (ok) - cout << "Done" << endl; - else - cout << "failed" << endl; - } - else - { - cout << "failed" << endl; - } - } - - return true; -} - -void CImageConvApp::CreateBmpFactory() -{ - // empty file - // - QFileInfo fi(m_BmpFactory); - - // already exists - if (fi.exists() && fi.isFile()) - return; - - QFile fw(m_BmpFactory); - QTextStream tw (&fw); - if (!fw.open(QIODevice::Text | QIODevice::Unbuffered | QIODevice::WriteOnly)) - return; - - // write header stuff - tw << "\n"; - tw << "void RegisterIcons()\n"; - tw << "{\n"; - tw << " Gui::BitmapFactoryInst& rclBmpFactory = Gui::BitmapFactory();\n"; - tw << "}\n"; - fw.close(); -} - -bool CImageConvApp::AppendToFile(const QString& file) -{ - CreateBmpFactory(); - - QString ohead("static char"); - QString nhead("static const char"); - - // save as XPM into tmp. buffer - QByteArray str; - QBuffer buf(&str); - buf.open (QIODevice::WriteOnly); - QImageWriter iio(&buf, "XPM"); - QImage im; - im = m_clPixmap.toImage(); - iio.write(im); - buf.close(); - - // convert to string and make changes - QString txt = str; - txt.replace(ohead, nhead); - txt.replace(QString("dummy"), file); - - // open file - bool found = false; - QFile fw(m_Output); - if (fw.open(QIODevice::ReadOnly)) - { - QTextStream tr (&fw); - QString line; - do - { - line = tr.readLine(); - if ((line.indexOf(file)) != -1) // icon already registered - { - found = true; - } - } while (!tr.atEnd() && !found); - - fw.close(); - } - - // register new icon - if (!found) - { - if (!fw.open(QIODevice::Text | QIODevice::Unbuffered | QIODevice::ReadWrite | QIODevice::Append)) - return false; - - // write into file now - QTextStream tw (&fw); - tw << txt << "\n"; - fw.close(); - - if (m_bUpdate) - { - QFile bmp(m_BmpFactory); - QTextStream ts (&bmp); - if (!bmp.open(QIODevice::Text | QIODevice::Unbuffered | QIODevice::WriteOnly)) - return false; - - bmp.seek(bmp.size()-3); - ts << " rclBmpFactory.addXPM(\"" << file << "\", " << file << ");\n"; - ts << "}\n"; - bmp.close(); - } - } - - return true; -} - -void CImageConvApp::Error() -{ - cerr << "Usage: " << (const char*)m_Executable.toLatin1() << " [OPTION(S)] -i input file(s) {-o output file}" << endl; - cerr << "Try '" << (const char*)m_Executable.toLatin1() << " --help' for more information." << endl; - - exit(0); -} - -void CImageConvApp::Version() -{ - cerr << (const char*)m_Executable.toLatin1() << " 1.0.0 " << endl; - exit(0); -} - -void CImageConvApp::Usage() -{ - cerr << "Usage: " << (const char*)m_Executable.toLatin1() << " [OPTION(S)] -i input file(s) {-o output file}\n" << endl; - cerr << "Options:" << endl; - - cerr << " -i \tSpecify the input file(s).\n" - " \tSeveral filenames must be separated by a blank.\n" - " \tIf you want to select all files of a format\n" - " \tyou also can write \"*.[FORMAT]\" (e.g. *.png).\n" - " \tSpecifying several files only makes sense in\n" - " \taddition with -a or -x." << endl; - - cerr << " -o \tSpecify the output file." << endl; - - cerr << " -x, --xpm\tConvert all specified image files to XPM.\n" - " \tFor each specified image file a corresponding\n" - " \tXPM file will be created.\n" - " \tWith -i you can specify the input files." << endl; - - cerr << " -a, --append\tConvert all specified image files to XPM and\n" - " \tappend the result to the file specified with -o.\n" - " \tWith -i you can specify the input files.\n" << endl; - - - cerr << " -u, --update\tUpdate the file \"BmpFactoryIcons.cpp\"\n" - " \tThis is a special mode to add icons to the FreeCAD's\n" - " \tbitmap factory automatically.\n" - " \tThis switch is only available in addition with -a.\n" << endl; - - cerr << " -v, --version\tPrint the version and exit." << endl; - - cerr << " -h, --help\tPrint this message and exit.\n" << endl; - - cerr << "This program supports the following image formats:\n" - " BMP, GIF, JPEG, MNG, PNG, PNM, XBM and XPM\n\n" - << (const char*)m_Executable.toLatin1() << " uses Qt Version " << qVersion() << "\n" - "Qt can be downloaded at http://www.trolltech.com." << endl; - - exit(0); -} diff --git a/src/Tools/ImageTools/ImageConv/imageconv.h b/src/Tools/ImageTools/ImageConv/imageconv.h deleted file mode 100644 index d90d51183e..0000000000 --- a/src/Tools/ImageTools/ImageConv/imageconv.h +++ /dev/null @@ -1,98 +0,0 @@ -/*************************************************************************** - imageconv.h - description - ------------------- - begin : Die Apr 23 21:02:14 CEST 2002 - copyright : (C) 2002 by Werner Mayer - email : - ***************************************************************************/ - -/*************************************************************************** - * * - * This program 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. * - * Werner Mayer 2002 * - * * - ***************************************************************************/ - -#ifndef IMAGECONV_H -#define IMAGECONV_H - -// includes -#include "CmdLine.h" -#include -#include -#include -#include - -#include -#include - -// defines -#define TString std::string -#define TVector std::vector -#define TMap std::map -#define TPair std::pair - - -// the command line parser class -class CCmdLineParser : public CCmdLine -{ -public: - CCmdLineParser (int argc, char** argv); - ~CCmdLineParser () {} - - CCmdParam GetArgumentList(const char* pSwitch); -}; - -// ------------------------------------------------------------ - -class CICException -{ -public: - CICException(const QString& text) - : msg(text) {} - CICException(const CICException& e) - { *this = e; } - ~CICException() - { } - QString what() const - { return msg; } - -private: - QString msg; -}; - -// ------------------------------------------------------------ - -class CImageConvApp -{ -public: - CImageConvApp(const QString& sFile = "Images.cpp"); - void SetOutputFile(const QString& sFile); - void SetNameFilters(const QStringList& nameFilter); - bool Save(const QString& fn); - bool Load(const QString& fn); - bool ConvertToXPM(bool bAppendToFile = false); - bool AppendToFile(const QString& file); - void SetUpdateBmpFactory(bool b) - { m_bUpdate = b; } - void CreateBmpFactory(); - - const QPixmap& GetPixmap() const; - - static void Usage(); - static void Error(); - static void Version(); - -private: - bool m_bUpdate; - static QString m_Executable; - static QString m_BmpFactory; - QPixmap m_clPixmap; // pixmap - QString m_Output; // specified output file - QDir m_Dir; // directory -}; - -#endif // IMAGECONV_H diff --git a/src/Tools/ImageTools/ImageConv/main.cpp b/src/Tools/ImageTools/ImageConv/main.cpp deleted file mode 100644 index f3a740ff26..0000000000 --- a/src/Tools/ImageTools/ImageConv/main.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/*************************************************************************** - main.cpp - description - ------------------- - begin : Die Apr 23 21:02:14 CEST 2002 - copyright : (C) 2002 by Werner Mayer - email : - ***************************************************************************/ - -/*************************************************************************** - * * - * This program 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. * - * Werner Mayer 2002 * - * * - ***************************************************************************/ - -#include -#include -#include "imageconv.h" - -using namespace std; - -int main( int argc, char **argv ) -{ - QApplication app( argc, argv ); - CImageConvApp cICApp; - CCmdLineParser cCmdP(argc, argv); - - try - { - // look for the specified switches and arguments - // - // - // show help message and exit - if (cCmdP.HasSwitch("-h") || cCmdP.HasSwitch("--help")) - { - CImageConvApp::Usage(); - } - // show version and exit - else if (cCmdP.HasSwitch("-v") || cCmdP.HasSwitch("--version")) - { - CImageConvApp::Version(); - } - - // convert all given/found image files to XPM - if (cCmdP.HasSwitch("-x") || cCmdP.HasSwitch("--xpm")) - { - // search for input files - if (cCmdP.GetArgumentCount("-i") > 0) - { - QStringList nameFilters; - CCmdParam para = cCmdP.GetArgumentList("-i"); - for (TVector::iterator it = para.m_strings.begin(); it != para.m_strings.end(); it++) - { - cout << "Search for " << it->c_str() << endl; - nameFilters.append(it->c_str()); - } - - cICApp.SetNameFilters(nameFilters); - cICApp.ConvertToXPM(false); - } - else - throw CICException("No input file specified."); - } - - // convert all given/found image files to XPM and write the result into a text file - else if (cCmdP.HasSwitch("-a") || cCmdP.HasSwitch("--append")) - { - // search for input fĂ­les - if (cCmdP.GetArgumentCount("-i") > 0) - { - cICApp.SetUpdateBmpFactory(cCmdP.HasSwitch("-a") || cCmdP.HasSwitch("--update")); - QStringList nameFilters; - CCmdParam para = cCmdP.GetArgumentList("-i"); - for (TVector::iterator it = para.m_strings.begin(); it != para.m_strings.end(); it++) - { - cout << "Search for " << it->c_str() << endl; - nameFilters.append(it->c_str()); - } - - cICApp.SetNameFilters(nameFilters); - } - else - throw CICException("No input files specified."); - - // search for output file - if (cCmdP.GetArgumentCount("-o") > 0) - { - cICApp.SetOutputFile(QString(cCmdP.GetArgument("-o", 0).c_str())); - cICApp.ConvertToXPM(true); - } - else - throw CICException("No output file specified."); - } - - // convert one image file to another image file - else if (cCmdP.HasSwitch("-i") && cCmdP.HasSwitch("-o")) - { - // input and output file specified - CCmdParam p1 = cCmdP.GetArgumentList("-i"); - CCmdParam p2 = cCmdP.GetArgumentList("-o"); - - if (p1.m_strings.size() > 1) - throw CICException("Too much input files specified."); - if (p1.m_strings.size() < 1) - throw CICException("No input file specified."); - if (p2.m_strings.size() > 1) - throw CICException("Too much output files specified."); - if (p2.m_strings.size() < 1) - throw CICException("No output file specified."); - - TString fil1(*p1.m_strings.begin()); - TString fil2(*p2.m_strings.begin()); - - if (cICApp.Load(QString(fil1.c_str())) == false) - { - cout << "Loading of " << fil1.c_str() << " failed!" << endl; - cout << "Perhaps the file does not exist or QT does not support this format." << endl; - return -1; - } - if (cICApp.Save(QString(fil2.c_str())) == false) - { - cout << "Saving of " << fil2.c_str() << " failed!" << endl; - cout << "Perhaps QT does not support this format." << endl; - } - else - { - cout << "Converted successfully!" << endl; - } - } - // no/wrong arguments - else - throw CICException("Wrong arguments."); - } - catch(const CICException& e) - { - cerr << (const char*)e.what().toLatin1() << endl; - CImageConvApp::Error(); - } - catch(...) - { - cerr << "An unknown exception has occurred!!!" << endl; - } - - return 0; -} diff --git a/tests/src/Misc/test1.cpp b/tests/src/Misc/test1.cpp deleted file mode 100644 index ec010830b1..0000000000 --- a/tests/src/Misc/test1.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "gtest/gtest.h" - -TEST(FirstSuite, FirstTest){ - EXPECT_NE(1, 1) << "are in fact equal"; -} - -TEST(FirstSuite, SecondTest){ - EXPECT_EQ(1, 2) << "not equal"; -} - -TEST(FirstSuite, ThirdTest){ - ASSERT_STREQ("A", "A") << "str not equal"; -} -TEST(FirstSuite,FifthTest){ - ASSERT_STRNE("am", "am") << "str equal"; -} -TEST(FirstSuite, FourthTest){ - ASSERT_STREQ("am", "A") << "str not equal"; -} diff --git a/tests/src/Misc/test2.cpp b/tests/src/Misc/test2.cpp deleted file mode 100644 index 6020366af2..0000000000 --- a/tests/src/Misc/test2.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "gtest/gtest.h"