Merge branch 'master' into path_custom_source

This commit is contained in:
Morgan 'ARR\!' Allen
2023-03-29 20:50:07 -07:00
67 changed files with 1431 additions and 1497 deletions

View File

@@ -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 "<details><summary>:fire: GTest C++ unit test suite failed</summary>" >> ${{ inputs.reportFile }}
else
echo "<details><summary>:heavy_check_mark: GTest C++ unit test suite succeeded</summary>" >> ${{ inputs.reportFile }}
fi
echo "" >> ${{ inputs.reportFile }}
echo "Results" >> ${{ inputs.reportFile }}
echo "" >> ${{ inputs.reportFile }}
echo '```' >> ${{ inputs.reportFile }}
echo "$result" >> ${{ inputs.reportFile }}
echo '```' >> ${{ inputs.reportFile }}
echo "</details>">> ${{ inputs.reportFile }}
echo "" >> ${{ inputs.reportFile }}

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -39,7 +39,7 @@ on:
type: string
required: true
checkLineendings:
default: true
default: false
type: boolean
required: false
lineendingsFailSilent:

View File

@@ -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)

View File

@@ -41,6 +41,8 @@
# include <QWindow>
#endif
#include <QLoggingCategory>
#include <App/Document.h>
#include <App/DocumentObjectPy.h>
#include <Base/Console.h>
@@ -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;
}

View File

