Assembly: Implement Bill Of Materials (#14198)
* Assembly: Implementation of BOM * Assembly: BOM: make it possible for BOM to be made without an assembly.
This commit is contained in:
@@ -28,6 +28,8 @@
|
||||
#include <Base/PyObjectBase.h>
|
||||
|
||||
#include "AssemblyObject.h"
|
||||
#include "BomObject.h"
|
||||
#include "BomGroup.h"
|
||||
#include "JointGroup.h"
|
||||
#include "ViewGroup.h"
|
||||
|
||||
@@ -43,6 +45,7 @@ PyMOD_INIT_FUNC(AssemblyApp)
|
||||
// load dependent module
|
||||
try {
|
||||
Base::Interpreter().runString("import Part");
|
||||
Base::Interpreter().runString("import Spreadsheet");
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
PyErr_SetString(PyExc_ImportError, e.what());
|
||||
@@ -58,6 +61,9 @@ PyMOD_INIT_FUNC(AssemblyApp)
|
||||
// This function is responsible for adding inherited slots from a type's base class.
|
||||
|
||||
Assembly::AssemblyObject ::init();
|
||||
Assembly::BomObject ::init();
|
||||
|
||||
Assembly::BomGroup ::init();
|
||||
Assembly::JointGroup ::init();
|
||||
Assembly::ViewGroup ::init();
|
||||
|
||||
|
||||
55
src/Mod/Assembly/App/BomGroup.cpp
Normal file
55
src/Mod/Assembly/App/BomGroup.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2023 Ondsel <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD 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 *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/FeaturePythonPyImp.h>
|
||||
#include <App/PropertyPythonObject.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Tools.h>
|
||||
|
||||
#include "BomGroup.h"
|
||||
#include "BomGroupPy.h"
|
||||
|
||||
using namespace Assembly;
|
||||
|
||||
|
||||
PROPERTY_SOURCE(Assembly::BomGroup, App::DocumentObjectGroup)
|
||||
|
||||
BomGroup::BomGroup()
|
||||
{}
|
||||
|
||||
BomGroup::~BomGroup() = default;
|
||||
|
||||
PyObject* BomGroup::getPyObject()
|
||||
{
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new BomGroupPy(this), true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
58
src/Mod/Assembly/App/BomGroup.h
Normal file
58
src/Mod/Assembly/App/BomGroup.h
Normal file
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2023 Ondsel <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD 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 *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef ASSEMBLY_BomGroup_H
|
||||
#define ASSEMBLY_BomGroup_H
|
||||
|
||||
#include <Mod/Assembly/AssemblyGlobal.h>
|
||||
|
||||
#include <App/DocumentObjectGroup.h>
|
||||
#include <App/PropertyLinks.h>
|
||||
|
||||
|
||||
namespace Assembly
|
||||
{
|
||||
|
||||
class AssemblyExport BomGroup: public App::DocumentObjectGroup
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Assembly::BomGroup);
|
||||
|
||||
public:
|
||||
BomGroup();
|
||||
~BomGroup() override;
|
||||
|
||||
PyObject* getPyObject() override;
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "AssemblyGui::ViewProviderBomGroup";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace Assembly
|
||||
|
||||
|
||||
#endif // ASSEMBLY_BomGroup_H
|
||||
19
src/Mod/Assembly/App/BomGroupPy.xml
Normal file
19
src/Mod/Assembly/App/BomGroupPy.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="DocumentObjectGroupPy"
|
||||
Name="BomGroupPy"
|
||||
Twin="BomGroup"
|
||||
TwinPointer="BomGroup"
|
||||
Include="Mod/Assembly/App/BomGroup.h"
|
||||
Namespace="Assembly"
|
||||
FatherInclude="App/DocumentObjectGroupPy.h"
|
||||
FatherNamespace="App">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Ondsel" EMail="development@ondsel.com" />
|
||||
<UserDocu>This class is a group subclass for boms.</UserDocu>
|
||||
</Documentation>
|
||||
|
||||
<CustomAttributes />
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
46
src/Mod/Assembly/App/BomGroupPyImp.cpp
Normal file
46
src/Mod/Assembly/App/BomGroupPyImp.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2014 Jürgen Riegel <juergen.riegel@web.de> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
// inclusion of the generated files (generated out of BomGroup.xml)
|
||||
#include "BomGroupPy.h"
|
||||
#include "BomGroupPy.cpp"
|
||||
|
||||
using namespace Assembly;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string BomGroupPy::representation() const
|
||||
{
|
||||
return {"<Bom Group>"};
|
||||
}
|
||||
|
||||
PyObject* BomGroupPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int BomGroupPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
303
src/Mod/Assembly/App/BomObject.cpp
Normal file
303
src/Mod/Assembly/App/BomObject.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2023 Ondsel <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD 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 *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObjectGroup.h>
|
||||
#include <App/FeaturePythonPyImp.h>
|
||||
#include <App/Link.h>
|
||||
#include <App/PropertyPythonObject.h>
|
||||
#include <App/Range.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Placement.h>
|
||||
#include <Base/Rotation.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Interpreter.h>
|
||||
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
#include <Mod/PartDesign/App/Body.h>
|
||||
#include <Mod/Spreadsheet/App/Cell.h>
|
||||
|
||||
|
||||
#include "AssemblyObject.h"
|
||||
#include "BomGroup.h"
|
||||
#include "JointGroup.h"
|
||||
#include "ViewGroup.h"
|
||||
#include "BomObject.h"
|
||||
#include "BomObjectPy.h"
|
||||
|
||||
|
||||
using namespace Assembly;
|
||||
|
||||
// ================================ Assembly Object ============================
|
||||
|
||||
PROPERTY_SOURCE(Assembly::BomObject, Spreadsheet::Sheet)
|
||||
|
||||
BomObject::BomObject()
|
||||
: Spreadsheet::Sheet()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(columnsNames,
|
||||
("Index"),
|
||||
"Bom",
|
||||
(App::PropertyType)(App::Prop_None),
|
||||
"List of the columns of the Bill of Materials.");
|
||||
|
||||
ADD_PROPERTY_TYPE(detailSubAssemblies,
|
||||
(true),
|
||||
"Bom",
|
||||
(App::PropertyType)(App::Prop_None),
|
||||
"Detail sub-assemblies components.");
|
||||
|
||||
ADD_PROPERTY_TYPE(detailParts,
|
||||
(true),
|
||||
"Bom",
|
||||
(App::PropertyType)(App::Prop_None),
|
||||
"Detail Parts sub-components.");
|
||||
|
||||
ADD_PROPERTY_TYPE(
|
||||
onlyParts,
|
||||
(false),
|
||||
"Bom",
|
||||
(App::PropertyType)(App::Prop_None),
|
||||
"Only Part containers will be added. Solids like PartDesign Bodies will be ignored.");
|
||||
}
|
||||
BomObject::~BomObject() = default;
|
||||
|
||||
PyObject* BomObject::getPyObject()
|
||||
{
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new BomObjectPy(this), true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn* BomObject::execute()
|
||||
{
|
||||
generateBOM();
|
||||
|
||||
return Spreadsheet::Sheet::execute();
|
||||
}
|
||||
|
||||
void BomObject::saveCustomColumnData()
|
||||
{
|
||||
// This function saves data that is not automatically generated.
|
||||
dataElements.clear();
|
||||
std::tuple<App::CellAddress, App::CellAddress> res = getUsedRange();
|
||||
int maxRow = std::get<1>(res).row();
|
||||
int nameColIndex = getColumnIndex("Name");
|
||||
|
||||
for (int row = 1; row <= maxRow; ++row) {
|
||||
|
||||
size_t col = 0;
|
||||
// Here we do not iterate columnName : columnsNames.getValues() because they may have
|
||||
// changed
|
||||
for (size_t i = 0; i < columnsNames.getValues().size(); ++i) {
|
||||
std::string columnName = getText(0, i);
|
||||
if (columnName != "Index" && columnName != "Name" && columnName != "Quantity"
|
||||
&& columnName != "File Name") {
|
||||
// Base::Console().Warning("row col %d %d\n", row, col);
|
||||
// save custom data if any.
|
||||
std::string text = getText(row, col);
|
||||
if (text != "") {
|
||||
std::string objName = getText(row, nameColIndex);
|
||||
BomDataElement el(objName, columnName, text);
|
||||
dataElements.push_back(el);
|
||||
}
|
||||
}
|
||||
|
||||
++col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BomObject::generateBOM()
|
||||
{
|
||||
saveCustomColumnData();
|
||||
clearAll();
|
||||
size_t row = 0;
|
||||
size_t col = 0;
|
||||
|
||||
// Populate headers
|
||||
for (auto& columnName : columnsNames.getValues()) {
|
||||
setCell(App::CellAddress(row, col), columnName.c_str());
|
||||
++col;
|
||||
}
|
||||
++row;
|
||||
|
||||
auto* assembly = getAssembly();
|
||||
if (assembly) {
|
||||
addObjectChildrenToBom(assembly->getOutList(), row, "");
|
||||
}
|
||||
else {
|
||||
addObjectChildrenToBom(getDocument()->getRootObjectsIgnoreLinks(), row, "");
|
||||
}
|
||||
}
|
||||
|
||||
void BomObject::addObjectChildrenToBom(std::vector<App::DocumentObject*> objs,
|
||||
size_t& row,
|
||||
std::string index)
|
||||
{
|
||||
int nameColIndex = getColumnIndex("Name");
|
||||
int quantityColIndex = getColumnIndex("Quantity");
|
||||
bool hasQuantityCol = hasQuantityColumn();
|
||||
|
||||
int siblingsInitialRow = row;
|
||||
|
||||
if (index != "") {
|
||||
index = index + ".";
|
||||
}
|
||||
|
||||
size_t sub_i = 1;
|
||||
|
||||
for (auto* child : objs) {
|
||||
if (child->isDerivedFrom<App::Link>()) {
|
||||
child = static_cast<App::Link*>(child)->getLinkedObject();
|
||||
}
|
||||
|
||||
if (child->isDerivedFrom<BomGroup>() || child->isDerivedFrom<JointGroup>()
|
||||
|| child->isDerivedFrom<ViewGroup>()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasQuantityCol) {
|
||||
// Check if the object is not already in (case of links). And if so just increment.
|
||||
// Note: an object can be used in several parts. In which case we do no want to blindly
|
||||
// increment.
|
||||
bool found = false;
|
||||
for (size_t i = siblingsInitialRow; i <= row; ++i) {
|
||||
std::string childName = child->Label.getValue();
|
||||
|
||||
if (childName == getText(i, nameColIndex) && childName != "") {
|
||||
int qty = std::stoi(getText(i, quantityColIndex)) + 1;
|
||||
setCell(App::CellAddress(i, quantityColIndex), std::to_string(qty).c_str());
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (child->isDerivedFrom<App::DocumentObjectGroup>()
|
||||
|| child->isDerivedFrom<AssemblyObject>() || child->isDerivedFrom<App::Part>()
|
||||
|| (child->isDerivedFrom<Part::Feature>() && !onlyParts.getValue())) {
|
||||
|
||||
std::string sub_index = index + std::to_string(sub_i);
|
||||
++sub_i;
|
||||
|
||||
addObjectToBom(child, row, sub_index);
|
||||
++row;
|
||||
|
||||
if (child->isDerivedFrom<App::DocumentObjectGroup>()
|
||||
|| (child->isDerivedFrom<AssemblyObject>() && detailSubAssemblies.getValue())
|
||||
|| (child->isDerivedFrom<App::Part>() && detailParts.getValue())) {
|
||||
addObjectChildrenToBom(child->getOutList(), row, sub_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BomObject::addObjectToBom(App::DocumentObject* obj, size_t row, std::string index)
|
||||
{
|
||||
size_t col = 0;
|
||||
for (auto& columnName : columnsNames.getValues()) {
|
||||
if (columnName == "Index") {
|
||||
setCell(App::CellAddress(row, col), index.c_str());
|
||||
}
|
||||
else if (columnName == "Name") {
|
||||
setCell(App::CellAddress(row, col), obj->Label.getValue());
|
||||
}
|
||||
else if (columnName == "File Name") {
|
||||
setCell(App::CellAddress(row, col), obj->getDocument()->getFileName());
|
||||
}
|
||||
else if (columnName == "Quantity") {
|
||||
setCell(App::CellAddress(row, col), std::to_string(1).c_str());
|
||||
}
|
||||
else {
|
||||
// load custom data if any.
|
||||
for (auto& el : dataElements) {
|
||||
if (el.objName == obj->Label.getValue() && el.columnName == columnName) {
|
||||
setCell(App::CellAddress(row, col), el.value.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
++col;
|
||||
}
|
||||
}
|
||||
|
||||
AssemblyObject* BomObject::getAssembly()
|
||||
{
|
||||
for (auto& obj : getInList()) {
|
||||
if (obj->isDerivedFrom<AssemblyObject>()) {
|
||||
return static_cast<AssemblyObject*>(obj);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool BomObject::hasQuantityColumn()
|
||||
{
|
||||
for (auto& columnName : columnsNames.getValues()) {
|
||||
if (columnName == "Quantity") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Assembly::BomObject::getText(size_t row, size_t col)
|
||||
{
|
||||
Spreadsheet::Cell* cell = getCell(App::CellAddress(row, col));
|
||||
std::string cellName;
|
||||
if (cell) {
|
||||
cell->getStringContent(cellName);
|
||||
|
||||
// getStringContent is addind a ' before the string for whatever reason.
|
||||
if (!cellName.empty() && cellName.front() == '\'') {
|
||||
cellName.erase(0, 1); // Remove the first character if it's a '
|
||||
}
|
||||
}
|
||||
|
||||
return cellName;
|
||||
}
|
||||
|
||||
int BomObject::getColumnIndex(std::string name)
|
||||
{
|
||||
int col = 0;
|
||||
for (auto& columnName : columnsNames.getValues()) {
|
||||
if (columnName == name) {
|
||||
return col;
|
||||
}
|
||||
++col;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
102
src/Mod/Assembly/App/BomObject.h
Normal file
102
src/Mod/Assembly/App/BomObject.h
Normal file
@@ -0,0 +1,102 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2023 Ondsel <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD 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 *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef ASSEMBLY_BomObject_H
|
||||
#define ASSEMBLY_BomObject_H
|
||||
|
||||
#include <App/PropertyFile.h>
|
||||
|
||||
#include <Mod/Assembly/AssemblyGlobal.h>
|
||||
|
||||
#include <Mod/Spreadsheet/App/Sheet.h>
|
||||
#include <App/PropertyLinks.h>
|
||||
|
||||
namespace App
|
||||
{
|
||||
class DocumentObject;
|
||||
}
|
||||
|
||||
namespace Assembly
|
||||
{
|
||||
|
||||
class AssemblyObject;
|
||||
|
||||
class BomDataElement
|
||||
{
|
||||
public:
|
||||
BomDataElement(std::string objName, std::string columnName, std::string value)
|
||||
: objName(objName)
|
||||
, columnName(columnName)
|
||||
, value(value)
|
||||
{}
|
||||
~BomDataElement()
|
||||
{}
|
||||
|
||||
std::string objName;
|
||||
std::string columnName;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
class AssemblyExport BomObject: public Spreadsheet::Sheet
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Assembly::BomObject);
|
||||
|
||||
public:
|
||||
BomObject();
|
||||
~BomObject() override;
|
||||
|
||||
PyObject* getPyObject() override;
|
||||
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "AssemblyGui::ViewProviderBom";
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn* execute() override;
|
||||
|
||||
void generateBOM();
|
||||
void addObjectToBom(App::DocumentObject* obj, size_t row, std::string index);
|
||||
void
|
||||
addObjectChildrenToBom(std::vector<App::DocumentObject*> objs, size_t& row, std::string index);
|
||||
void saveCustomColumnData();
|
||||
|
||||
AssemblyObject* getAssembly();
|
||||
|
||||
bool hasQuantityColumn();
|
||||
int getColumnIndex(std::string name);
|
||||
std::string getText(size_t row, size_t col);
|
||||
|
||||
App::PropertyStringList columnsNames;
|
||||
App::PropertyBool detailSubAssemblies;
|
||||
App::PropertyBool detailParts;
|
||||
App::PropertyBool onlyParts;
|
||||
|
||||
std::vector<BomDataElement> dataElements;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Assembly
|
||||
|
||||
|
||||
#endif // ASSEMBLY_BomObject_H
|
||||
19
src/Mod/Assembly/App/BomObjectPy.xml
Normal file
19
src/Mod/Assembly/App/BomObjectPy.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="SheetPy"
|
||||
Name="BomObjectPy"
|
||||
Twin="BomObject"
|
||||
TwinPointer="BomObject"
|
||||
Include="Mod/Assembly/App/BomObject.h"
|
||||
Namespace="Assembly"
|
||||
FatherInclude="Mod/Spreadsheet/App/SheetPy.h"
|
||||
FatherNamespace="Spreadsheet">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Ondsel" EMail="development@ondsel.com" />
|
||||
<UserDocu>This class is the BOM object of assemblies, it derives from Spreadsheet::Sheet.</UserDocu>
|
||||
</Documentation>
|
||||
|
||||
<CustomAttributes />
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
46
src/Mod/Assembly/App/BomObjectPyImp.cpp
Normal file
46
src/Mod/Assembly/App/BomObjectPyImp.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Boyer Pierre-Louis <development@ondsel> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
// inclusion of the generated files (generated out of BomObject.xml)
|
||||
#include "BomObjectPy.h"
|
||||
#include "BomObjectPy.cpp"
|
||||
|
||||
using namespace Assembly;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string BomObjectPy::representation() const
|
||||
{
|
||||
return {"<Bill of Materials object>"};
|
||||
}
|
||||
|
||||
PyObject* BomObjectPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int BomObjectPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -13,17 +13,24 @@ link_directories(${OCC_LIBRARY_DIR})
|
||||
set(Assembly_LIBS
|
||||
Part
|
||||
PartDesign
|
||||
Spreadsheet
|
||||
FreeCADApp
|
||||
OndselSolver
|
||||
)
|
||||
|
||||
generate_from_xml(AssemblyObjectPy)
|
||||
generate_from_xml(BomObjectPy)
|
||||
generate_from_xml(BomGroupPy)
|
||||
generate_from_xml(JointGroupPy)
|
||||
generate_from_xml(ViewGroupPy)
|
||||
|
||||
SET(Python_SRCS
|
||||
AssemblyObjectPy.xml
|
||||
AssemblyObjectPyImp.cpp
|
||||
BomObjectPy.xml
|
||||
BomObjectPyImp.cpp
|
||||
BomGroupPy.xml
|
||||
BomGroupPyImp.cpp
|
||||
JointGroupPy.xml
|
||||
JointGroupPyImp.cpp
|
||||
ViewGroupPy.xml
|
||||
@@ -42,6 +49,10 @@ SOURCE_GROUP("Module" FILES ${Module_SRCS})
|
||||
SET(Assembly_SRCS
|
||||
AssemblyObject.cpp
|
||||
AssemblyObject.h
|
||||
BomObject.cpp
|
||||
BomObject.h
|
||||
BomGroup.cpp
|
||||
BomGroup.h
|
||||
JointGroup.cpp
|
||||
JointGroup.h
|
||||
ViewGroup.cpp
|
||||
|
||||
@@ -7,6 +7,7 @@ endif(BUILD_GUI)
|
||||
set(Assembly_Scripts
|
||||
Init.py
|
||||
CommandCreateAssembly.py
|
||||
CommandCreateBom.py
|
||||
CommandInsertLink.py
|
||||
CommandSolveAssembly.py
|
||||
CommandCreateJoint.py
|
||||
|
||||
294
src/Mod/Assembly/CommandCreateBom.py
Normal file
294
src/Mod/Assembly/CommandCreateBom.py
Normal file
@@ -0,0 +1,294 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# /**************************************************************************
|
||||
# *
|
||||
# Copyright (c) 2023 Ondsel <development@ondsel.com> *
|
||||
# *
|
||||
# This file is part of FreeCAD. *
|
||||
# *
|
||||
# FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
# under the terms of the GNU Lesser General Public License as *
|
||||
# published by the Free Software Foundation, either version 2.1 of the *
|
||||
# License, or (at your option) any later version. *
|
||||
# *
|
||||
# FreeCAD 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 *
|
||||
# Lesser General Public License for more details. *
|
||||
# *
|
||||
# You should have received a copy of the GNU Lesser General Public *
|
||||
# License along with FreeCAD. If not, see *
|
||||
# <https://www.gnu.org/licenses/>. *
|
||||
# *
|
||||
# **************************************************************************/
|
||||
|
||||
import re
|
||||
import os
|
||||
import FreeCAD as App
|
||||
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
if App.GuiUp:
|
||||
import FreeCADGui as Gui
|
||||
from PySide import QtCore, QtGui, QtWidgets, QtUiTools
|
||||
from PySide.QtWidgets import QPushButton, QMenu
|
||||
|
||||
import UtilsAssembly
|
||||
import Preferences
|
||||
|
||||
# translate = App.Qt.translate
|
||||
|
||||
__title__ = "Assembly Command Create Bill of Materials"
|
||||
__author__ = "Ondsel"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
translate = App.Qt.translate
|
||||
|
||||
TranslatedColumnNames = [
|
||||
translate("Assembly", "Index"),
|
||||
translate("Assembly", "Name"),
|
||||
translate("Assembly", "Description"),
|
||||
translate("Assembly", "File Name"),
|
||||
translate("Assembly", "Quantity"),
|
||||
]
|
||||
|
||||
ColumnNames = [
|
||||
"Index",
|
||||
"Name",
|
||||
"Description",
|
||||
"File Name",
|
||||
"Quantity",
|
||||
]
|
||||
|
||||
|
||||
class CommandCreateBom:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def GetResources(self):
|
||||
return {
|
||||
"Pixmap": "Assembly_BillOfMaterials",
|
||||
"MenuText": QT_TRANSLATE_NOOP("Assembly_BillOfMaterials", "Create Bill of Materials"),
|
||||
"Accel": "O",
|
||||
"ToolTip": "<p>"
|
||||
+ QT_TRANSLATE_NOOP(
|
||||
"Assembly_CreateView",
|
||||
"Create a bill of materials of the current assembly. If an assembly is active, it will be a BOM of this assembly. Else it will be a BOM of the whole document.",
|
||||
)
|
||||
+ "</p><p>"
|
||||
+ QT_TRANSLATE_NOOP(
|
||||
"Assembly_CreateView",
|
||||
"The BOM object is a document object that stores the settings of your BOM. It is also a spreadsheet object so you can easily visualize the bom. If you don't need the BOM object to be saved as a document object, you can simply export and cancel the task.",
|
||||
)
|
||||
+ "</p><p>"
|
||||
+ QT_TRANSLATE_NOOP(
|
||||
"Assembly_CreateView",
|
||||
"The columns 'Index', 'Name', 'File Name' and 'Quantity' are automatically generated on recompute. The 'Description' and custom columns are not overwriten.",
|
||||
)
|
||||
+ "</p>",
|
||||
"CmdType": "ForEdit",
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
return True
|
||||
|
||||
def Activated(self):
|
||||
self.panel = TaskAssemblyCreateBom()
|
||||
Gui.Control.showDialog(self.panel)
|
||||
|
||||
|
||||
######### Create Exploded View Task ###########
|
||||
class TaskAssemblyCreateBom(QtCore.QObject):
|
||||
def __init__(self, bomObj=None):
|
||||
super().__init__()
|
||||
|
||||
self.form = Gui.PySideUic.loadUi(":/panels/TaskAssemblyCreateBom.ui")
|
||||
|
||||
# Set the QListWidget properties to support drag and drop
|
||||
self.form.columnList.setEditTriggers(
|
||||
QtWidgets.QAbstractItemView.DoubleClicked | QtWidgets.QAbstractItemView.EditKeyPressed
|
||||
)
|
||||
self.form.columnList.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
|
||||
self.form.columnList.setDragEnabled(True)
|
||||
self.form.columnList.setAcceptDrops(True)
|
||||
self.form.columnList.setDropIndicatorShown(True)
|
||||
self.form.columnList.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
|
||||
|
||||
self.form.columnList.installEventFilter(self)
|
||||
|
||||
self.form.btnAddColumn.clicked.connect(self.addColumn)
|
||||
self.form.btnExport.clicked.connect(self.export)
|
||||
|
||||
pref = Preferences.preferences()
|
||||
|
||||
if bomObj:
|
||||
App.setActiveTransaction("Edit Bill Of Materials")
|
||||
|
||||
names = []
|
||||
for i in range(len(bomObj.columnsNames)):
|
||||
text = bomObj.columnsNames[i]
|
||||
if text in ColumnNames:
|
||||
index = ColumnNames.index(text)
|
||||
text = TranslatedColumnNames[index]
|
||||
names.append(text)
|
||||
self.form.columnList.addItems(names)
|
||||
|
||||
self.bomObj = bomObj
|
||||
self.form.CheckBox_onlyParts.setChecked(bomObj.onlyParts)
|
||||
self.form.CheckBox_detailParts.setChecked(bomObj.detailParts)
|
||||
self.form.CheckBox_detailSubAssemblies.setChecked(bomObj.detailSubAssemblies)
|
||||
|
||||
else:
|
||||
App.setActiveTransaction("Create Bill Of Materials")
|
||||
self.form.columnList.addItems(TranslatedColumnNames)
|
||||
|
||||
self.createBomObject()
|
||||
self.form.CheckBox_onlyParts.setChecked(pref.GetBool("BOMOnlyParts", False))
|
||||
self.form.CheckBox_detailParts.setChecked(pref.GetBool("BOMDetailParts", True))
|
||||
self.form.CheckBox_detailSubAssemblies.setChecked(
|
||||
pref.GetBool("BOMDetailSubAssemblies", True)
|
||||
)
|
||||
|
||||
self.form.columnList.model().rowsMoved.connect(self.onItemsReordered)
|
||||
self.form.columnList.itemChanged.connect(self.itemUpdated)
|
||||
|
||||
self.form.CheckBox_onlyParts.stateChanged.connect(self.onIncludeSolids)
|
||||
self.form.CheckBox_detailParts.stateChanged.connect(self.onDetailParts)
|
||||
self.form.CheckBox_detailSubAssemblies.stateChanged.connect(self.onDetailSubAssemblies)
|
||||
|
||||
self.updateColumnList()
|
||||
|
||||
def accept(self):
|
||||
self.deactivate()
|
||||
App.closeActiveTransaction()
|
||||
|
||||
self.bomObj.recompute()
|
||||
|
||||
self.bomObj.ViewObject.showSheetMdi()
|
||||
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
self.deactivate()
|
||||
App.closeActiveTransaction(True)
|
||||
return True
|
||||
|
||||
def deactivate(self):
|
||||
pref = Preferences.preferences()
|
||||
pref.SetBool("BOMOnlyParts", self.form.CheckBox_onlyParts.isChecked())
|
||||
pref.SetBool("BOMDetailParts", self.form.CheckBox_detailParts.isChecked())
|
||||
pref.SetBool("BOMDetailSubAssemblies", self.form.CheckBox_detailSubAssemblies.isChecked())
|
||||
|
||||
if Gui.Control.activeDialog():
|
||||
Gui.Control.closeDialog()
|
||||
|
||||
def onIncludeSolids(self, val):
|
||||
self.bomObj.onlyParts = val
|
||||
|
||||
def onDetailParts(self, val):
|
||||
self.bomObj.detailParts = val
|
||||
|
||||
def onDetailSubAssemblies(self, val):
|
||||
self.bomObj.detailSubAssemblies = val
|
||||
|
||||
def addColumn(self):
|
||||
new_name = translate("Assembly", "Default")
|
||||
if self.isNameDuplicate(new_name):
|
||||
# Find a unique name
|
||||
counter = 1
|
||||
while self.isNameDuplicate(f"{new_name}_{counter}"):
|
||||
counter += 1
|
||||
new_name = f"{new_name}_{counter}"
|
||||
|
||||
new_item = QtWidgets.QListWidgetItem(new_name)
|
||||
new_item.setFlags(new_item.flags() | QtCore.Qt.ItemIsEditable)
|
||||
self.form.columnList.addItem(new_item)
|
||||
|
||||
# Ensure the new item is selected and starts editing
|
||||
self.form.columnList.setCurrentItem(new_item)
|
||||
self.form.columnList.editItem(new_item)
|
||||
self.updateColumnList()
|
||||
|
||||
def onItemsReordered(self, parent, start, end, destination, row):
|
||||
self.updateColumnList()
|
||||
|
||||
def updateColumnList(self):
|
||||
if self.bomObj:
|
||||
new_names = []
|
||||
for i in range(self.form.columnList.count()):
|
||||
text = self.form.columnList.item(i).text()
|
||||
if text in TranslatedColumnNames:
|
||||
index = TranslatedColumnNames.index(text)
|
||||
text = ColumnNames[index]
|
||||
new_names.append(text)
|
||||
self.bomObj.columnsNames = new_names
|
||||
|
||||
def itemUpdated(self, item):
|
||||
new_text = item.text()
|
||||
item_row = self.form.columnList.row(item)
|
||||
|
||||
# Check for duplicate names
|
||||
duplicate_found = False
|
||||
for i in range(self.form.columnList.count()):
|
||||
if i != item_row and self.form.columnList.item(i).text() == new_text:
|
||||
duplicate_found = True
|
||||
break
|
||||
|
||||
if duplicate_found:
|
||||
QtWidgets.QMessageBox.warning(
|
||||
self.form,
|
||||
translate("Assembly", "Duplicate Name"),
|
||||
translate("Assembly", "This name is already used. Please choose a different name."),
|
||||
)
|
||||
|
||||
# Revert the change
|
||||
old_text = (
|
||||
self.bomObj.columnsNames[item_row]
|
||||
if self.bomObj and item_row < len(self.bomObj.columnsNames)
|
||||
else ""
|
||||
)
|
||||
item.setText(old_text)
|
||||
else:
|
||||
self.updateColumnList()
|
||||
|
||||
def isNameDuplicate(self, name):
|
||||
for i in range(self.form.columnList.count()):
|
||||
if self.form.columnList.item(i).text() == name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def createBomObject(self):
|
||||
assembly = UtilsAssembly.activeAssembly()
|
||||
if assembly is not None:
|
||||
bom_group = UtilsAssembly.getBomGroup(assembly)
|
||||
self.bomObj = bom_group.newObject("Assembly::BomObject", "Bill of Materials")
|
||||
else:
|
||||
self.bomObj = App.activeDocument().addObject("Assembly::BomObject", "Bill of Materials")
|
||||
|
||||
def export(self):
|
||||
self.bomObj.recompute()
|
||||
self.bomObj.ViewObject.exportAsFile()
|
||||
|
||||
def eventFilter(self, watched, event):
|
||||
if self.form is not None and watched == self.form.columnList:
|
||||
if event.type() == QtCore.QEvent.ShortcutOverride:
|
||||
if event.key() == QtCore.Qt.Key_Delete:
|
||||
event.accept() # Accept the event only if the key is Delete
|
||||
return True # Indicate that the event has been handled
|
||||
return False
|
||||
|
||||
elif event.type() == QtCore.QEvent.KeyPress:
|
||||
if event.key() == QtCore.Qt.Key_Delete:
|
||||
selected_indexes = self.form.columnList.selectedIndexes()
|
||||
items_to_remove = []
|
||||
|
||||
for index in selected_indexes:
|
||||
self.form.columnList.takeItem(index.row())
|
||||
|
||||
self.updateColumnList()
|
||||
return True # Consume the event
|
||||
|
||||
return super().eventFilter(watched, event)
|
||||
|
||||
|
||||
if App.GuiUp:
|
||||
Gui.addCommand("Assembly_CreateBom", CommandCreateBom())
|
||||
@@ -24,9 +24,12 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/PyObjectBase.h>
|
||||
|
||||
#include "ViewProviderAssembly.h"
|
||||
#include "ViewProviderBom.h"
|
||||
#include "ViewProviderBomGroup.h"
|
||||
#include "ViewProviderJointGroup.h"
|
||||
#include "ViewProviderViewGroup.h"
|
||||
|
||||
@@ -39,6 +42,15 @@ extern PyObject* initModule();
|
||||
/* Python entry */
|
||||
PyMOD_INIT_FUNC(AssemblyGui)
|
||||
{
|
||||
// load dependent module
|
||||
try {
|
||||
Base::Interpreter().runString("import SpreadsheetGui");
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
PyErr_SetString(PyExc_ImportError, e.what());
|
||||
PyMOD_Return(nullptr);
|
||||
}
|
||||
|
||||
PyObject* mod = AssemblyGui::initModule();
|
||||
Base::Console().Log("Loading AssemblyGui module... done\n");
|
||||
|
||||
@@ -47,7 +59,9 @@ PyMOD_INIT_FUNC(AssemblyGui)
|
||||
// call PyType_Ready, otherwise we run into a segmentation fault, later on.
|
||||
// This function is responsible for adding inherited slots from a type's base class.
|
||||
|
||||
AssemblyGui::ViewProviderAssembly ::init();
|
||||
AssemblyGui::ViewProviderAssembly::init();
|
||||
AssemblyGui::ViewProviderBom::init();
|
||||
AssemblyGui::ViewProviderBomGroup::init();
|
||||
AssemblyGui::ViewProviderJointGroup::init();
|
||||
AssemblyGui::ViewProviderViewGroup::init();
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ set(AssemblyGui_LIBS
|
||||
Assembly
|
||||
PartDesign
|
||||
PartGui
|
||||
Spreadsheet
|
||||
SpreadsheetGui
|
||||
FreeCADGui
|
||||
)
|
||||
|
||||
@@ -38,6 +40,10 @@ SET(AssemblyGui_SRCS_Module
|
||||
PreCompiled.h
|
||||
ViewProviderAssembly.cpp
|
||||
ViewProviderAssembly.h
|
||||
ViewProviderBom.cpp
|
||||
ViewProviderBom.h
|
||||
ViewProviderBomGroup.cpp
|
||||
ViewProviderBomGroup.h
|
||||
ViewProviderJointGroup.cpp
|
||||
ViewProviderJointGroup.h
|
||||
ViewProviderViewGroup.cpp
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<file>icons/Assembly_InsertLink.svg</file>
|
||||
<file>icons/preferences-assembly.svg</file>
|
||||
<file>icons/Assembly_ToggleGrounded.svg</file>
|
||||
<file>icons/Assembly_BillOfMaterials.svg</file>
|
||||
<file>icons/Assembly_BillOfMaterialsGroup.svg</file>
|
||||
<file>icons/Assembly_CreateJointAngle.svg</file>
|
||||
<file>icons/Assembly_CreateJointBall.svg</file>
|
||||
<file>icons/Assembly_CreateJointCylindrical.svg</file>
|
||||
@@ -22,6 +24,7 @@
|
||||
<file>icons/Assembly_JointGroup.svg</file>
|
||||
<file>icons/Assembly_ExplodedView.svg</file>
|
||||
<file>icons/Assembly_ExplodedViewGroup.svg</file>
|
||||
<file>panels/TaskAssemblyCreateBom.ui</file>
|
||||
<file>panels/TaskAssemblyCreateJoint.ui</file>
|
||||
<file>panels/TaskAssemblyInsertLink.ui</file>
|
||||
<file>panels/TaskAssemblyCreateView.ui</file>
|
||||
|
||||
@@ -0,0 +1,600 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="64"
|
||||
height="64"
|
||||
viewBox="0 0 16.933333 16.933333"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.1-beta1 (77e7b44db3, 2021-03-28)"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="Assembly_BillOfMaterials.svg"
|
||||
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"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="false"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:document-units="px"
|
||||
showgrid="true"
|
||||
inkscape:zoom="8"
|
||||
inkscape:cx="60.4375"
|
||||
inkscape:cy="43.4375"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="1571"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1"
|
||||
objecttolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
guidetolerance="10.0"
|
||||
inkscape:pageshadow="0"><inkscape:grid
|
||||
id="grid1"
|
||||
units="px"
|
||||
originx="0"
|
||||
originy="0"
|
||||
spacingx="0.26458333"
|
||||
spacingy="0.26458333"
|
||||
empcolor="#0099e5"
|
||||
empopacity="0.30196078"
|
||||
color="#0099e5"
|
||||
opacity="0.14901961"
|
||||
empspacing="5"
|
||||
dotted="false"
|
||||
gridanglex="30"
|
||||
gridanglez="30"
|
||||
visible="true" /></sodipodi:namedview><defs
|
||||
id="defs1"><linearGradient
|
||||
id="swatch2"
|
||||
inkscape:swatch="solid"><stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4" /></linearGradient><linearGradient
|
||||
id="swatch7"
|
||||
inkscape:swatch="solid"><stop
|
||||
style="stop-color:#292600;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop7" /></linearGradient><linearGradient
|
||||
id="swatch3"
|
||||
inkscape:swatch="solid"><stop
|
||||
style="stop-color:#2b2800;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3" /></linearGradient><linearGradient
|
||||
id="linearGradient1"
|
||||
inkscape:swatch="gradient"><stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1" /><stop
|
||||
style="stop-color:#ffdd00;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop2" /></linearGradient><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377"
|
||||
id="radialGradient3692"
|
||||
cx="45.883327"
|
||||
cy="28.869568"
|
||||
fx="45.883327"
|
||||
fy="28.869568"
|
||||
r="19.467436"
|
||||
gradientUnits="userSpaceOnUse" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377"
|
||||
id="radialGradient3703"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="135.38333"
|
||||
cy="97.369568"
|
||||
fx="135.38333"
|
||||
fy="97.369568"
|
||||
r="19.467436"
|
||||
gradientTransform="matrix(0.97435,0.2250379,-0.4623105,2.0016728,48.487554,-127.99883)" /><linearGradient
|
||||
id="linearGradient3377"><stop
|
||||
id="stop3379"
|
||||
offset="0"
|
||||
style="stop-color:#faff2b;stop-opacity:1;" /><stop
|
||||
id="stop3381"
|
||||
offset="1"
|
||||
style="stop-color:#ffaa00;stop-opacity:1;" /></linearGradient><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377"
|
||||
id="radialGradient3705"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="148.88333"
|
||||
cy="81.869568"
|
||||
fx="148.88333"
|
||||
fy="81.869568"
|
||||
r="19.467436"
|
||||
gradientTransform="matrix(1.3852588,-0.05136783,0.03705629,0.9993132,-60.392403,7.7040438)" /><inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2868" /><marker
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker3034"
|
||||
style="overflow:visible"><path
|
||||
id="path3032"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)" /></marker><marker
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker2976"
|
||||
style="overflow:visible"><path
|
||||
id="path2974"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
transform="matrix(0.4,0,0,0.4,4,0)" /></marker><marker
|
||||
style="overflow:visible"
|
||||
id="Arrow1Sstart"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"><path
|
||||
transform="matrix(0.2,0,0,0.2,1.2,0)"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
id="path839" /></marker><linearGradient
|
||||
id="linearGradient3794"><stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3796" /><stop
|
||||
style="stop-color:#000000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3798" /></linearGradient><linearGradient
|
||||
id="linearGradient3864"><stop
|
||||
id="stop3866"
|
||||
offset="0"
|
||||
style="stop-color:#71b2f8;stop-opacity:1;" /><stop
|
||||
id="stop3868"
|
||||
offset="1"
|
||||
style="stop-color:#002795;stop-opacity:1;" /></linearGradient><linearGradient
|
||||
id="linearGradient3767"><stop
|
||||
style="stop-color:#3465a4;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3769" /><stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3771" /></linearGradient><linearGradient
|
||||
id="linearGradient3777"><stop
|
||||
style="stop-color:#204a87;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3779" /><stop
|
||||
style="stop-color:#3465a4;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3781" /></linearGradient><radialGradient
|
||||
xlink:href="#linearGradient3794"
|
||||
id="radialGradient3800"
|
||||
cx="1"
|
||||
cy="45"
|
||||
fx="1"
|
||||
fy="45"
|
||||
r="41"
|
||||
gradientTransform="matrix(0.93348213,-2.2905276e-8,0,0.28687573,0.06651751,32.090592)"
|
||||
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||
y2="21.83742"
|
||||
x2="47.502235"
|
||||
y1="51.179787"
|
||||
x1="53.896763"
|
||||
gradientTransform="matrix(0.66145831,-0.38958979,0,0.63269947,49.344787,283.66808)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient1141"
|
||||
xlink:href="#linearGradient3777" /><linearGradient
|
||||
y2="21.31134"
|
||||
x2="17.328547"
|
||||
y1="55.717518"
|
||||
x1="22.116516"
|
||||
gradientTransform="matrix(2.882353,0.59358255,0,2.3181818,136.36158,-174.5987)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient1143"
|
||||
xlink:href="#linearGradient3767" /><linearGradient
|
||||
y2="21.31134"
|
||||
x2="17.328547"
|
||||
y1="55.717518"
|
||||
x1="22.116516"
|
||||
gradientTransform="matrix(0.76262255,0.15705205,0,0.61335226,45.601725,262.63108)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient1148"
|
||||
xlink:href="#linearGradient3767" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient3850"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.6028459,1.0471639,-1.9794021,1.1395295,127.9588,-74.456907)"
|
||||
cx="51.328892"
|
||||
cy="31.074146"
|
||||
fx="51.328892"
|
||||
fy="31.074146"
|
||||
r="19.571428" /><inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2988" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377-6"
|
||||
id="radialGradient3699"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="76.383331"
|
||||
cy="94.369568"
|
||||
fx="76.383331"
|
||||
fy="94.369568"
|
||||
r="19.467436"
|
||||
gradientTransform="matrix(0.9818943,0.1894295,-0.4109427,2.1300924,40.163453,-121.11559)" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377"
|
||||
id="radialGradient3701"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="84.883324"
|
||||
cy="77.042847"
|
||||
fx="84.883324"
|
||||
fy="77.042847"
|
||||
r="19.467436"
|
||||
gradientTransform="matrix(2.8492421,1.2585119,-0.4040415,0.9147407,-125.84131,-100.25805)" /><radialGradient
|
||||
r="19.467436"
|
||||
fy="77.042847"
|
||||
fx="84.883324"
|
||||
cy="77.042847"
|
||||
cx="84.883324"
|
||||
gradientTransform="matrix(2.8492421,1.2585119,-0.4040415,0.9147407,-125.84131,-100.25805)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3017"
|
||||
xlink:href="#linearGradient3377-6"
|
||||
inkscape:collect="always" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377-6"
|
||||
id="radialGradient3699-2"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="76.383331"
|
||||
cy="94.369568"
|
||||
fx="76.383331"
|
||||
fy="94.369568"
|
||||
r="19.467436"
|
||||
gradientTransform="matrix(0.9818943,0.1894295,-0.4109427,2.1300924,40.163453,-121.11559)" /><linearGradient
|
||||
id="linearGradient3377-6"><stop
|
||||
id="stop3379-2"
|
||||
offset="0"
|
||||
style="stop-color:#00afff;stop-opacity:1;" /><stop
|
||||
id="stop3381-4"
|
||||
offset="1"
|
||||
style="stop-color:#0034ff;stop-opacity:1;" /></linearGradient><radialGradient
|
||||
r="19.467436"
|
||||
fy="77.042847"
|
||||
fx="84.883324"
|
||||
cy="77.042847"
|
||||
cx="84.883324"
|
||||
gradientTransform="matrix(2.8492421,1.2585119,-0.4040415,0.9147407,-125.84131,-100.25805)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3017-8"
|
||||
xlink:href="#linearGradient3377-6"
|
||||
inkscape:collect="always" /><radialGradient
|
||||
r="19.467436"
|
||||
fy="77.042847"
|
||||
fx="84.883324"
|
||||
cy="77.042847"
|
||||
cx="84.883324"
|
||||
gradientTransform="matrix(2.8492421,1.2585119,-0.4040415,0.9147407,-125.84131,-100.25805)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3844"
|
||||
xlink:href="#linearGradient3377-6"
|
||||
inkscape:collect="always" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377-6"
|
||||
id="radialGradient3699-7"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="76.383331"
|
||||
cy="94.369568"
|
||||
fx="76.383331"
|
||||
fy="94.369568"
|
||||
r="19.467436"
|
||||
gradientTransform="matrix(0.9818943,0.1894295,-0.4109427,2.1300924,40.163453,-121.11559)" /><radialGradient
|
||||
r="19.467436"
|
||||
fy="77.042847"
|
||||
fx="84.883324"
|
||||
cy="77.042847"
|
||||
cx="84.883324"
|
||||
gradientTransform="matrix(2.8492421,1.2585119,-0.4040415,0.9147407,-125.84131,-100.25805)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3017-6"
|
||||
xlink:href="#linearGradient3377"
|
||||
inkscape:collect="always" /><radialGradient
|
||||
r="19.467436"
|
||||
fy="77.042847"
|
||||
fx="84.883324"
|
||||
cy="77.042847"
|
||||
cx="84.883324"
|
||||
gradientTransform="matrix(2.8492421,1.2585119,-0.4040415,0.9147407,-125.84131,-100.25805)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3844-7"
|
||||
xlink:href="#linearGradient3377-6"
|
||||
inkscape:collect="always" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient4112"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-0.19157613,0.46621455,-1.1364164,-0.41904304,156.5648,24.076707)"
|
||||
cx="86.836884"
|
||||
cy="90.601151"
|
||||
fx="86.836884"
|
||||
fy="90.601151"
|
||||
r="19.467436" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient4114"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.19036833,-0.61386357,1.99853,-0.19092801,-47.133199,165.45559)"
|
||||
cx="113.50187"
|
||||
cy="65.849281"
|
||||
fx="113.50187"
|
||||
fy="65.849281"
|
||||
r="19.467436" /><radialGradient
|
||||
r="19.467436"
|
||||
fy="65.849281"
|
||||
fx="113.50187"
|
||||
cy="65.849281"
|
||||
cx="113.50187"
|
||||
gradientTransform="matrix(0.19036833,-0.61386357,1.99853,-0.19092801,-47.133199,165.45559)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3180"
|
||||
xlink:href="#linearGradient3864"
|
||||
inkscape:collect="always" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient4112-9"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-0.19157613,0.46621455,-1.1364164,-0.41904304,162.99236,26.56694)"
|
||||
cx="86.836884"
|
||||
cy="90.601151"
|
||||
fx="86.836884"
|
||||
fy="90.601151"
|
||||
r="19.467436" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient4114-3"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.19036833,-0.61386357,1.99853,-0.19092801,-47.133199,165.45559)"
|
||||
cx="113.50187"
|
||||
cy="65.849281"
|
||||
fx="113.50187"
|
||||
fy="65.849281"
|
||||
r="19.467436" /><radialGradient
|
||||
r="19.467436"
|
||||
fy="65.849281"
|
||||
fx="113.50187"
|
||||
cy="65.849281"
|
||||
cx="113.50187"
|
||||
gradientTransform="matrix(0.19036833,-0.61386357,1.99853,-0.19092801,-47.133199,165.45559)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3180-6"
|
||||
xlink:href="#linearGradient3864"
|
||||
inkscape:collect="always" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient4112-7"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-0.19157613,0.46621455,-1.1364164,-0.41904304,156.5648,24.076707)"
|
||||
cx="86.836884"
|
||||
cy="90.601151"
|
||||
fx="86.836884"
|
||||
fy="90.601151"
|
||||
r="19.467436" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient4114-9"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.19036833,-0.61386357,1.99853,-0.19092801,-47.133199,165.45559)"
|
||||
cx="113.50187"
|
||||
cy="65.849281"
|
||||
fx="113.50187"
|
||||
fy="65.849281"
|
||||
r="19.467436" /><radialGradient
|
||||
r="19.467436"
|
||||
fy="65.849281"
|
||||
fx="113.50187"
|
||||
cy="65.849281"
|
||||
cx="113.50187"
|
||||
gradientTransform="matrix(0.19036833,-0.61386357,1.99853,-0.19092801,-47.133199,165.45559)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3180-9"
|
||||
xlink:href="#linearGradient3864"
|
||||
inkscape:collect="always" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3864"
|
||||
id="linearGradient3822"
|
||||
x1="154.13527"
|
||||
y1="33.267025"
|
||||
x2="165.61629"
|
||||
y2="46.429642"
|
||||
gradientUnits="userSpaceOnUse" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient3703-5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="132.70454"
|
||||
cy="90.193245"
|
||||
fx="132.70454"
|
||||
fy="90.193245"
|
||||
r="19.467436"
|
||||
gradientTransform="matrix(-0.08162339,1.3949072,-1.1572569,-0.26963374,245.22773,-105.44363)" /><radialGradient
|
||||
r="19.467436"
|
||||
fy="90.193245"
|
||||
fx="132.70454"
|
||||
cy="90.193245"
|
||||
cx="132.70454"
|
||||
gradientTransform="matrix(-0.08162339,1.3949072,-1.1572569,-0.26963374,245.22773,-105.44363)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3294"
|
||||
xlink:href="#linearGradient3864"
|
||||
inkscape:collect="always" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4023"
|
||||
id="linearGradient4029"
|
||||
x1="45"
|
||||
y1="34"
|
||||
x2="50"
|
||||
y2="59"
|
||||
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4023"><stop
|
||||
style="stop-color:#8ae234;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4025" /><stop
|
||||
style="stop-color:#4e9a06;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4027" /></linearGradient><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3801-6-1"
|
||||
id="linearGradient3807-3-9"
|
||||
x1="110"
|
||||
y1="35"
|
||||
x2="85"
|
||||
y2="35"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
spreadMethod="reflect"
|
||||
gradientTransform="matrix(0.45833337,0,0,0.51724135,7.374997,5.432404)" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3801-6-1"><stop
|
||||
style="stop-color:#204a87;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3803-7-2" /><stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3805-5-7" /></linearGradient><linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3801-6"><stop
|
||||
style="stop-color:#c4a000;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3803-7" /><stop
|
||||
style="stop-color:#fce94f;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3805-5" /></linearGradient><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3801-6"
|
||||
id="linearGradient3807-3-9-3"
|
||||
x1="110"
|
||||
y1="35"
|
||||
x2="85"
|
||||
y2="35"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
spreadMethod="reflect"
|
||||
gradientTransform="matrix(0.45833337,0,0,0.51724135,7.374996,33.448275)" /><linearGradient
|
||||
id="linearGradient4389"
|
||||
x1="20.244"
|
||||
x2="17.244"
|
||||
y1="37.588"
|
||||
y2="27.588"
|
||||
gradientTransform="translate(-1.2435,-2.5881)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient3774" /><linearGradient
|
||||
id="linearGradient4399"
|
||||
x1="48.714"
|
||||
x2="44.714"
|
||||
y1="45.586"
|
||||
y2="34.586"
|
||||
gradientTransform="translate(1.2856,1.4142)"
|
||||
gradientUnits="userSpaceOnUse"><stop
|
||||
stop-color="#c4a000"
|
||||
offset="0"
|
||||
id="stop8" /><stop
|
||||
stop-color="#edd400"
|
||||
offset="1"
|
||||
id="stop10" /></linearGradient><linearGradient
|
||||
id="linearGradient69042"
|
||||
x1="48.714"
|
||||
x2="44.714"
|
||||
y1="45.586"
|
||||
y2="34.586"
|
||||
gradientTransform="translate(-12.714,-17.586)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient3774" /><linearGradient
|
||||
id="linearGradient69056"
|
||||
x1="27.244"
|
||||
x2="22.244"
|
||||
y1="54.588"
|
||||
y2="40.588"
|
||||
gradientTransform="translate(-1.2435,-2.5881)"
|
||||
gradientUnits="userSpaceOnUse"><stop
|
||||
stop-color="#c4a000"
|
||||
offset="0"
|
||||
id="stop14" /><stop
|
||||
stop-color="#fce94f"
|
||||
offset="1"
|
||||
id="stop16" /></linearGradient><linearGradient
|
||||
id="linearGradient69709"
|
||||
x1="20.244"
|
||||
x2="17.244"
|
||||
y1="37.588"
|
||||
y2="27.588"
|
||||
gradientTransform="matrix(1,-0.026667,0,1,81.696,-5.3735)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient3767" /><linearGradient
|
||||
id="linearGradient69717"
|
||||
x1="50.714"
|
||||
x2="48.714"
|
||||
y1="25.586"
|
||||
y2="20.586"
|
||||
gradientTransform="translate(61.2256,1.0356)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient3767" /><linearGradient
|
||||
id="linearGradient3774"><stop
|
||||
stop-color="#4e9a06"
|
||||
offset="0"
|
||||
id="stop21" /><stop
|
||||
stop-color="#8ae234"
|
||||
offset="1"
|
||||
id="stop23" /></linearGradient></defs><g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"><g
|
||||
id="layer1-2"
|
||||
inkscape:label="Layer 1"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,-2.1375e-7,1.8190105)"
|
||||
style="fill:#cccccc"><rect
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#cccccc;stroke:#2e3436;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:accumulate"
|
||||
id="rect3002-9"
|
||||
width="56"
|
||||
height="44"
|
||||
x="4"
|
||||
y="8" /><rect
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
id="rect3002-9-3"
|
||||
width="54"
|
||||
height="42"
|
||||
x="5"
|
||||
y="9" /><path
|
||||
style="fill:#cccccc;stroke:#2e3436;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 3,18 H 61"
|
||||
id="path3790"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:#cccccc;stroke:#2e3436;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 22,6 V 54"
|
||||
id="path3792"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:#cccccc;stroke:#2e3436;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 3,30 H 61"
|
||||
id="path3794"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:#cccccc;stroke:#2e3436;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 3,42 H 61"
|
||||
id="path3796"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" /></g><rect
|
||||
style="fill:#217844;fill-opacity:1;stroke:#2e3436;stroke-width:0.813824;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||
id="rect6"
|
||||
width="15.08098"
|
||||
height="2.6350014"
|
||||
x="0.92617661"
|
||||
y="1.1682484" /></g></svg>
|
||||
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,298 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="64"
|
||||
height="64"
|
||||
version="1.1"
|
||||
viewBox="0 0 64 64"
|
||||
id="svg96"
|
||||
sodipodi:docname="Assembly_BillOfMaterialsGroup.svg"
|
||||
inkscape:version="1.1-beta1 (77e7b44db3, 2021-03-28)"
|
||||
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="namedview68"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
objecttolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
guidetolerance="10.0"
|
||||
inkscape:pageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.8828125"
|
||||
inkscape:cx="-24.563081"
|
||||
inkscape:cy="18.273572"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="1571"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg96" />
|
||||
<defs
|
||||
id="defs26">
|
||||
<linearGradient
|
||||
id="linearGradient1">
|
||||
<stop
|
||||
style="stop-color:#efdc3d;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1" />
|
||||
<stop
|
||||
style="stop-color:#bba80d;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4383">
|
||||
<stop
|
||||
stop-color="#3465a4"
|
||||
offset="0"
|
||||
id="stop2" />
|
||||
<stop
|
||||
stop-color="#729fcf"
|
||||
offset="1"
|
||||
id="stop4" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4399"
|
||||
x1="48.714"
|
||||
x2="44.714"
|
||||
y1="45.586"
|
||||
y2="34.586"
|
||||
gradientTransform="translate(1.2856,1.4142)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#c4a000"
|
||||
offset="0"
|
||||
id="stop8" />
|
||||
<stop
|
||||
stop-color="#edd400"
|
||||
offset="1"
|
||||
id="stop10" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient69056"
|
||||
x1="27.244"
|
||||
x2="22.244"
|
||||
y1="54.588"
|
||||
y2="40.588"
|
||||
gradientTransform="translate(-1.2435,-2.5881)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#c4a000"
|
||||
offset="0"
|
||||
id="stop14" />
|
||||
<stop
|
||||
stop-color="#fce94f"
|
||||
offset="1"
|
||||
id="stop16" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3774">
|
||||
<stop
|
||||
stop-color="#4e9a06"
|
||||
offset="0"
|
||||
id="stop21" />
|
||||
<stop
|
||||
stop-color="#8ae234"
|
||||
offset="1"
|
||||
id="stop23" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient4383"
|
||||
id="linearGradient9"
|
||||
x1="32"
|
||||
y1="64"
|
||||
x2="32"
|
||||
y2="14.419661"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient4399"
|
||||
id="linearGradient13"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(1.2856,1.4142)"
|
||||
x1="48.714"
|
||||
y1="45.586"
|
||||
x2="44.714"
|
||||
y2="34.586" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient1"
|
||||
id="linearGradient14"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="8.000092"
|
||||
y1="31.5"
|
||||
x2="55.999914"
|
||||
y2="31.5" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient3774"
|
||||
id="linearGradient15"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-1.2435,-2.5881)"
|
||||
x1="20.244"
|
||||
y1="37.588"
|
||||
x2="17.244"
|
||||
y2="27.588" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient3774"
|
||||
id="linearGradient16"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-12.714,-17.586)"
|
||||
x1="48.714"
|
||||
y1="45.586"
|
||||
x2="44.714"
|
||||
y2="34.586" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient69056"
|
||||
id="linearGradient17"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-41.2435,-2.5881)"
|
||||
x1="20.243999"
|
||||
y1="37.588001"
|
||||
x2="17.243999"
|
||||
y2="27.587999" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient4399"
|
||||
id="linearGradient18"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-52.714,-17.586)"
|
||||
x1="48.714001"
|
||||
y1="45.585999"
|
||||
x2="44.714001"
|
||||
y2="34.585999" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient4383"
|
||||
id="linearGradient19"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,-0.026667,0,1,81.696,-5.3735)"
|
||||
x1="20.244"
|
||||
y1="37.588"
|
||||
x2="17.244"
|
||||
y2="27.588" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient4383"
|
||||
id="linearGradient20"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(61.2256,1.0356)"
|
||||
x1="50.714"
|
||||
y1="25.586"
|
||||
x2="48.714"
|
||||
y2="20.586" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient69056"
|
||||
id="linearGradient21"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-1.2435,-2.5881)"
|
||||
x1="27.244"
|
||||
y1="54.588"
|
||||
x2="22.244"
|
||||
y2="40.588" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata28">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:date>2015-07-04</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-Stock.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer3"
|
||||
style="display:inline">
|
||||
<path
|
||||
style="fill:#204a87;fill-opacity:1;stroke:#0c1522;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
id="path4"
|
||||
d="M 29.921921,10.073012 26.993293,6.1977395 C 26.21651,5.1698698 25.163057,4.5924975 24.064598,4.5924975 H 5.0714589 c -1.1437425,0 -2.0708717,1.2268134 -2.0708717,2.740257 V 58.484215 c 0,0.504481 0.309043,0.913419 0.6902905,0.913419 H 60.294706 c 0.381247,0 0.690291,-0.408938 0.690291,-0.913419 V 12.813269 c 0,-1.513445 -0.927129,-2.740257 -2.070872,-2.740257 z" />
|
||||
<path
|
||||
style="fill:#204a87;fill-opacity:1;stroke:#3465a4;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
id="path7"
|
||||
d="M 5.2089844,6.5917969 H 24.064453 c 0.375444,0 0.874561,0.2026195 1.333984,0.8105468 l 3.527344,4.6699223 h 29.84961 c 0.0082,0.01044 0.01784,0.02289 0.02734,0.03711 0.01056,0.0158 0.02193,0.03237 0.0332,0.05273 0.08049,0.145363 0.148438,0.361331 0.148438,0.650391 v 44.58594 H 5 V 7.3320312 C 5,7.0436394 5.0678061,6.828994 5.1484375,6.6835937 c 0.011294,-0.020366 0.022609,-0.038859 0.033203,-0.054687 0.00953,-0.014245 0.019073,-0.026632 0.027344,-0.03711 z" />
|
||||
<path
|
||||
style="fill:#729fcf;fill-opacity:1;stroke:#0c1522;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
id="path6-0"
|
||||
d="m 29.919347,14.419661 -2.927223,3.534545 C 26.215716,18.891703 25.16247,19.41831 24.064012,19.41831 H 3.0000008 l 0.015588,39.156085 c 2.171e-4,0.460126 0.3093777,0.833108 0.6906252,0.833108 h 56.603828 c 0.381248,0 0.690139,-0.372982 0.689957,-0.833108 L 60.983419,16.918986 C 60.982865,15.538609 60.055293,14.419661 58.91155,14.419661 H 29.919344 Z" />
|
||||
<path
|
||||
style="fill:url(#linearGradient9);fill-opacity:1;stroke:#729fcf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
id="path8"
|
||||
d="m 30.861328,16.419922 h 28.050781 c 0,0 0.07225,0.463543 0.07227,0.5 L 59,57.408203 H 5.015625 L 5,21.417969 h 19.064453 c 1.756119,0 3.349555,-0.836095 4.46875,-2.1875 z" />
|
||||
</g>
|
||||
<g
|
||||
id="layer1-2"
|
||||
inkscape:label="Layer 1"
|
||||
transform="matrix(0.61968135,0,0,0.56329122,15.349257,25.353936)"
|
||||
style="fill:#cccccc">
|
||||
<rect
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#cccccc;stroke:#2e3436;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:accumulate"
|
||||
id="rect3002-9"
|
||||
width="56"
|
||||
height="44"
|
||||
x="4"
|
||||
y="8" />
|
||||
<rect
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
id="rect3002-9-3"
|
||||
width="54"
|
||||
height="42"
|
||||
x="5"
|
||||
y="9" />
|
||||
<path
|
||||
style="fill:#cccccc;stroke:#2e3436;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 3,18 H 61"
|
||||
id="path3790"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:#cccccc;stroke:#2e3436;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 22,6 V 54"
|
||||
id="path3792"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:#cccccc;stroke:#2e3436;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 3,30 H 61"
|
||||
id="path3794"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:#cccccc;stroke:#2e3436;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 3,42 H 61"
|
||||
id="path3796"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
<rect
|
||||
style="fill:#217844;fill-opacity:1;stroke:#2e3436;stroke-width:1.81727;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||
id="rect6"
|
||||
width="35.321205"
|
||||
height="5.6098514"
|
||||
x="17.518461"
|
||||
y="23.968481" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
114
src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateBom.ui
Normal file
114
src/Mod/Assembly/Gui/Resources/panels/TaskAssemblyCreateBom.ui
Normal file
@@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TaskAssemblyCreateView</class>
|
||||
<widget class="QWidget" name="TaskAssemblyCreateBom">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>376</width>
|
||||
<height>387</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create Bill Of Materials</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="Gui::PrefCheckBox" name="CheckBox_detailSubAssemblies">
|
||||
<property name="toolTip">
|
||||
<string>If checked, Sub assemblies sub-components will be added to the bill of materials.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Detail sub-assemblies</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>BOMDetailSubAssemblies</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Assembly</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="Gui::PrefCheckBox" name="CheckBox_detailParts">
|
||||
<property name="toolTip">
|
||||
<string>If checked, Parts sub-components will be added to the bill of materials.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Detail parts</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>BOMDetailParts</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Assembly</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="Gui::PrefCheckBox" name="CheckBox_onlyParts">
|
||||
<property name="toolTip">
|
||||
<string>If checked, only Part containers will be added to the bill of materials. Solids like PartDesign Bodies will be ignored.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Only parts</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>BOMOnlyParts</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Assembly</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_1">
|
||||
<property name="toolTip">
|
||||
<string>Columns of the bill of materials</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Columns</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QListWidget" name="columnList"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="btnAddColumn">
|
||||
<property name="text">
|
||||
<string>Add column</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QPushButton" name="btnExport">
|
||||
<property name="text">
|
||||
<string>Export</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Gui::PrefCheckBox</class>
|
||||
<extends>QCheckBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
85
src/Mod/Assembly/Gui/ViewProviderBom.cpp
Normal file
85
src/Mod/Assembly/Gui/ViewProviderBom.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2023 Ondsel <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD 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 *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/BitmapFactory.h>
|
||||
|
||||
#include <Base/Interpreter.h>
|
||||
|
||||
#include "ViewProviderBom.h"
|
||||
|
||||
using namespace AssemblyGui;
|
||||
|
||||
PROPERTY_SOURCE(AssemblyGui::ViewProviderBom, SpreadsheetGui::ViewProviderSheet)
|
||||
|
||||
ViewProviderBom::ViewProviderBom()
|
||||
{}
|
||||
|
||||
ViewProviderBom::~ViewProviderBom() = default;
|
||||
|
||||
QIcon ViewProviderBom::getIcon() const
|
||||
{
|
||||
return Gui::BitmapFactory().pixmap("Assembly_BillOfMaterials.svg");
|
||||
}
|
||||
|
||||
bool ViewProviderBom::doubleClicked()
|
||||
{
|
||||
try {
|
||||
// Ensure the Python interpreter is initialized
|
||||
if (!Py_IsInitialized()) {
|
||||
Py_Initialize();
|
||||
}
|
||||
|
||||
// Acquire the GIL (Global Interpreter Lock)
|
||||
PyGILState_STATE gstate;
|
||||
gstate = PyGILState_Ensure();
|
||||
std::string obj_name = getObject()->getNameInDocument();
|
||||
std::string doc_name = getObject()->getDocument()->getName();
|
||||
|
||||
// Call the Python function
|
||||
std::string pythonCommand = "import CommandCreateBom\n"
|
||||
"obj = App.getDocument('"
|
||||
+ doc_name + "').getObject('" + obj_name
|
||||
+ "')\n"
|
||||
"Gui.Control.showDialog(CommandCreateBom.TaskAssemblyCreateBom(obj))";
|
||||
|
||||
PyRun_SimpleString(pythonCommand.c_str());
|
||||
|
||||
// Release the GIL
|
||||
PyGILState_Release(gstate);
|
||||
}
|
||||
catch (...) {
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
51
src/Mod/Assembly/Gui/ViewProviderBom.h
Normal file
51
src/Mod/Assembly/Gui/ViewProviderBom.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2023 Ondsel <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD 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 *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ASSEMBLYGUI_VIEWPROVIDER_ViewProviderBom_H
|
||||
#define ASSEMBLYGUI_VIEWPROVIDER_ViewProviderBom_H
|
||||
|
||||
#include <Mod/Assembly/AssemblyGlobal.h>
|
||||
|
||||
#include <Mod/Spreadsheet/Gui/ViewProviderSpreadsheet.h>
|
||||
|
||||
|
||||
namespace AssemblyGui
|
||||
{
|
||||
|
||||
class AssemblyGuiExport ViewProviderBom: public SpreadsheetGui::ViewProviderSheet
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(AssemblyGui::ViewProviderBom);
|
||||
|
||||
|
||||
public:
|
||||
ViewProviderBom();
|
||||
~ViewProviderBom() override;
|
||||
|
||||
QIcon getIcon() const override;
|
||||
|
||||
bool doubleClicked() override;
|
||||
};
|
||||
|
||||
} // namespace AssemblyGui
|
||||
|
||||
#endif // ASSEMBLYGUI_VIEWPROVIDER_ViewProviderBom_H
|
||||
49
src/Mod/Assembly/Gui/ViewProviderBomGroup.cpp
Normal file
49
src/Mod/Assembly/Gui/ViewProviderBomGroup.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2023 Ondsel <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD 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 *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/BitmapFactory.h>
|
||||
|
||||
#include "ViewProviderBomGroup.h"
|
||||
|
||||
|
||||
using namespace AssemblyGui;
|
||||
|
||||
PROPERTY_SOURCE(AssemblyGui::ViewProviderBomGroup, Gui::ViewProviderDocumentObjectGroup)
|
||||
|
||||
ViewProviderBomGroup::ViewProviderBomGroup()
|
||||
{}
|
||||
|
||||
ViewProviderBomGroup::~ViewProviderBomGroup() = default;
|
||||
|
||||
QIcon ViewProviderBomGroup::getIcon() const
|
||||
{
|
||||
return Gui::BitmapFactory().pixmap("Assembly_BillOfMaterialsGroup.svg");
|
||||
}
|
||||
67
src/Mod/Assembly/Gui/ViewProviderBomGroup.h
Normal file
67
src/Mod/Assembly/Gui/ViewProviderBomGroup.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2023 Ondsel <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD 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 *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ASSEMBLYGUI_VIEWPROVIDER_ViewProviderBomGroup_H
|
||||
#define ASSEMBLYGUI_VIEWPROVIDER_ViewProviderBomGroup_H
|
||||
|
||||
#include <Mod/Assembly/AssemblyGlobal.h>
|
||||
|
||||
#include <Gui/ViewProviderDocumentObjectGroup.h>
|
||||
|
||||
|
||||
namespace AssemblyGui
|
||||
{
|
||||
|
||||
class AssemblyGuiExport ViewProviderBomGroup: public Gui::ViewProviderDocumentObjectGroup
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(AssemblyGui::ViewProviderBomGroup);
|
||||
|
||||
public:
|
||||
ViewProviderBomGroup();
|
||||
~ViewProviderBomGroup() override;
|
||||
|
||||
/// deliver the icon shown in the tree view. Override from ViewProvider.h
|
||||
QIcon getIcon() const override;
|
||||
|
||||
// Prevent dragging of the joints and dropping things inside the joint group.
|
||||
bool canDragObjects() const override
|
||||
{
|
||||
return false;
|
||||
};
|
||||
bool canDropObjects() const override
|
||||
{
|
||||
return false;
|
||||
};
|
||||
bool canDragAndDropObject(App::DocumentObject*) const override
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
// protected:
|
||||
/// get called by the container whenever a property has been changed
|
||||
// void onChanged(const App::Property* prop) override;
|
||||
};
|
||||
|
||||
} // namespace AssemblyGui
|
||||
|
||||
#endif // ASSEMBLYGUI_VIEWPROVIDER_ViewProviderBomGroup_H
|
||||
@@ -63,7 +63,7 @@ class AssemblyWorkbench(Workbench):
|
||||
# load the builtin modules
|
||||
from PySide import QtCore, QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import CommandCreateAssembly, CommandInsertLink, CommandCreateJoint, CommandSolveAssembly, CommandExportASMT, CommandCreateView
|
||||
import CommandCreateAssembly, CommandInsertLink, CommandCreateJoint, CommandSolveAssembly, CommandExportASMT, CommandCreateView, CommandCreateBom
|
||||
import Preferences
|
||||
|
||||
FreeCADGui.addLanguagePath(":/translations")
|
||||
@@ -79,6 +79,7 @@ class AssemblyWorkbench(Workbench):
|
||||
"Assembly_InsertLink",
|
||||
"Assembly_SolveAssembly",
|
||||
"Assembly_CreateView",
|
||||
"Assembly_CreateBom",
|
||||
]
|
||||
|
||||
cmdListMenuOnly = [
|
||||
|
||||
@@ -607,6 +607,20 @@ def color_from_unsigned(c):
|
||||
]
|
||||
|
||||
|
||||
def getBomGroup(assembly):
|
||||
bom_group = None
|
||||
|
||||
for obj in assembly.OutList:
|
||||
if obj.TypeId == "Assembly::BomGroup":
|
||||
bom_group = obj
|
||||
break
|
||||
|
||||
if not bom_group:
|
||||
bom_group = assembly.newObject("Assembly::BomGroup", "Bills of Materials")
|
||||
|
||||
return bom_group
|
||||
|
||||
|
||||
def getJointGroup(assembly):
|
||||
joint_group = None
|
||||
|
||||
|
||||
@@ -516,6 +516,11 @@ App::Range Sheet::getRange(const char* name, bool silent) const
|
||||
return cells.getRange(name, silent);
|
||||
}
|
||||
|
||||
std::tuple<App::CellAddress, App::CellAddress> Sheet::getUsedRange() const
|
||||
{
|
||||
return cells.getUsedRange();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a map with column indices and widths.
|
||||
* @return Map with results.
|
||||
|
||||
@@ -199,6 +199,8 @@ public:
|
||||
|
||||
App::Range getRange(const char* name, bool silent = false) const;
|
||||
|
||||
std::tuple<App::CellAddress, App::CellAddress> getUsedRange() const;
|
||||
|
||||
std::map<int, int> getColumnWidths() const;
|
||||
|
||||
std::map<int, int> getRowHeights() const;
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
#include "PropertiesDialog.h"
|
||||
#include "SpreadsheetView.h"
|
||||
#include "ViewProviderSpreadsheet.h"
|
||||
|
||||
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@@ -250,27 +251,10 @@ void CmdSpreadsheetExport::activated(int iMsg)
|
||||
|
||||
if (sheetView) {
|
||||
Sheet* sheet = sheetView->getSheet();
|
||||
QString selectedFilter;
|
||||
QString formatList = QObject::tr("CSV (*.csv *.CSV);;All (*)");
|
||||
QString fileName = Gui::FileDialog::getSaveFileName(Gui::getMainWindow(),
|
||||
QObject::tr("Export file"),
|
||||
QString(),
|
||||
formatList,
|
||||
&selectedFilter);
|
||||
if (!fileName.isEmpty()) {
|
||||
if (sheet) {
|
||||
char delim, quote, escape;
|
||||
std::string errMsg = "Export";
|
||||
bool isValid = sheet->getCharsFromPrefs(delim, quote, escape, errMsg);
|
||||
|
||||
if (isValid) {
|
||||
sheet->exportToFile(fileName.toStdString(), delim, quote, escape);
|
||||
}
|
||||
else {
|
||||
Base::Console().Error(errMsg.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(sheet);
|
||||
auto* vps = dynamic_cast<ViewProviderSheet*>(vp);
|
||||
if (vps) {
|
||||
vps->exportAsFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <Gui/BitmapFactory.h>
|
||||
#include <Gui/CommandT.h>
|
||||
#include <Gui/Document.h>
|
||||
#include <Gui/FileDialog.h>
|
||||
#include <Gui/MainWindow.h>
|
||||
#include <Gui/View3DInventor.h>
|
||||
#include <Mod/Spreadsheet/App/Sheet.h>
|
||||
@@ -102,11 +103,7 @@ QIcon ViewProviderSheet::getIcon() const
|
||||
bool ViewProviderSheet::setEdit(int ModNum)
|
||||
{
|
||||
if (ModNum == ViewProvider::Default) {
|
||||
if (!this->view) {
|
||||
showSpreadsheetView();
|
||||
view->viewAll();
|
||||
}
|
||||
Gui::getMainWindow()->setActiveWindow(this->view);
|
||||
showSheetMdi();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -123,12 +120,44 @@ bool ViewProviderSheet::doubleClicked()
|
||||
Gui::Command::assureWorkbench("SpreadsheetWorkbench");
|
||||
}
|
||||
|
||||
showSheetMdi();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ViewProviderSheet::showSheetMdi()
|
||||
{
|
||||
if (!this->view) {
|
||||
showSpreadsheetView();
|
||||
view->viewAll();
|
||||
}
|
||||
Gui::getMainWindow()->setActiveWindow(this->view);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ViewProviderSheet::exportAsFile()
|
||||
{
|
||||
auto* sheet = static_cast<Spreadsheet::Sheet*>(getObject());
|
||||
QString selectedFilter;
|
||||
QString formatList = QObject::tr("CSV (*.csv *.CSV);;All (*)");
|
||||
QString fileName = Gui::FileDialog::getSaveFileName(Gui::getMainWindow(),
|
||||
QObject::tr("Export file"),
|
||||
QString(),
|
||||
formatList,
|
||||
&selectedFilter);
|
||||
if (!fileName.isEmpty()) {
|
||||
if (sheet) {
|
||||
char delim, quote, escape;
|
||||
std::string errMsg = "Export";
|
||||
bool isValid = sheet->getCharsFromPrefs(delim, quote, escape, errMsg);
|
||||
|
||||
if (isValid) {
|
||||
sheet->exportToFile(fileName.toStdString(), delim, quote, escape);
|
||||
}
|
||||
else {
|
||||
Base::Console().Error(errMsg.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ViewProviderSheet::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
|
||||
|
||||
@@ -78,6 +78,10 @@ public:
|
||||
|
||||
PyObject* getPyObject() override;
|
||||
|
||||
void showSheetMdi();
|
||||
|
||||
void exportAsFile();
|
||||
|
||||
protected:
|
||||
SheetView* showSpreadsheetView();
|
||||
void updateData(const App::Property* prop) override;
|
||||
|
||||
@@ -20,5 +20,27 @@
|
||||
<UserDocu>Get access to the sheet view</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="showSheetMdi">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
Create (if necessary) and switch to the Spreadsheet MDI.
|
||||
|
||||
showSheetMdi()
|
||||
|
||||
Returns: None
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="exportAsFile">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
Export the sheet as a file.
|
||||
|
||||
exportAsFile()
|
||||
|
||||
Returns: None
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
|
||||
@@ -59,3 +59,21 @@ int ViewProviderSpreadsheetPy::setCustomAttributes(const char* /*attr*/, PyObjec
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* ViewProviderSpreadsheetPy::showSheetMdi(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
this->getViewProviderSheetPtr()->showSheetMdi();
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* ViewProviderSpreadsheetPy::exportAsFile(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
this->getViewProviderSheetPtr()->exportAsFile();
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user