Loading files
/*
* 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 "componentpinsignalmapmodel.h"
#include "../../undostack.h"
#include "../cmd/cmdcomponentpinsignalmapitemedit.h"
#include "../libraryelementcache.h"
#include <librepcb/core/library/sym/symbol.h>
#include <QtCore>
#include <algorithm>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
namespace editor {
/*******************************************************************************
* Constructors / Destructor
******************************************************************************/
ComponentPinSignalMapModel::ComponentPinSignalMapModel(QObject* parent) noexcept
: QAbstractTableModel(parent),
mSymbolVariant(nullptr),
mSignals(nullptr),
mSymbolsCache(nullptr),
mUndoStack(nullptr),
mOnItemsEditedSlot(*this, &ComponentPinSignalMapModel::symbolItemsEdited),
mOnSignalsEditedSlot(*this, &ComponentPinSignalMapModel::signalListEdited) {
foreach (const CmpSigPinDisplayType& type,
CmpSigPinDisplayType::getAllTypes()) {
mDisplayTypeComboBoxItems.append(
ComboBoxDelegate::Item{type.getNameTr(), QIcon(), type.toString()});
}
}
ComponentPinSignalMapModel::~ComponentPinSignalMapModel() noexcept {
}
/*******************************************************************************
* Setters
******************************************************************************/
void ComponentPinSignalMapModel::setSymbolVariant(
ComponentSymbolVariant* variant) noexcept {
emit beginResetModel();
mOnItemsEditedSlot.detachAll();
mSymbolVariant = variant;
if (mSymbolVariant) {
mSymbolVariant->getSymbolItems().onEdited.attach(mOnItemsEditedSlot);
}
emit endResetModel();
}
void ComponentPinSignalMapModel::setSymbolsCache(
const std::shared_ptr<const LibraryElementCache>& cache) noexcept {
mSymbolsCache = cache;
emit dataChanged(index(0, COLUMN_SYMBOL), index(rowCount() - 1, COLUMN_PIN));
}
void ComponentPinSignalMapModel::setSignalList(
const ComponentSignalList* list) noexcept {
mOnSignalsEditedSlot.detachAll();
mSignals = list;
if (mSignals) {
mSignals->onEdited.attach(mOnSignalsEditedSlot);
}
updateSignalComboBoxItems();
emit dataChanged(index(0, COLUMN_SIGNAL), index(rowCount() - 1, COLUMN_PIN));
}
void ComponentPinSignalMapModel::setUndoStack(UndoStack* stack) noexcept {
mUndoStack = stack;
}
/*******************************************************************************
* General Methods
******************************************************************************/
void ComponentPinSignalMapModel::autoAssignSignals() noexcept {
if (!mSymbolVariant || !mSignals || !mSymbolsCache) {
return;
}
try {
for (ComponentSymbolVariantItem& item : mSymbolVariant->getSymbolItems()) {
std::shared_ptr<const Symbol> symbol =
mSymbolsCache->getSymbol(item.getSymbolUuid());
if (symbol) {
for (ComponentPinSignalMapItem& map : item.getPinSignalMap()) {
CircuitIdentifier pinName =
symbol->getPins().get(map.getPinUuid())->getName();
std::shared_ptr<const ComponentSignal> signal =
mSignals->find(*pinName);
tl::optional<Uuid> signalUuid =
signal ? tl::make_optional(signal->getUuid()) : tl::nullopt;
QScopedPointer<CmdComponentPinSignalMapItemEdit> cmd(
new CmdComponentPinSignalMapItemEdit(map));
cmd->setSignalUuid(signalUuid);
execCmd(cmd.take()); // can throw
}
}
}
} catch (const Exception& e) {
QMessageBox::critical(0, tr("Error"), e.getMsg());
}
}
/*******************************************************************************
* Inherited from QAbstractItemModel
******************************************************************************/
int ComponentPinSignalMapModel::rowCount(const QModelIndex& parent) const {
int count = 0;
if (!parent.isValid() && mSymbolVariant) {
for (const auto& item : mSymbolVariant->getSymbolItems()) {
count += item.getPinSignalMap().count();
}
}
return count;
}
int ComponentPinSignalMapModel::columnCount(const QModelIndex& parent) const {
if (!parent.isValid()) {
return _COLUMN_COUNT;
}
return 0;
}
QVariant ComponentPinSignalMapModel::data(const QModelIndex& index,
int role) const {
if (!index.isValid() || !mSymbolVariant) {
return QVariant();
}
int symbolItemIndex = -1;
std::shared_ptr<ComponentSymbolVariantItem> symbolItem;
std::shared_ptr<ComponentPinSignalMapItem> mapItem;
getRowItem(index.row(), symbolItemIndex, symbolItem, mapItem);
if (!symbolItem || !mapItem) {
return QVariant();
}
switch (index.column()) {
case COLUMN_SYMBOL: {
Uuid symbolUuid = symbolItem->getSymbolUuid();
std::shared_ptr<const Symbol> symbol;
if (mSymbolsCache) {
symbol = mSymbolsCache->getSymbol(symbolUuid);
}
switch (role) {
case Qt::DisplayRole:
return symbol ? *symbol->getNames().getDefaultValue()
: symbolUuid.toStr();
case Qt::ToolTipRole:
return symbolUuid.toStr();
default:
return QVariant();
}
}
case COLUMN_PIN: {
Uuid symbolUuid = symbolItem->getSymbolUuid();
std::shared_ptr<const Symbol> symbol;
if (mSymbolsCache) {
symbol = mSymbolsCache->getSymbol(symbolUuid);
}
Uuid pinUuid = mapItem->getPinUuid();
std::shared_ptr<const SymbolPin> pin =
symbol ? symbol->getPins().find(pinUuid) : nullptr;
QString pinName = pin ? *pin->getName() : pinUuid.toStr();
QString pinPath;
if (mSymbolVariant->getSymbolItems().count() > 1) {
pinPath += QString::number(symbolItemIndex + 1) % "::";
}
if (!symbolItem->getSuffix()->isEmpty()) {
pinPath += *symbolItem->getSuffix() % "::";
}
pinPath += pinName;
switch (role) {
case Qt::DisplayRole:
case Qt::ToolTipRole:
return pinPath;
default:
return QVariant();
}
}
case COLUMN_SIGNAL: {
tl::optional<Uuid> uuid = mapItem->getSignalUuid();
std::shared_ptr<const ComponentSignal> sig =
uuid && mSignals ? mSignals->find(*uuid) : nullptr;
switch (role) {
case Qt::DisplayRole:
return sig
? *sig->getName()
: (uuid ? uuid->toStr() : QString("(%1)").arg(tr("unconnected")));
case Qt::EditRole:
case Qt::ToolTipRole:
return uuid ? uuid->toStr() : QVariant(); // NULL means unconnected!
case Qt::UserRole:
return QVariant::fromValue(mSignalComboBoxItems);
default:
return QVariant();
}
}
case COLUMN_DISPLAY: {
switch (role) {
case Qt::DisplayRole:
case Qt::ToolTipRole:
return mapItem->getDisplayType().getNameTr();
case Qt::EditRole:
return mapItem->getDisplayType().toString();
case Qt::UserRole:
return QVariant::fromValue(mDisplayTypeComboBoxItems);
default:
return QVariant();
}
}
default:
return QVariant();
}
return QVariant();
}
QVariant ComponentPinSignalMapModel::headerData(int section,
Qt::Orientation orientation,
int role) const {
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
switch (section) {
case COLUMN_SYMBOL:
return tr("Symbol");
case COLUMN_PIN:
return tr("Pin");
case COLUMN_SIGNAL:
return tr("Component Signal");
case COLUMN_DISPLAY:
return tr("Designator in Schematics");
}
}
}
return QVariant();
}
Qt::ItemFlags ComponentPinSignalMapModel::flags(
const QModelIndex& index) const {
Qt::ItemFlags f = QAbstractTableModel::flags(index);
if (index.isValid() &&
((index.column() == COLUMN_SIGNAL) ||
(index.column() == COLUMN_DISPLAY))) {
f |= Qt::ItemIsEditable;
}
return f;
}
bool ComponentPinSignalMapModel::setData(const QModelIndex& index,
const QVariant& value, int role) {
if (!mSymbolVariant) {
return false;
}
try {
int symbolItemIndex = -1;
std::shared_ptr<ComponentSymbolVariantItem> symbolItem;
std::shared_ptr<ComponentPinSignalMapItem> mapItem;
getRowItem(index.row(), symbolItemIndex, symbolItem, mapItem);
if (!mapItem) {
return false;
}
if ((index.column() == COLUMN_SIGNAL) && (role == Qt::EditRole)) {
QScopedPointer<CmdComponentPinSignalMapItemEdit> cmd(
new CmdComponentPinSignalMapItemEdit(*mapItem));
cmd->setSignalUuid(Uuid::tryFromString(value.toString()));
execCmd(cmd.take());
return true;
} else if ((index.column() == COLUMN_DISPLAY) && (role == Qt::EditRole)) {
QScopedPointer<CmdComponentPinSignalMapItemEdit> cmd(
new CmdComponentPinSignalMapItemEdit(*mapItem));
cmd->setDisplayType(CmpSigPinDisplayType::fromString(value.toString()));
execCmd(cmd.take());
return true;
}
} catch (const Exception& e) {
QMessageBox::critical(0, tr("Error"), e.getMsg());
}
return false;
}
/*******************************************************************************
* Private Methods
******************************************************************************/
void ComponentPinSignalMapModel::symbolItemsEdited(
const ComponentSymbolVariantItemList& list, int index,
const std::shared_ptr<const ComponentSymbolVariantItem>& item,
ComponentSymbolVariantItemList::Event event) noexcept {
Q_UNUSED(list);
Q_UNUSED(index);
Q_UNUSED(item);
switch (event) {
case ComponentSymbolVariantItemList::Event::ElementAdded:
case ComponentSymbolVariantItemList::Event::ElementRemoved:
case ComponentSymbolVariantItemList::Event::ElementEdited:
emit beginResetModel();
emit endResetModel();
break;
default:
qWarning() << "Unhandled switch-case in "
"ComponentPinSignalMapModel::symbolItemsEdited():"
<< static_cast<int>(event);
break;
}
}
void ComponentPinSignalMapModel::signalListEdited(
const ComponentSignalList& list, int index,
const std::shared_ptr<const ComponentSignal>& signal,
ComponentSignalList::Event event) noexcept {
Q_UNUSED(list);
Q_UNUSED(index);
Q_UNUSED(signal);
switch (event) {
case ComponentSignalList::Event::ElementAdded:
case ComponentSignalList::Event::ElementRemoved:
case ComponentSignalList::Event::ElementEdited:
updateSignalComboBoxItems();
dataChanged(this->index(0, COLUMN_SIGNAL),
this->index(rowCount() - 1, COLUMN_SIGNAL));
break;
default:
qWarning() << "Unhandled switch-case in "
"ComponentPinSignalMapModel::signalListEdited():"
<< static_cast<int>(event);
break;
}
}
void ComponentPinSignalMapModel::execCmd(UndoCommand* cmd) {
if (mUndoStack) {
mUndoStack->execCmd(cmd);
} else {
QScopedPointer<UndoCommand> cmdGuard(cmd);
cmdGuard->execute();
}
}
void ComponentPinSignalMapModel::updateSignalComboBoxItems() noexcept {
mSignalComboBoxItems.clear();
if (mSignals) {
for (const ComponentSignal& sig : *mSignals) {
mSignalComboBoxItems.append(ComboBoxDelegate::Item{
*sig.getName(), QIcon(), sig.getUuid().toStr()});
}
}
mSignalComboBoxItems.sort();
mSignalComboBoxItems.insert(
0,
ComboBoxDelegate::Item{QString("(%1)").arg(tr("unconnected")), QIcon(),
QVariant()});
}
void ComponentPinSignalMapModel::getRowItem(
int row, int& symbolItemIndex,
std::shared_ptr<ComponentSymbolVariantItem>& symbolItem,
std::shared_ptr<ComponentPinSignalMapItem>& mapItem) const noexcept {
int count = 0;
for (int i = 0; i < mSymbolVariant->getSymbolItems().count(); ++i) {
symbolItemIndex = i;
symbolItem = mSymbolVariant->getSymbolItems().value(i);
if (row < (count + symbolItem->getPinSignalMap().count())) {
mapItem = symbolItem->getPinSignalMap().value(row - count);
break;
} else {
count += symbolItem->getPinSignalMap().count();
}
}
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace editor
} // namespace librepcb
c74bd0883This file is pinned to the selected release. Download the original to open it in your design tool.