@@ -49,6 +49,7 @@
<file>icons/Draft_Join.svg</file>
<file>icons/Draft_Label.svg</file>
<file>icons/Draft_Layer.svg</file>
<file>icons/Draft_LayerManager.svg</file>
<file>icons/Draft_Line.svg</file>
<file>icons/Draft_LinkArray.svg</file>
<file>icons/Draft_Lock.svg</file>
@@ -191,5 +192,6 @@
<file>ui/dialog_AnnotationStyleEditor.ui</file>
<file>ui/TaskPanel_SetStyle.ui</file>
<file>ui/dialogHatch.ui</file>
<file>ui/dialogLayers.ui</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,515 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48.000000px"
height="48.000000px"
id="svg249"
sodipodi:version="0.32"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="BIM_Layers.svg"
inkscape:export-filename="/home/jimmac/gfx/novell/pdes/trunk/docs/BIGmime-text.png"
inkscape:export-xdpi="240.00000"
inkscape:export-ydpi="240.00000"
version="1.1">
<defs
id="defs3">
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5060"
id="radialGradient5031"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
cx="605.71429"
cy="486.64789"
fx="605.71429"
fy="486.64789"
r="117.14286" />
<linearGradient
inkscape:collect="always"
id="linearGradient5060">
<stop
style="stop-color:black;stop-opacity:1;"
offset="0"
id="stop5062" />
<stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop5064" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5060"
id="radialGradient5029"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
cx="605.71429"
cy="486.64789"
fx="605.71429"
fy="486.64789"
r="117.14286" />
<linearGradient
id="linearGradient5048">
<stop
style="stop-color:black;stop-opacity:0;"
offset="0"
id="stop5050" />
<stop
id="stop5056"
offset="0.5"
style="stop-color:black;stop-opacity:1;" />
<stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop5052" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5048"
id="linearGradient5027"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)"
x1="302.85715"
y1="366.64789"
x2="302.85715"
y2="609.50507" />
<linearGradient
inkscape:collect="always"
id="linearGradient4542">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4544" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop4546" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4542"
id="radialGradient4548"
cx="24.306795"
cy="42.07798"
fx="24.306795"
fy="42.07798"
r="15.821514"
gradientTransform="matrix(1.000000,0.000000,0.000000,0.284916,-6.310056e-16,30.08928)"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient15662">
<stop
style="stop-color:#ffffff;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop15664" />
<stop
style="stop-color:#f8f8f8;stop-opacity:1.0000000;"
offset="1.0000000"
id="stop15666" />
</linearGradient>
<radialGradient
gradientUnits="userSpaceOnUse"
fy="64.5679"
fx="20.8921"
r="5.257"
cy="64.5679"
cx="20.8921"
id="aigrd3">
<stop
id="stop15573"
style="stop-color:#F0F0F0"
offset="0" />
<stop
id="stop15575"
style="stop-color:#9a9a9a;stop-opacity:1.0000000;"
offset="1.0000000" />
</radialGradient>
<radialGradient
gradientUnits="userSpaceOnUse"
fy="114.5684"
fx="20.8921"
r="5.256"
cy="114.5684"
cx="20.8921"
id="aigrd2">
<stop
id="stop15566"
style="stop-color:#F0F0F0"
offset="0" />
<stop
id="stop15568"
style="stop-color:#9a9a9a;stop-opacity:1.0000000;"
offset="1.0000000" />
</radialGradient>
<linearGradient
id="linearGradient269">
<stop
style="stop-color:#a3a3a3;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop270" />
<stop
style="stop-color:#4c4c4c;stop-opacity:1.0000000;"
offset="1.0000000"
id="stop271" />
</linearGradient>
<linearGradient
id="linearGradient259">
<stop
style="stop-color:#fafafa;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop260" />
<stop
style="stop-color:#bbbbbb;stop-opacity:1.0000000;"
offset="1.0000000"
id="stop261" />
</linearGradient>
<linearGradient
id="linearGradient12512">
<stop
style="stop-color:#ffffff;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop12513" />
<stop
style="stop-color:#fff520;stop-opacity:0.89108908;"
offset="0.50000000"
id="stop12517" />
<stop
style="stop-color:#fff300;stop-opacity:0.0000000;"
offset="1.0000000"
id="stop12514" />
</linearGradient>
<radialGradient
r="37.751713"
fy="3.7561285"
fx="8.8244190"
cy="3.7561285"
cx="8.8244190"
gradientTransform="matrix(0.968273,0.000000,0.000000,1.032767,3.353553,0.646447)"
gradientUnits="userSpaceOnUse"
id="radialGradient15656"
xlink:href="#linearGradient269"
inkscape:collect="always" />
<radialGradient
r="86.708450"
fy="35.736916"
fx="33.966679"
cy="35.736916"
cx="33.966679"
gradientTransform="scale(0.960493,1.041132)"
gradientUnits="userSpaceOnUse"
id="radialGradient15658"
xlink:href="#linearGradient259"
inkscape:collect="always" />
<radialGradient
r="38.158695"
fy="7.2678967"
fx="8.1435566"
cy="7.2678967"
cx="8.1435566"
gradientTransform="matrix(0.968273,0.000000,0.000000,1.032767,3.353553,0.646447)"
gradientUnits="userSpaceOnUse"
id="radialGradient15668"
xlink:href="#linearGradient15662"
inkscape:collect="always" />
<radialGradient
inkscape:collect="always"
xlink:href="#aigrd2"
id="radialGradient2283"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.229703,0.000000,0.000000,0.229703,4.613529,3.979808)"
cx="20.8921"
cy="114.5684"
fx="20.8921"
fy="114.5684"
r="5.256" />
<radialGradient
inkscape:collect="always"
xlink:href="#aigrd3"
id="radialGradient2285"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.229703,0.000000,0.000000,0.229703,4.613529,3.979808)"
cx="20.8921"
cy="64.5679"
fx="20.8921"
fy="64.5679"
r="5.257" />
<linearGradient
id="linearGradient3815"
inkscape:collect="always">
<stop
id="stop3817"
offset="0"
style="stop-color:#d3d7cf;stop-opacity:1;" />
<stop
id="stop3819"
offset="1"
style="stop-color:#ffffff;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientTransform="translate(-0.02151317,-0.91811256)"
gradientUnits="userSpaceOnUse"
y2="-1.3815211"
x2="25.928942"
y1="19.086002"
x1="53.257175"
id="linearGradient3805"
xlink:href="#linearGradient3815"
inkscape:collect="always" />
<linearGradient
gradientTransform="translate(0.75600263,0.0412295)"
gradientUnits="userSpaceOnUse"
y2="12.022611"
x2="36.843666"
y1="27.953379"
x1="61.719494"
id="linearGradient3813"
xlink:href="#linearGradient3815"
inkscape:collect="always" />
<linearGradient
gradientTransform="translate(-0.18895427,-1.1237431)"
gradientUnits="userSpaceOnUse"
y2="23.542751"
x2="48.388607"
y1="43.419685"
x1="74.313408"
id="linearGradient3821"
xlink:href="#linearGradient3815"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="0.32941176"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="93.761718"
inkscape:cy="-13.65303"
inkscape:current-layer="layer4"
showgrid="false"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1920"
inkscape:window-height="1051"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:showpageshadow="false"
inkscape:window-maximized="1" />
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:creator>
<cc:Agent>
<dc:title>Jakub Steiner</dc:title>
</cc:Agent>
</dc:creator>
<dc:source>http://jimmac.musichall.cz</dc:source>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Attribution" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Shadow"
id="layer6"
inkscape:groupmode="layer">
<g
style="display:inline"
id="g5022"
transform="matrix(2.165152e-2,0,0,1.485743e-2,43.0076,42.68539)">
<rect
y="-150.69685"
x="-1559.2523"
height="478.35718"
width="1339.6335"
id="rect4173"
style="opacity:0.40206185;color:black;fill:url(#linearGradient5027);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
<path
sodipodi:nodetypes="cccc"
id="path5058"
d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z "
style="opacity:0.40206185;color:black;fill:url(#radialGradient5029);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
<path
style="opacity:0.40206185;color:black;fill:url(#radialGradient5031);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z "
id="path5018"
sodipodi:nodetypes="cccc" />
</g>
</g>
<g
id="layer1"
inkscape:label="Base"
inkscape:groupmode="layer"
style="display:inline">
<rect
ry="1.1490486"
y="3.6464462"
x="6.6035528"
height="40.920494"
width="34.875000"
id="rect15391"
style="color:#000000;fill:url(#radialGradient15658);fill-opacity:1.0000000;fill-rule:nonzero;stroke:url(#radialGradient15656);stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:block;overflow:visible" />
<rect
rx="0.14904857"
ry="0.14904857"
y="4.5839462"
x="7.6660538"
height="38.946384"
width="32.775887"
id="rect15660"
style="color:#000000;fill:none;fill-opacity:1.0000000;fill-rule:nonzero;stroke:url(#radialGradient15668);stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:block;overflow:visible" />
<g
id="g2270"
transform="translate(0.646447,-3.798933e-2)">
<g
transform="matrix(0.229703,0.000000,0.000000,0.229703,4.967081,4.244972)"
style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4.0000000"
id="g1440">
<radialGradient
gradientUnits="userSpaceOnUse"
fy="114.56840"
fx="20.892099"
r="5.2560000"
cy="114.56840"
cx="20.892099"
id="radialGradient1442">
<stop
id="stop1444"
style="stop-color:#F0F0F0"
offset="0" />
<stop
id="stop1446"
style="stop-color:#474747"
offset="1" />
</radialGradient>
<path
id="path1448"
d="M 23.428000,113.07000 C 23.428000,115.04300 21.828000,116.64200 19.855000,116.64200 C 17.881000,116.64200 16.282000,115.04200 16.282000,113.07000 C 16.282000,111.09600 17.882000,109.49700 19.855000,109.49700 C 21.828000,109.49700 23.428000,111.09700 23.428000,113.07000 z "
style="stroke:none" />
<radialGradient
gradientUnits="userSpaceOnUse"
fy="64.567902"
fx="20.892099"
r="5.2570000"
cy="64.567902"
cx="20.892099"
id="radialGradient1450">
<stop
id="stop1452"
style="stop-color:#F0F0F0"
offset="0" />
<stop
id="stop1454"
style="stop-color:#474747"
offset="1" />
</radialGradient>
<path
id="path1456"
d="M 23.428000,63.070000 C 23.428000,65.043000 21.828000,66.643000 19.855000,66.643000 C 17.881000,66.643000 16.282000,65.043000 16.282000,63.070000 C 16.282000,61.096000 17.882000,59.497000 19.855000,59.497000 C 21.828000,59.497000 23.428000,61.097000 23.428000,63.070000 z "
style="stroke:none" />
</g>
<path
id="path15570"
d="M 9.9950109,29.952326 C 9.9950109,30.405530 9.6274861,30.772825 9.1742821,30.772825 C 8.7208483,30.772825 8.3535532,30.405301 8.3535532,29.952326 C 8.3535532,29.498892 8.7210780,29.131597 9.1742821,29.131597 C 9.6274861,29.131597 9.9950109,29.499122 9.9950109,29.952326 z "
style="fill:url(#radialGradient2283);fill-rule:nonzero;stroke:none;stroke-miterlimit:4.0000000" />
<path
id="path15577"
d="M 9.9950109,18.467176 C 9.9950109,18.920380 9.6274861,19.287905 9.1742821,19.287905 C 8.7208483,19.287905 8.3535532,18.920380 8.3535532,18.467176 C 8.3535532,18.013742 8.7210780,17.646447 9.1742821,17.646447 C 9.6274861,17.646447 9.9950109,18.013972 9.9950109,18.467176 z "
style="fill:url(#radialGradient2285);fill-rule:nonzero;stroke:none;stroke-miterlimit:4.0000000" />
</g>
<path
sodipodi:nodetypes="cc"
id="path15672"
d="M 11.505723,5.4942766 L 11.505723,43.400869"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.98855311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:0.017543854" />
<path
sodipodi:nodetypes="cc"
id="path15674"
d="M 12.500000,5.0205154 L 12.500000,43.038228"
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:0.20467831" />
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="new"
style="display:inline">
<g
inkscape:label="Layer 1"
id="layer1-6"
transform="matrix(0.45072343,0,0,0.45072343,9.6052107,9.3385922)"
style="stroke-width:2.53389549;stroke-miterlimit:4;stroke-dasharray:none">
<rect
transform="matrix(0.92408158,0.38219528,-0.75246174,0.65863596,0,0)"
y="16.492231"
x="40.359722"
height="27.016869"
width="39.045357"
id="rect2993"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3821);fill-opacity:1;fill-rule:evenodd;stroke:#2e3436;stroke-width:7.0861426;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="rect2993-0-9-3-7"
d="M 25.329927,28.679638 57.173418,41.866954 40.234042,56.653163 8.3211848,43.465847 Z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:2.53389549;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
<rect
transform="matrix(0.92408158,0.38219528,-0.75246174,0.65863596,0,0)"
y="6.2172832"
x="31.989382"
height="27.016869"
width="39.045357"
id="rect2993-0"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3813);fill-opacity:1;fill-rule:evenodd;stroke:#2e3436;stroke-width:7.0861426;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="rect2993-0-9-3-6"
d="M 25.30824,18.773895 57.151731,31.961211 40.212355,46.74742 8.2994962,33.560104 Z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:2.53389549;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
<rect
transform="matrix(0.92408158,0.38219528,-0.75246174,0.65863596,6.510896e-8,5.0104617e-8)"
y="-6.1819811"
x="21.896566"
height="27.016869"
width="39.045357"
id="rect2993-0-9"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3805);fill-opacity:1;fill-rule:evenodd;stroke:#2e3436;stroke-width:7.0861426;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="rect2993-0-9-3"
d="M 25.281278,6.6563352 57.124769,19.843651 40.185393,34.62986 8.2725348,21.442544 Z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ffffff;stroke-width:2.53389549;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>667</width>
<height>320</height>
</rect>
</property>
<property name="windowTitle">
<string>Layers manager</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeView" name="tree">
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="buttonNew">
<property name="text">
<string>New</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonDelete">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonSelectAll">
<property name="text">
<string>Select all</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonToggle">
<property name="text">
<string>Toggle on/off</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonIsolate">
<property name="text">
<string>Isolate</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="buttonCancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonOK">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -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))

