Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
/*
* LibrePCB - Professional EDA for everyone!
* Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
* https://librepcb.org/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*******************************************************************************
* Includes
******************************************************************************/
#include "newelementwizardcontext.h"
#include <librepcb/core/exceptions.h>
#include <librepcb/core/fileio/transactionalfilesystem.h>
#include <librepcb/core/library/cat/componentcategory.h>
#include <librepcb/core/library/cat/packagecategory.h>
#include <librepcb/core/library/cmp/component.h>
#include <librepcb/core/library/dev/device.h>
#include <librepcb/core/library/library.h>
#include <librepcb/core/library/pkg/package.h>
#include <librepcb/core/library/sym/symbol.h>
#include <librepcb/core/workspace/workspace.h>
#include <librepcb/core/workspace/workspacesettings.h>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
namespace editor {
/*******************************************************************************
* Constructors / Destructor
******************************************************************************/
NewElementWizardContext::NewElementWizardContext(
const Workspace& ws, Library& lib, const IF_GraphicsLayerProvider& lp,
QObject* parent) noexcept
: QObject(parent),
mWorkspace(ws),
mLibrary(lib),
mLayerProvider(lp),
mElementType(ElementType::None),
mPackageAssemblyType(Package::AssemblyType::Auto),
mComponentPrefixes(ComponentPrefix("")) {
reset();
}
NewElementWizardContext::~NewElementWizardContext() noexcept {
}
/*******************************************************************************
* Getters
******************************************************************************/
const QStringList& NewElementWizardContext::getLibLocaleOrder() const noexcept {
return mWorkspace.getSettings().libraryLocaleOrder.get();
}
/*******************************************************************************
* Private Methods
******************************************************************************/
void NewElementWizardContext::reset(ElementType newType) noexcept {
// common
mFiles.clear();
mElementType = newType;
mElementName = tl::nullopt;
mElementDescription.clear();
mElementKeywords.clear();
mElementAuthor = mWorkspace.getSettings().userName.get();
mElementVersion = Version::fromString("0.1");
mElementCategoryUuids.clear();
// symbol
mSymbolPins.clear();
mSymbolPolygons.clear();
mSymbolCircles.clear();
mSymbolTexts.clear();
// package
mPackageAssemblyType = Package::AssemblyType::Auto;
mPackagePads.clear();
mPackageModels.clear();
mPackageFootprints.clear();
// component
mComponentSchematicOnly = false;
mComponentAttributes.clear();
mComponentDefaultValue.clear();
mComponentPrefixes = NormDependentPrefixMap(ComponentPrefix(""));
mComponentSignals.clear();
mComponentSymbolVariants.clear();
// device
mDeviceComponentUuid = tl::nullopt;
mDevicePackageUuid = tl::nullopt;
}
void NewElementWizardContext::copyElement(ElementType type,
const FilePath& fp) {
mElementType = type;
std::unique_ptr<TransactionalDirectory> dir(
new TransactionalDirectory(TransactionalFileSystem::openRO(fp)));
std::unique_ptr<LibraryBaseElement> element;
switch (mElementType) {
case NewElementWizardContext::ElementType::ComponentCategory: {
element = ComponentCategory::open(std::move(dir));
break;
}
case NewElementWizardContext::ElementType::PackageCategory: {
element = PackageCategory::open(std::move(dir));
break;
}
case NewElementWizardContext::ElementType::Symbol: {
element = Symbol::open(std::move(dir));
break;
}
case NewElementWizardContext::ElementType::Component: {
element = Component::open(std::move(dir));
break;
}
case NewElementWizardContext::ElementType::Device: {
element = Device::open(std::move(dir));
break;
}
case NewElementWizardContext::ElementType::Package: {
element = Package::open(std::move(dir));
break;
}
default: {
qCritical()
<< "Unhandled switch-case in NewElementWizardContext::copyElement():"
<< static_cast<int>(mElementType);
break;
}
}
mElementName = element->getNames().getDefaultValue();
mElementDescription = element->getDescriptions().getDefaultValue();
mElementKeywords = element->getKeywords().getDefaultValue();
if (const LibraryCategory* category =
dynamic_cast<const LibraryCategory*>(element.get())) {
if (category->getParentUuid().has_value()) {
mElementCategoryUuids.insert(*category->getParentUuid());
}
}
if (const LibraryElement* libElement =
dynamic_cast<const LibraryElement*>(element.get())) {
mElementCategoryUuids = libElement->getCategories();
}
switch (mElementType) {
case NewElementWizardContext::ElementType::Symbol: {
const Symbol* symbol = dynamic_cast<Symbol*>(element.get());
Q_ASSERT(symbol);
// copy pins but generate new UUIDs
mSymbolPins.clear();
for (const SymbolPin& pin : symbol->getPins()) {
mSymbolPins.append(std::make_shared<SymbolPin>(
Uuid::createRandom(), pin.getName(), pin.getPosition(),
pin.getLength(), pin.getRotation(), pin.getNamePosition(),
pin.getNameRotation(), pin.getNameHeight(),
pin.getNameAlignment()));
}
// copy polygons but generate new UUIDs
mSymbolPolygons.clear();
for (const Polygon& polygon : symbol->getPolygons()) {
mSymbolPolygons.append(std::make_shared<Polygon>(
Uuid::createRandom(), polygon.getLayer(), polygon.getLineWidth(),
polygon.isFilled(), polygon.isGrabArea(), polygon.getPath()));
}
// copy circles but generate new UUIDs
mSymbolCircles.clear();
for (const Circle& circle : symbol->getCircles()) {
mSymbolCircles.append(std::make_shared<Circle>(
Uuid::createRandom(), circle.getLayer(), circle.getLineWidth(),
circle.isFilled(), circle.isGrabArea(), circle.getCenter(),
circle.getDiameter()));
}
// copy texts but generate new UUIDs
mSymbolTexts.clear();
for (const Text& text : symbol->getTexts()) {
mSymbolTexts.append(std::make_shared<Text>(
Uuid::createRandom(), text.getLayer(), text.getText(),
text.getPosition(), text.getRotation(), text.getHeight(),
text.getAlign()));
}
break;
}
case ElementType::Package: {
const Package* package = dynamic_cast<Package*>(element.get());
Q_ASSERT(package);
mPackageAssemblyType = package->getAssemblyType(false);
// copy pads but generate new UUIDs
QHash<Uuid, tl::optional<Uuid>> padUuidMap;
mPackagePads.clear();
for (const PackagePad& pad : package->getPads()) {
Uuid newUuid = Uuid::createRandom();
padUuidMap.insert(pad.getUuid(), newUuid);
mPackagePads.append(
std::make_shared<PackagePad>(newUuid, pad.getName()));
}
// Copy 3D models but generate new UUIDs.
QHash<Uuid, tl::optional<Uuid>> modelsUuidMap;
mPackageModels.clear();
for (const PackageModel& model : package->getModels()) {
auto newModel = std::make_shared<PackageModel>(Uuid::createRandom(),
model.getName());
modelsUuidMap.insert(model.getUuid(), newModel->getUuid());
mPackageModels.append(newModel);
const QByteArray fileContent =
package->getDirectory().readIfExists(model.getFileName());
if (!fileContent.isNull()) {
mFiles.insert(newModel->getFileName(), fileContent);
}
}
// copy footprints but generate new UUIDs
mPackageFootprints.clear();
for (const Footprint& footprint : package->getFootprints()) {
// don't copy translations as they would need to be adjusted anyway
std::shared_ptr<Footprint> newFootprint(new Footprint(
Uuid::createRandom(), footprint.getNames().getDefaultValue(),
footprint.getDescriptions().getDefaultValue()));
newFootprint->setModelPosition(footprint.getModelPosition());
newFootprint->setModelRotation(footprint.getModelRotation());
// Copy models but with the new UUIDs.
QSet<Uuid> models;
foreach (const Uuid& uuid, footprint.getModels()) {
if (auto newUuid = modelsUuidMap.value(uuid)) {
models.insert(*newUuid);
}
}
newFootprint->setModels(models);
// copy pads but generate new UUIDs
for (const FootprintPad& pad : footprint.getPads()) {
tl::optional<Uuid> pkgPad = pad.getPackagePadUuid();
if (pkgPad) {
pkgPad = padUuidMap.value(*pkgPad); // Translate to new UUID
}
newFootprint->getPads().append(std::make_shared<FootprintPad>(
Uuid::createRandom(), pkgPad, pad.getPosition(),
pad.getRotation(), pad.getShape(), pad.getWidth(),
pad.getHeight(), pad.getRadius(), pad.getCustomShapeOutline(),
pad.getStopMaskConfig(), pad.getSolderPasteConfig(),
pad.getCopperClearance(), pad.getComponentSide(),
pad.getFunction(), pad.getHoles()));
}
// copy polygons but generate new UUIDs
for (const Polygon& polygon : footprint.getPolygons()) {
newFootprint->getPolygons().append(std::make_shared<Polygon>(
Uuid::createRandom(), polygon.getLayer(), polygon.getLineWidth(),
polygon.isFilled(), polygon.isGrabArea(), polygon.getPath()));
}
// copy circles but generate new UUIDs
for (const Circle& circle : footprint.getCircles()) {
newFootprint->getCircles().append(std::make_shared<Circle>(
Uuid::createRandom(), circle.getLayer(), circle.getLineWidth(),
circle.isFilled(), circle.isGrabArea(), circle.getCenter(),
circle.getDiameter()));
}
// copy stroke texts but generate new UUIDs
for (const StrokeText& text : footprint.getStrokeTexts()) {
newFootprint->getStrokeTexts().append(std::make_shared<StrokeText>(
Uuid::createRandom(), text.getLayer(), text.getText(),
text.getPosition(), text.getRotation(), text.getHeight(),
text.getStrokeWidth(), text.getLetterSpacing(),
text.getLineSpacing(), text.getAlign(), text.getMirrored(),
text.getAutoRotate()));
}
// copy holes but generate new UUIDs
for (const Hole& hole : footprint.getHoles()) {
newFootprint->getHoles().append(
std::make_shared<Hole>(Uuid::createRandom(), hole.getDiameter(),
hole.getPath(), hole.getStopMaskConfig()));
}
mPackageFootprints.append(newFootprint);
}
break;
}
case ElementType::Component: {
const Component* component = dynamic_cast<Component*>(element.get());
Q_ASSERT(component);
mComponentSchematicOnly = component->isSchematicOnly();
mComponentAttributes = component->getAttributes();
mComponentDefaultValue = component->getDefaultValue();
mComponentPrefixes = component->getPrefixes();
// copy signals but generate new UUIDs
QHash<Uuid, Uuid> signalUuidMap;
mComponentSignals.clear();
for (const ComponentSignal& signal : component->getSignals()) {
Uuid newUuid = Uuid::createRandom();
signalUuidMap.insert(signal.getUuid(), newUuid);
mComponentSignals.append(std::make_shared<ComponentSignal>(
newUuid, signal.getName(), signal.getRole(),
signal.getForcedNetName(), signal.isRequired(), signal.isNegated(),
signal.isClock()));
}
// copy symbol variants but generate new UUIDs
mComponentSymbolVariants.clear();
for (const ComponentSymbolVariant& var : component->getSymbolVariants()) {
// don't copy translations as they would need to be adjusted anyway
std::shared_ptr<ComponentSymbolVariant> copy(new ComponentSymbolVariant(
Uuid::createRandom(), var.getNorm(),
var.getNames().getDefaultValue(),
var.getDescriptions().getDefaultValue()));
// copy items
for (const ComponentSymbolVariantItem& item : var.getSymbolItems()) {
std::shared_ptr<ComponentSymbolVariantItem> itemCopy(
new ComponentSymbolVariantItem(
Uuid::createRandom(), item.getSymbolUuid(),
item.getSymbolPosition(), item.getSymbolRotation(),
item.isRequired(), item.getSuffix()));
// copy pin-signal-map
for (const ComponentPinSignalMapItem& map : item.getPinSignalMap()) {
tl::optional<Uuid> signal = map.getSignalUuid();
if (signal) {
signal = *signalUuidMap.find(*map.getSignalUuid());
}
itemCopy->getPinSignalMap().append(
std::make_shared<ComponentPinSignalMapItem>(
map.getPinUuid(), signal, map.getDisplayType()));
}
copy->getSymbolItems().append(itemCopy);
}
mComponentSymbolVariants.append(copy);
}
break;
}
case ElementType::Device: {
const Device* device = dynamic_cast<Device*>(element.get());
Q_ASSERT(device);
mDeviceComponentUuid = device->getComponentUuid();
mDevicePackageUuid = device->getPackageUuid();
mDevicePadSignalMap = device->getPadSignalMap();
break;
}
default: { break; }
}
}
void NewElementWizardContext::createLibraryElement() {
if (!mElementName) throw LogicError(__FILE__, __LINE__);
if (!mElementVersion) throw LogicError(__FILE__, __LINE__);
tl::optional<Uuid> rootCategoryUuid = tl::nullopt;
if (mElementCategoryUuids.count()) {
rootCategoryUuid = mElementCategoryUuids.values().first();
}
auto copyFiles = [this](TransactionalDirectory& dst) {
for (auto it = mFiles.begin(); it != mFiles.end(); ++it) {
dst.write(it.key(), it.value());
}
};
switch (mElementType) {
case NewElementWizardContext::ElementType::ComponentCategory: {
ComponentCategory element(Uuid::createRandom(), *mElementVersion,
mElementAuthor, *mElementName,
mElementDescription, mElementKeywords);
element.setParentUuid(rootCategoryUuid);
TransactionalDirectory dir(
mLibrary.getDirectory(),
mLibrary.getElementsDirectoryName<ComponentCategory>());
element.moveIntoParentDirectory(dir);
copyFiles(element.getDirectory());
mOutputDirectory = element.getDirectory().getAbsPath();
break;
}
case NewElementWizardContext::ElementType::PackageCategory: {
PackageCategory element(Uuid::createRandom(), *mElementVersion,
mElementAuthor, *mElementName,
mElementDescription, mElementKeywords);
element.setParentUuid(rootCategoryUuid);
TransactionalDirectory dir(
mLibrary.getDirectory(),
mLibrary.getElementsDirectoryName<PackageCategory>());
element.moveIntoParentDirectory(dir);
copyFiles(element.getDirectory());
mOutputDirectory = element.getDirectory().getAbsPath();
break;
}
case NewElementWizardContext::ElementType::Symbol: {
Symbol element(Uuid::createRandom(), *mElementVersion, mElementAuthor,
*mElementName, mElementDescription, mElementKeywords);
element.setCategories(mElementCategoryUuids);
element.getPins() = mSymbolPins;
element.getPolygons() = mSymbolPolygons;
element.getCircles() = mSymbolCircles;
element.getTexts() = mSymbolTexts;
TransactionalDirectory dir(mLibrary.getDirectory(),
mLibrary.getElementsDirectoryName<Symbol>());
element.moveIntoParentDirectory(dir);
copyFiles(element.getDirectory());
mOutputDirectory = element.getDirectory().getAbsPath();
break;
}
case NewElementWizardContext::ElementType::Package: {
Package element(Uuid::createRandom(), *mElementVersion, mElementAuthor,
*mElementName, mElementDescription, mElementKeywords,
mPackageAssemblyType);
element.setCategories(mElementCategoryUuids);
element.getPads() = mPackagePads;
element.getModels() = mPackageModels;
element.getFootprints() = mPackageFootprints;
if (element.getFootprints().isEmpty()) {
element.getFootprints().append(std::make_shared<Footprint>(
Uuid::createRandom(), ElementName("default"), ""));
}
TransactionalDirectory dir(mLibrary.getDirectory(),
mLibrary.getElementsDirectoryName<Package>());
element.moveIntoParentDirectory(dir);
copyFiles(element.getDirectory());
mOutputDirectory = element.getDirectory().getAbsPath();
break;
}
case NewElementWizardContext::ElementType::Component: {
Component element(Uuid::createRandom(), *mElementVersion, mElementAuthor,
*mElementName, mElementDescription, mElementKeywords);
element.setCategories(mElementCategoryUuids);
element.setIsSchematicOnly(mComponentSchematicOnly);
element.getAttributes() = mComponentAttributes;
element.setDefaultValue(mComponentDefaultValue);
element.setPrefixes(mComponentPrefixes);
element.getSignals() = mComponentSignals;
element.getSymbolVariants() = mComponentSymbolVariants;
TransactionalDirectory dir(
mLibrary.getDirectory(),
mLibrary.getElementsDirectoryName<Component>());
element.moveIntoParentDirectory(dir);
copyFiles(element.getDirectory());
mOutputDirectory = element.getDirectory().getAbsPath();
break;
}
case NewElementWizardContext::ElementType::Device: {
if (!mDeviceComponentUuid) throw LogicError(__FILE__, __LINE__);
if (!mDevicePackageUuid) throw LogicError(__FILE__, __LINE__);
Device element(Uuid::createRandom(), *mElementVersion, mElementAuthor,
*mElementName, mElementDescription, mElementKeywords,
*mDeviceComponentUuid, *mDevicePackageUuid);
element.setCategories(mElementCategoryUuids);
element.getPadSignalMap() = mDevicePadSignalMap;
TransactionalDirectory dir(mLibrary.getDirectory(),
mLibrary.getElementsDirectoryName<Device>());
element.moveIntoParentDirectory(dir);
copyFiles(element.getDirectory());
mOutputDirectory = element.getDirectory().getAbsPath();
break;
}
default:
throw LogicError(__FILE__, __LINE__);
}
// save to disk (a bit hacky, but should work...)
mLibrary.getDirectory().getFileSystem()->save();
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace editor
} // namespace librepcb
d953b88eaThis file is pinned to the selected release. Download the original to open it in your design tool.