FEM: Modernize multiframe code and incorporate review feedback

This commit is contained in:
Stefan Tröger
2025-02-21 19:04:52 +01:00
committed by Benjamin Nauck
parent 0a1cc21b5c
commit 9738b9b6ea
15 changed files with 80 additions and 149 deletions

View File

@@ -24,27 +24,10 @@
#ifndef _PreComp_
#include <Python.h>
#include <vtkDataSetReader.h>
#include <vtkImageData.h>
#include <vtkRectilinearGrid.h>
#include <vtkStructuredGrid.h>
#include <vtkUnstructuredGrid.h>
#include <vtkXMLImageDataReader.h>
#include <vtkXMLPUnstructuredGridReader.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkXMLRectilinearGridReader.h>
#include <vtkXMLStructuredGridReader.h>
#include <vtkXMLUnstructuredGridReader.h>
#endif
#include <Base/Console.h>
#include "FemMesh.h"
#include "FemMeshObject.h"
#include "FemPostBranchFilter.h"
#include "FemPostBranchFilterPy.h"
#include "FemVTKTools.h"
using namespace Fem;
using namespace App;
@@ -120,15 +103,14 @@ void FemPostBranchFilter::setupPipeline()
m_append->RemoveAllInputConnections(0);
FemPostFilter* filter = NULL;
std::vector<App::DocumentObject*>::iterator it = objs.begin();
for (; it != objs.end(); ++it) {
for (auto& obj : objs) {
// prepare the filter: make all connections new
FemPostFilter* nextFilter = static_cast<FemPostFilter*>(*it);
FemPostFilter* nextFilter = static_cast<FemPostFilter*>(obj);
nextFilter->getFilterInput()->RemoveAllInputConnections(0);
// handle input modes
if (Mode.getValue() == 0) {
if (Mode.getValue() == Fem::PostGroupMode::Serial) {
// serial: the next filter gets the previous output, the first one gets our input
if (filter == NULL) {
nextFilter->getFilterInput()->SetInputConnection(m_passthrough->GetOutputPort());
@@ -137,7 +119,7 @@ void FemPostBranchFilter::setupPipeline()
}
}
else if (Mode.getValue() == 1) {
else if (Mode.getValue() == Fem::PostGroupMode::Parallel) {
// parallel: all filters get out input
nextFilter->getFilterInput()->SetInputConnection(m_passthrough->GetOutputPort());
}
@@ -162,7 +144,7 @@ void FemPostBranchFilter::onChanged(const Property* prop)
if (prop == &Frame) {
//Update all children with the new step
for (const auto& obj : Group.getValues()) {
if (obj->isDerivedFrom(FemPostFilter::getClassTypeId())) {
if (obj->isDerivedFrom<FemPostFilter>()) {
static_cast<Fem::FemPostFilter*>(obj)->Frame.setValue(Frame.getValue());
}
}
@@ -193,7 +175,7 @@ void FemPostBranchFilter::filterChanged(FemPostFilter* filter)
{
//we only need to update the following children if we are in serial mode
if (Mode.getValue() == 0) {
if (Mode.getValue() == Fem::PostGroupMode::Serial) {
std::vector<App::DocumentObject*> objs = Group.getValues();
@@ -201,14 +183,13 @@ void FemPostBranchFilter::filterChanged(FemPostFilter* filter)
return;
}
bool started = false;
std::vector<App::DocumentObject*>::iterator it = objs.begin();
for (; it != objs.end(); ++it) {
for (auto& obj : objs) {
if (started) {
(*it)->touch();
obj->touch();
}
if (*it == filter) {
if (obj == filter) {
started = true;
}
}

View File

@@ -50,7 +50,7 @@ public:
short mustExecute() const override;
PyObject* getPyObject() override;
const char* getViewProviderName() const override
constexpr const char* getViewProviderName() const override
{
return "FemGui::ViewProviderFemPostBranchFilter";
}

View File

@@ -25,8 +25,6 @@
#include <Python.h>
#endif
#include <Base/FileInfo.h>
// clang-format off
#include "FemPostBranchFilter.h"
#include "FemPostBranchFilterPy.h"

View File

@@ -45,7 +45,11 @@
namespace Fem
{
enum TransformLocation { input, output };
enum class TransformLocation : size_t
{
input,
output
};
class FemExport FemPostFilter: public Fem::FemPostObject
{

View File

@@ -41,7 +41,7 @@ FemPostFunctionProvider::~FemPostFunctionProvider() = default;
bool FemPostFunctionProvider::allowObject(App::DocumentObject* obj)
{
return obj->isDerivedFrom(FemPostFunction::getClassTypeId());
return obj->isDerivedFrom<FemPostFunction>();
}
void FemPostFunctionProvider::unsetupObject()
@@ -60,11 +60,8 @@ void FemPostFunctionProvider::handleChangedPropertyName(Base::XMLReader& reader,
if (strcmp(propName, "Functions") == 0
&& Base::Type::fromName(typeName) == App::PropertyLinkList::getClassTypeId()) {
// add the formerly Functions values to the group
App::PropertyLinkList functions;
functions.setContainer(this);
functions.Restore(reader);
Group.setValues(functions.getValues());
// restore the property into Group, instead of the old Functions property
Group.Restore(reader);
}
else {
App::DocumentObject::handleChangedPropertyName(reader, typeName, propName);

View File

@@ -53,7 +53,7 @@ FemPostGroupExtension::~FemPostGroupExtension() {
void FemPostGroupExtension::initExtension(App::ExtensionContainer* obj)
{
if (!obj->isDerivedFrom(Fem::FemPostObject::getClassTypeId())) {
if (!obj->isDerivedFrom<FemPostObject>()) {
throw Base::RuntimeError("FemPostGroupExtension can only be applied to FemPostObject");
}
@@ -68,8 +68,8 @@ void FemPostGroupExtension::extensionOnChanged(const App::Property* p)
auto objs = Group.getValues();
std::sort( objs.begin( ), objs.end( ), [ ]( const App::DocumentObject* lhs, const App::DocumentObject* rhs ){
int l = lhs->isDerivedFrom(FemPostFilter::getClassTypeId()) ? 0 : 1;
int r = rhs->isDerivedFrom(FemPostFilter::getClassTypeId()) ? 0 : 1;
int l = lhs->isDerivedFrom<FemPostFilter>() ? 0 : 1;
int r = rhs->isDerivedFrom<FemPostFilter>() ? 0 : 1;
return r<l;
});
m_blockChange = true;
@@ -84,8 +84,8 @@ std::vector<Fem::FemPostFilter*> FemPostGroupExtension::getFilter()
{
//collect all other items that are not filters
std::vector<Fem::FemPostFilter*> filters;
for (auto obj : Group.getValues()) {
if (obj->isDerivedFrom(Fem::FemPostFilter::getClassTypeId())) {
for (auto& obj : Group.getValues()) {
if (obj->isDerivedFrom<FemPostFilter>()) {
filters.push_back(static_cast<FemPostFilter*>(obj));
}
}
@@ -115,7 +115,7 @@ void FemPostGroupExtension::onExtendedUnsetupObject()
bool FemPostGroupExtension::allowObject(App::DocumentObject* obj)
{
// only filters may be added
return obj->isDerivedFrom(Fem::FemPostFilter::getClassTypeId());
return obj->isDerivedFrom<FemPostFilter>();
}
@@ -142,11 +142,9 @@ FemPostObject* FemPostGroupExtension::getLastPostObject()
bool FemPostGroupExtension::holdsPostObject(FemPostObject* obj)
{
for (const auto& group_obj : Group.getValues()) {
std::vector<App::DocumentObject*>::const_iterator it = Group.getValues().begin();
for (; it != Group.getValues().end(); ++it) {
if (*it == obj) {
if (group_obj == obj) {
return true;
}
}

View File

@@ -30,6 +30,12 @@
namespace Fem
{
enum PostGroupMode
{
Serial,
Parallel
};
// object grouping FEM filters and building the structure of the pipeline
class FemExport FemPostGroupExtension : public App::GroupExtension {

View File

@@ -27,11 +27,12 @@
#include "PropertyPostDataObject.h"
#include <App/GeoFeature.h>
#include <App/PropertyStandard.h>
#include <vtkBoundingBox.h>
#include <vtkDataSet.h>
#include <vtkTransformFilter.h>
#include <vtkSmartPointer.h>
class vtkDataSet;
namespace Fem
{

View File

@@ -39,9 +39,10 @@
#include <vtkXMLMultiBlockDataReader.h>
#include <vtkMultiBlockDataSet.h>
#include <vtkStreamingDemandDrivenPipeline.h>
#include <vtkPointData.h>
#include <vtkFloatArray.h>
#include <vtkStringArray.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#endif
#include <Base/Console.h>
@@ -102,23 +103,20 @@ std::vector<double> FemFrameSourceAlgorithm::getFrameValues()
vtkDataObject* block = multiblock->GetBlock(i);
// check if the TimeValue field is available
if (!block->GetFieldData()->HasArray("TimeValue")) {
break;
// a frame with no valid value is a undefined state
return std::vector<double>();
}
// store the time value!
vtkDataArray* TimeValue = block->GetFieldData()->GetArray("TimeValue");
if (!TimeValue->IsA("vtkFloatArray") || TimeValue->GetNumberOfTuples() < 1) {
break;
// a frame with no valid value is a undefined state
return std::vector<double>();
}
tFrames[i] = vtkFloatArray::SafeDownCast(TimeValue)->GetValue(0);
}
if (tFrames.size() != nblocks) {
// not every block had time data
return std::vector<double>();
}
return tFrames;
}
@@ -189,7 +187,6 @@ int FemFrameSourceAlgorithm::RequestData(vtkInformation*,
return 1;
}
PROPERTY_SOURCE_WITH_EXTENSIONS(Fem::FemPostPipeline, Fem::FemPostObject)
FemPostPipeline::FemPostPipeline()
@@ -237,7 +234,7 @@ Fem::FemPostFunctionProvider* FemPostPipeline::getFunctionProvider()
// see if we have one
for (auto obj : Group.getValues()) {
if (obj->isDerivedFrom(FemPostFunctionProvider::getClassTypeId())) {
if (obj->isDerivedFrom<FemPostFunctionProvider>()) {
return static_cast<FemPostFunctionProvider*>(obj);
}
}
@@ -247,7 +244,7 @@ Fem::FemPostFunctionProvider* FemPostPipeline::getFunctionProvider()
bool FemPostPipeline::allowObject(App::DocumentObject* obj)
{
// we additionally allow FunctionPRoviders to be added
if (obj->isDerivedFrom(FemPostFunctionProvider::getClassTypeId())) {
if (obj->isDerivedFrom<FemPostFunctionProvider>()) {
return true;
}
@@ -406,7 +403,7 @@ void FemPostPipeline::onChanged(const Property* prop)
value = frames[Frame.getValue()];
}
for (const auto& obj : Group.getValues()) {
if (obj->isDerivedFrom(FemPostFilter::getClassTypeId())) {
if (obj->isDerivedFrom<FemPostFilter>()) {
static_cast<Fem::FemPostFilter*>(obj)->Frame.setValue(value);
}
}
@@ -427,16 +424,15 @@ void FemPostPipeline::onChanged(const Property* prop)
}
FemPostFilter* filter = NULL;
std::vector<FemPostFilter*>::iterator it = objs.begin();
for (; it != objs.end(); ++it) {
for (auto& obj : objs) {
// prepare the filter: make all connections new
FemPostFilter* nextFilter = *it;
FemPostFilter* nextFilter = obj;
nextFilter->getFilterInput()->RemoveAllInputConnections(0);
// handle input modes (Parallel is seperated, alll other settings are serial, just in
// case an old document is loaded with "custom" mode, idx 2)
if (Mode.getValue() == 1) {
if (Mode.getValue() == Fem::PostGroupMode::Parallel) {
// parallel: all filters get out input
nextFilter->getFilterInput()->SetInputConnection(
m_transform_filter->GetOutputPort(0));
@@ -464,7 +460,7 @@ void FemPostPipeline::onChanged(const Property* prop)
void FemPostPipeline::filterChanged(FemPostFilter* filter)
{
// we only need to update the following children if we are in serial mode
if (Mode.getValue() == 0) {
if (Mode.getValue() == Fem::PostGroupMode::Serial) {
std::vector<App::DocumentObject*> objs = Group.getValues();
@@ -472,17 +468,16 @@ void FemPostPipeline::filterChanged(FemPostFilter* filter)
return;
}
bool started = false;
std::vector<App::DocumentObject*>::iterator it = objs.begin();
for (; it != objs.end(); ++it) {
for (auto& obj : objs) {
if (started) {
(*it)->touch();
if((*it)->hasExtension(Fem::FemPostGroupExtension::getExtensionClassTypeId())) {
(*it)->getExtension<FemPostGroupExtension>()->recomputeChildren();
obj->touch();
if(obj->hasExtension(Fem::FemPostGroupExtension::getExtensionClassTypeId())) {
obj->getExtension<FemPostGroupExtension>()->recomputeChildren();
}
}
if (*it == filter) {
if (obj == filter) {
started = true;
}
}
@@ -592,10 +587,10 @@ void FemPostPipeline::load(FemResultObject* res)
// set multiple result objects as frames for one pipeline
// Notes:
// 1. values vector must contain growing value, smallest first
void FemPostPipeline::load(std::vector<FemResultObject*> res,
std::vector<double> values,
void FemPostPipeline::load(std::vector<FemResultObject*>& res,
std::vector<double>& values,
Base::Unit unit,
std::string frame_type)
std::string& frame_type)
{
if (res.size() != values.size()) {
@@ -612,7 +607,7 @@ void FemPostPipeline::load(std::vector<FemResultObject*> res,
auto multiblock = vtkSmartPointer<vtkMultiBlockDataSet>::New();
for (ulong i = 0; i < res.size(); i++) {
if (!res[i]->Mesh.getValue()->isDerivedFrom(Fem::FemMeshObject::getClassTypeId())) {
if (!res[i]->Mesh.getValue()->isDerivedFrom<FemMeshObject>()) {
Base::Console().Error("Result mesh object is not derived from Fem::FemMeshObject.\n");
return;
}
@@ -679,8 +674,8 @@ void FemPostPipeline::onDocumentRestored()
{
// if a old document was loaded with "custom" mode setting, the current value
// would be out of range. Reset it to "serial"
if (Mode.getValue() > 1 || Mode.getValue() < 0) {
Mode.setValue(long(0));
if (Mode.getValue() > Fem::PostGroupMode::Parallel || Mode.getValue() < Fem::PostGroupMode::Serial) {
Mode.setValue(Fem::PostGroupMode::Serial);
}
}

View File

@@ -33,8 +33,9 @@
#include <vtkSmartPointer.h>
#include <vtkUnstructuredGridAlgorithm.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
class vtkInformation;
class vtkInformationVector;
namespace Fem
@@ -93,7 +94,7 @@ public:
// load from results
void load(FemResultObject* res);
void load(std::vector<FemResultObject*> res, std::vector<double> values, Base::Unit unit, std::string frame_type);
void load(std::vector<FemResultObject*>& res, std::vector<double>& values, Base::Unit unit, std::string& frame_type);
// Group pipeline handling
void filterChanged(FemPostFilter* filter) override;

View File

@@ -56,6 +56,7 @@
#include <zipios++/zipios-config.h>
#endif
#include <zipios++/zipoutputstream.h>
#include <zipios++/zipinputstream.h>
#include "PropertyPostDataObject.h"

View File

@@ -1843,7 +1843,7 @@ void setupFilter(Gui::Command* cmd, std::string Name)
pipeline = selObject;
} else {
pipeline = Fem::FemPostGroupExtension::getGroupOfObject(selObject);
if (!pipeline || !pipeline->isDerivedFrom(Fem::FemPostObject::getClassTypeId())) {
if (!pipeline || !pipeline->isDerivedFrom<Fem::FemPostObject>()) {
QMessageBox::warning(
Gui::getMainWindow(),
qApp->translate("setupFilter", "Error: Object not in a post processing group"),
@@ -2027,7 +2027,7 @@ bool CmdFemPostClipFilter::isActive()
}
// only activate if a post object is selected
for (auto obj : selection ) {
if (obj.pObject->isDerivedFrom(Fem::FemPostObject::getClassTypeId())) {
if (obj.pObject->isDerivedFrom<Fem::FemPostObject>()) {
return true;
}
}
@@ -2064,7 +2064,7 @@ bool CmdFemPostCutFilter::isActive()
}
// only activate if a post object is selected
for (auto obj : selection ) {
if (obj.pObject->isDerivedFrom(Fem::FemPostObject::getClassTypeId())) {
if (obj.pObject->isDerivedFrom<Fem::FemPostObject>()) {
return true;
}
}
@@ -2101,7 +2101,7 @@ bool CmdFemPostDataAlongLineFilter::isActive()
}
// only activate if a post object is selected
for (auto obj : selection ) {
if (obj.pObject->isDerivedFrom(Fem::FemPostObject::getClassTypeId())) {
if (obj.pObject->isDerivedFrom<Fem::FemPostObject>()) {
return true;
}
}
@@ -2139,7 +2139,7 @@ bool CmdFemPostDataAtPointFilter::isActive()
}
// only activate if a post object is selected
for (auto obj : selection ) {
if (obj.pObject->isDerivedFrom(Fem::FemPostObject::getClassTypeId())) {
if (obj.pObject->isDerivedFrom<Fem::FemPostObject>()) {
return true;
}
}
@@ -2252,7 +2252,7 @@ bool CmdFemPostScalarClipFilter::isActive()
}
// only activate if a post object is selected
for (auto obj : selection ) {
if (obj.pObject->isDerivedFrom(Fem::FemPostObject::getClassTypeId())) {
if (obj.pObject->isDerivedFrom<Fem::FemPostObject>()) {
return true;
}
}
@@ -2289,7 +2289,7 @@ bool CmdFemPostWarpVectorFilter::isActive()
}
// only activate if a post object is selected
for (auto obj : selection ) {
if (obj.pObject->isDerivedFrom(Fem::FemPostObject::getClassTypeId())) {
if (obj.pObject->isDerivedFrom<Fem::FemPostObject>()) {
return true;
}
}
@@ -2326,7 +2326,7 @@ bool CmdFemPostContoursFilter::isActive()
}
// only activate if a post object is selected
for (auto obj : selection ) {
if (obj.pObject->isDerivedFrom(Fem::FemPostObject::getClassTypeId())) {
if (obj.pObject->isDerivedFrom<Fem::FemPostObject>()) {
return true;
}
}
@@ -2724,7 +2724,7 @@ bool CmdFemPostBranchFilter::isActive()
}
// only activate if a post object is selected
for (auto obj : selection ) {
if (obj.pObject->isDerivedFrom(Fem::FemPostObject::getClassTypeId())) {
if (obj.pObject->isDerivedFrom<Fem::FemPostObject>()) {
return true;
}
}

View File

@@ -6,34 +6,12 @@
height="64"
id="svg2"
version="1.1"
sodipodi:docname="FEM_PostBranch.svg"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:zoom="22.627417"
inkscape:cx="36.018252"
inkscape:cy="29.676388"
inkscape:window-width="3772"
inkscape:window-height="2132"
inkscape:window-x="68"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs4">
<linearGradient
@@ -97,22 +75,18 @@
<path
style="fill:none;stroke:#172a04;stroke-width:14.3583;stroke-linejoin:bevel;stroke-dasharray:none"
d="m 7.3446662,1052.2913 c -0.191309,-28.689 5.4919548,-27.8281 16.3618638,-30.5412 8.792494,-2.559 8.364413,-18.0247 8.364413,-18.0247 l -0.0367,-15.1045"
id="path2"
sodipodi:nodetypes="cccc" />
id="path2" />
<path
style="fill:none;stroke:#172a04;stroke-width:14.3583;stroke-linejoin:bevel;stroke-dasharray:none"
d="m 56.732958,1052.2676 c 0.19131,-28.6891 -5.491978,-27.8281 -16.361932,-30.5413 -8.79253,-2.559 -8.364448,-18.0247 -8.364448,-18.0247 l 0.0367,-15.10452"
id="path2-5"
sodipodi:nodetypes="cccc" />
id="path2-5" />
<path
style="fill:none;stroke:#8ae234;stroke-width:7.511;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:1"
d="m 56.806638,1052.2731 c 0.191309,-28.6892 -5.491977,-27.8281 -16.361932,-30.5414 -8.79253,-2.559 -8.364446,-18.0247 -8.364446,-18.0247 l 0.0367,-15.10445"
id="path2-6-3"
sodipodi:nodetypes="cccc" />
id="path2-6-3" />
<path
style="fill:none;stroke:#8ae234;stroke-width:7.511;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:1"
d="m 7.435987,1052.2558 c -0.1913091,-28.689 5.491954,-27.8281 16.361864,-30.5412 8.792494,-2.559 8.364413,-18.0247 8.364413,-18.0247 l -0.0367,-15.10449"
id="path2-6"
sodipodi:nodetypes="cccc" />
id="path2-6" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -6,34 +6,12 @@
height="64"
id="svg2"
version="1.1"
sodipodi:docname="FEM_PostSteps.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:zoom="10.650796"
inkscape:cx="26.24217"
inkscape:cy="37.743658"
inkscape:window-width="3772"
inkscape:window-height="2132"
inkscape:window-x="68"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs4">
<linearGradient
@@ -97,12 +75,10 @@
<path
style="fill:none;stroke:#172a04;stroke-width:7.88137;stroke-linecap:butt;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:1"
d="m 4.3166604,1048.6979 c 10.0528756,-6.3495 11.0960996,-30.5752 16.6915666,-33.7987 5.595471,-3.2236 6.828368,10.3544 14.225768,14.3596 3.888376,1.9536 12.80319,-6.5449 15.838022,-11.8199 3.03483,-5.275 9.389006,-25.69077 9.389006,-25.69077 v 0"
id="path1"
sodipodi:nodetypes="cccccc" />
id="path1" />
<path
style="fill:none;stroke:#8ae234;stroke-width:5.1317;stroke-opacity:1"
d="m 4.3878505,1048.9004 c 10.0583295,-6.3607 11.1021185,-30.6296 16.7006225,-33.859 5.598506,-3.2291 6.832073,10.3729 14.233486,14.3854 3.890486,1.9571 12.810136,-6.5567 15.846614,-11.841 3.036476,-5.2844 9.394101,-25.73679 9.394101,-25.73679 v 0"
id="path1-6"
sodipodi:nodetypes="cccccc" />
id="path1-6" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -330,9 +330,8 @@ void TaskDlgPost::clicked(int button)
bool TaskDlgPost::accept()
{
try {
std::vector<TaskPostBox*>::iterator it = m_boxes.begin();
for (; it != m_boxes.end(); ++it) {
(*it)->applyPythonCode();
for (auto& box : m_boxes) {
box->applyPythonCode();
}
}
catch (const Base::Exception& e) {