View File

@@ -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()

View File

@@ -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())
## @}

View File

@@ -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

View File

@@ -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):

View File

@@ -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."""

View File

@@ -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",

View File

@@ -31,6 +31,7 @@
# include <Inventor/nodes/SoSeparator.h>
#endif
#include <App/Document.h>
#include <App/MaterialObject.h>
#include <App/TextDocument.h>
#include <Gui/ActionFunction.h>
@@ -38,6 +39,8 @@
#include <Gui/Control.h>
#include <Gui/Document.h>
#include <Gui/MainWindow.h>
#include <Gui/Selection.h>
#include <Gui/SelectionObject.h>
#include <Mod/Fem/App/FemAnalysis.h>
#include <Mod/Fem/App/FemConstraint.h>
#include <Mod/Fem/App/FemMeshObject.h>
@@ -251,15 +254,40 @@ void ViewProviderFemAnalysis::dropObject(App::DocumentObject *obj)
bool ViewProviderFemAnalysis::onDelete(const std::vector<std::string> &)
{
// 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<App::DocumentObject*> 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());

View File

@@ -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<App::DocumentObject*> claimChildren()const override;
// handling when object is deleted
/// handling when object is deleted
bool onDelete(const std::vector<std::string>&) 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<App::DocumentObject*> 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<App::DocumentObject*> 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<std::string> getDisplayModes() const override;
// shows solid in the tree
/// shows solid in the tree
bool isShow() const override {
return Visibility.getValue();
}

View File

@@ -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<std::string>&)
{
// 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) {

View File

@@ -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;
};

View File

@@ -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<std::string>&)
{
// 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

View File

@@ -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) {

View File

@@ -32,6 +32,7 @@
#include <Gui/MainWindow.h>
#include "ViewProviderSolver.h"
#include "ViewProviderAnalysis.h"
using namespace FemGui;
@@ -44,9 +45,7 @@ ViewProviderSolver::ViewProviderSolver()
}
ViewProviderSolver::~ViewProviderSolver()
{
}
{}
std::vector<std::string> ViewProviderSolver::getDisplayModes() const
{
@@ -55,32 +54,9 @@ std::vector<std::string> ViewProviderSolver::getDisplayModes() const
bool ViewProviderSolver::onDelete(const std::vector<std::string>&)
{
// 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

View File

@@ -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

View File

@@ -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. "

View File

@@ -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"]

View File

@@ -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)

View File

@@ -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

Binary file not shown.

Binary file not shown.

View File

@@ -22,6 +22,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QLocale>
# include <QRegularExpression>
#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;

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -58,7 +58,7 @@ public:
TopoDS_Compound alignSectionFaces(TopoDS_Shape faceIntersections) override;
std::pair<Base::Vector3d, Base::Vector3d> 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; }

View File

@@ -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");

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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());

View File

@@ -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; }

View File

@@ -84,14 +84,13 @@ void loadTechDrawResource()
// add fonts
std::string fontDir = App::Application::getResourceDir() + "Mod/TechDraw/Resources/fonts/";
QFontDatabase fontDB;
std::vector<std::string> 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));

View File

@@ -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()

View File

@@ -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;
};

View File

@@ -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<QGraphicsItem*>::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());
}

View File

@@ -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();

View File

@@ -27,7 +27,6 @@
#include <QApplication>
#include <QBitmap>
#include <QContextMenuEvent>
#include <QGLWidget>
#include <QLabel>
#include <QMouseEvent>
#include <QPaintEvent>
@@ -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);

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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<CCmdLine::iterator, bool> 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;
}

View File

@@ -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 <iostream> // you may need this
#include <map>
#include <string>
#include <vector>
using namespace std ;
// handy little container for our argument vector
struct CCmdParam
{
vector<StringType> m_strings;
};
// this class is actually a map of strings to vectors
using _CCmdLine = map<StringType, CCmdParam>;
// 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

View File

@@ -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

View File

@@ -1,146 +0,0 @@
<!--#include virtual="header.shtml" -->
<CENTER><H3><FONT COLOR="#AOAO99">
CCmdLine - a class for parsing command line with or without MFC
</FONT></H3></CENTER><HR>
<!-- Author and contact details -->
This article was contributed by <A HREF="mailto:smallest@smalleranimals.com">Chris Losinger</A>.
<!-- Environment eg NT 4.0 SP3, VC6.0 SP1 -->
<p>Environment: All</u>
<!-- Text / source code -->
<p>
<!-- The 'p' starts a paragraph of normal text -->
CCmdLine is a simple way to parse a command line into <i>switches</i> and <i>arguments</i>.
Ex :
<br>
<ul>
MyApp.exe -sw1 arg1 arg2 -sw2 arg3 -sw3 -sw4
</ul>
<br>
When using CCmdLine, "-sw1", "-sw2", "-sw3" and "-sw4" are <i>switches</i> and "arg1", "arg2" and "arg3" are <i>arguments</i>.
<p>
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.
<p>
CCmdLine was written for use with console apps, but can be easily used in
any application which requires command-line parsing.
<p>
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.
<p>
<hr>
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.
<ul>
Sample command line :
<br>
<pre>
MyApp.exe -p1 text1 text2 -p2 "this is a big argument" -opt1 -55 -opt2
</pre>
Switches -p1 and -p2 are required.
<br>
p1 has two arguments and p2 has one.
<br>
<br>
Switches -opt1 and -opt2 are optional.
<br>
opt1 requires a numeric argument.
<br>
opt2 has no arguments.
<br>
<br>
Also, assume that the app displays a 'help' screen if the '-h' switch
is present on the command line.
</ul>
Here's how you can use CCmdLine to handle this :
<hr>
<!-- start a block of source code -->
<PRE><TT><FONT COLOR="#990000">
// 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....
}
<!-- end the block of source code -->
</FONT></TT></PRE>
<!-- demo project -->
<p><A HREF="cmdline.zip">Download source - 5 Kb</A>
<!-- Date Posted and Last update (eg August 11, 1998) -->
<p>Date Posted: June 16, 1999
<!--#include virtual="footer.shtml" -->

View File

@@ -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 <QStringList>
#include <QBuffer>
#include <QTextStream>
#include <QImage>
#include <QImageWriter>
#include <QImageReader>
#include <iostream>
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);
}

View File

@@ -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 <string>
#include <map>
#include <string>
#include <vector>
#include <QPixmap>
#include <QDir>
// 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

View File

@@ -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 <iostream>
#include <QApplication>
#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<TString>::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<TString>::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;
}

View File

@@ -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";
}

View File

@@ -1 +0,0 @@
#include "gtest/gtest.h"