diff --git a/sources/qetgraphicsitem/masterelement.cpp b/sources/qetgraphicsitem/masterelement.cpp index 1ccebfd3a..b9c829a0f 100644 --- a/sources/qetgraphicsitem/masterelement.cpp +++ b/sources/qetgraphicsitem/masterelement.cpp @@ -235,6 +235,28 @@ void MasterElement::aboutDeleteXref() * so they cannot disagree with each other. * @return the per type usage */ +namespace { + + /** + Map the element data's contact type onto the tally's own, so that + the used count and the declared capacity cannot classify the same + contact type differently. + */ + ContactUsage::Type contactType(ElementData::SlaveState state) + { + switch (state) + { + case ElementData::NO: return ContactUsage::NO; + case ElementData::NC: return ContactUsage::NC; + case ElementData::SW: return ContactUsage::SW; + case ElementData::Other: break; + } + + return ContactUsage::Other; + } + +} + ContactUsage MasterElement::contactUsage() const { ContactUsage usage; @@ -246,22 +268,32 @@ ContactUsage MasterElement::contactUsage() const } const ElementData &data = elmt->elementData(); - - ContactUsage::Type type = ContactUsage::Other; - switch (data.m_slave_state) - { - case ElementData::NO: type = ContactUsage::NO; break; - case ElementData::NC: type = ContactUsage::NC; break; - case ElementData::SW: type = ContactUsage::SW; break; - case ElementData::Other: type = ContactUsage::Other; break; - } - - usage.addSlave(type, data.m_contact_count); + usage.addSlave(contactType(data.m_slave_state), data.m_contact_count); } return usage; } +/** + * @brief MasterElement::contactCapacity + * The contacts this master declares it provides, by type, summed over its + * contact groups. A group stands for contactCount contacts of its type. + * Returns an empty tally when the element declares no groups, which is the + * case for every element in the standard collection today -- callers use + * that to decide whether a capacity is worth showing at all. + * @return the per type capacity + */ +ContactUsage MasterElement::contactCapacity() const +{ + ContactUsage capacity; + + for (const auto &group : m_data.m_slave_contact_groups) { + capacity.addSlave(contactType(group.type), group.contactCount); + } + + return capacity; +} + /** * @brief MasterElement::isFull * @return true if the master has reached its maximum number of slaves diff --git a/sources/qetgraphicsitem/masterelement.h b/sources/qetgraphicsitem/masterelement.h index 21aa20f40..2892e68e1 100644 --- a/sources/qetgraphicsitem/masterelement.h +++ b/sources/qetgraphicsitem/masterelement.h @@ -49,6 +49,7 @@ class MasterElement : public Element QRectF XrefBoundingRect() const; ContactUsage contactUsage() const; + ContactUsage contactCapacity() const; bool isFull() const; // Check Slave-Limit protected: diff --git a/sources/ui/elementpropertieswidget.cpp b/sources/ui/elementpropertieswidget.cpp index 2dc75cd51..db6603663 100644 --- a/sources/ui/elementpropertieswidget.cpp +++ b/sources/ui/elementpropertieswidget.cpp @@ -393,16 +393,32 @@ QWidget *ElementPropertiesWidget::generalWidget() //Counted in contacts rather than in linked elements, so that a //slave standing for several contacts is reported as the number //of contacts it actually uses. - const ContactUsage usage = - static_cast(m_element.data())->contactUsage(); + const MasterElement *master = + static_cast(m_element.data()); + const ContactUsage usage = master->contactUsage(); description_string += QString(tr("Nombre de contacts esclaves utilisés : %1\n")).arg(usage.total()); //The breakdown is what tells you which auxiliary block would //satisfy this coil, so it is only worth printing once there is //something to break down. - if (usage.total() > 0) + const ContactUsage capacity = master->contactCapacity(); + + if (capacity.total() > 0) { + //The element declares contact groups, so it can say not + //only what has been used but what it has to offer. A type + //used beyond what is declared shows as e.g. "1/0", which + //is the point: it says this contact does not fit the part. + description_string += QString(tr(" NO : %1/%2, NC : %3/%4, inverseurs : %5/%6, autres : %7/%8\n")) + .arg(usage.no).arg(capacity.no) + .arg(usage.nc).arg(capacity.nc) + .arg(usage.sw).arg(capacity.sw) + .arg(usage.other).arg(capacity.other); + } + else if (usage.total() > 0) + { + //No declared groups, so a plain count of what is in use. description_string += QString(tr(" NO : %1, NC : %2, inverseurs : %3, autres : %4\n")) .arg(usage.no) .arg(usage.nc) diff --git a/tests/qttest/tst_contactusage.cpp b/tests/qttest/tst_contactusage.cpp index c587b3fbb..deb756933 100644 --- a/tests/qttest/tst_contactusage.cpp +++ b/tests/qttest/tst_contactusage.cpp @@ -101,6 +101,20 @@ private slots: QCOMPARE(usage.total(), 1); } + // A declared capacity is summed across groups, so two NO groups of two + // contacts each declare four NO contacts, not two groups. + void capacitySumsAcrossGroups() + { + ContactUsage capacity; + capacity.addSlave(ContactUsage::NO, 2); + capacity.addSlave(ContactUsage::NO, 2); + capacity.addSlave(ContactUsage::NC, 1); + + QCOMPARE(capacity.no, 4); + QCOMPARE(capacity.nc, 1); + QCOMPARE(capacity.total(), 5); + } + // The mix a coil would actually carry: two single NO, one 4 pole NO, // one NC and one changeover. void tallysARealisticMix()