mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-23 15:34:12 +02:00
Draw a terminal's label and its number apart, when asked to
A terminal's label is written as it is read off the plan, "X1:1", and
the symbol draws it as one field. On a long strip that field is long
enough to reach into the next terminal, and a user who wants the number
next to the screw and the label out of the way has no way to say so.
Settings > General > Appearance now has a "Display of the terminal
labelling" group with two choices: the label and its terminal number in
one field, the way it has always been drawn, or the two split. The
first is what every drawing gets, so nothing moves until the user asks
for it, and choosing the other one redraws the drawings already open --
nothing needs to be closed and opened again.
A symbol made for the split carries a text field bound to the new
"Terminal number" information (in the element editor's list, next to
the label, and as the %{terminal_number} variable of a composite text):
the label field then shows "X1" and the number field "1", each placed
where the symbol wants it, and hideable when it must be. A symbol which
has no such field -- every symbol drawn until now -- gets the number on
its own line inside the label field, so switching the setting on can
never make a number vanish, and never needs a symbol to be touched
first. A field which becomes, or stops being, the number field tells
the label fields of its symbol to draw themselves again.
Only the drawing reacts. What the element stores, the numbering, the
sorting in the terminal strip editor, the automatic strip import and
every export keep the whole label: the split is read where the text is
drawn (Element::labelForDisplay() and friends), not where the label is
made.
The new test covers both choices, with and without the number field, a
label with no colon at all, and the way back to the whole label. The
full test suite passes (124/124).
This commit is contained in:
@@ -6942,6 +6942,36 @@ Texte und Zahlen sind ebenso erlaubt.</translation>
|
||||
<source>Use gestures touchpad</source>
|
||||
<translation>Gesten vom Touchpad aktivieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../sources/ui/configpage/generalconfigurationpage.ui" line="146"/>
|
||||
<source>Display of the terminal labelling</source>
|
||||
<translation>Darstellung der Klemmenbeschriftung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../sources/ui/configpage/generalconfigurationpage.ui" line="152"/>
|
||||
<source>A terminal's label (X1:1) is drawn as a whole, the way it has always been.</source>
|
||||
<translation>Die BMK einer Klemme (X1:1) wird ganz gezeichnet, wie bisher.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../sources/ui/configpage/generalconfigurationpage.ui" line="155"/>
|
||||
<source>Show the label and the terminal number in one field</source>
|
||||
<translation>BMK (Label) und Anschlussnummer in einem Feld anzeigen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../sources/ui/configpage/generalconfigurationpage.ui" line="165"/>
|
||||
<source>The label (X1) is drawn in one field and the terminal number (1) in another, which a terminal symbol may place where it wants -- and hide when it must. A symbol without such a field shows the two, one under the other.</source>
|
||||
<translation>Die BMK (X1) wird in einem Feld und die Anschlussnummer (1) in einem weiteren Feld gezeichnet, das ein Klemmensymbol platzieren kann, wo es will -- und ausblenden, wenn es muss. Ein Symbol ohne ein solches Feld zeigt beides untereinander.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../sources/ui/configpage/generalconfigurationpage.ui" line="168"/>
|
||||
<source>Split the label and the terminal number</source>
|
||||
<translation>BMK und Anschlussnummer auftrennen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../sources/ui/configpage/generalconfigurationpage.ui" line="175"/>
|
||||
<source>Only the drawing changes: what is written in the element, the numbering, the sorting and the exports keep the whole label.</source>
|
||||
<translation>Es ändert sich nur die Darstellung: Was im Bauteil steht, die Nummerierung, die Sortierung und die Exporte behalten das ganze Label.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../sources/ui/configpage/generalconfigurationpage.ui" line="297"/>
|
||||
<source>Use sheet numbers instead of their position in the project</source>
|
||||
@@ -16677,6 +16707,11 @@ Möchten Sie sie ersetzen?</translation>
|
||||
<source>Label</source>
|
||||
<translation>Betriebsmittelkennzeichen (BMK)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../sources/qetinformation.cpp" line="315"/>
|
||||
<source>Terminal number</source>
|
||||
<translation>Anschlussnummer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../sources/editor/graphicspart/partplctable.cpp" line="189"/>
|
||||
<source>PLC Table</source>
|
||||
|
||||
@@ -46,6 +46,20 @@
|
||||
#include <QTextCursor>
|
||||
#include <QTextDocumentFragment>
|
||||
|
||||
namespace {
|
||||
/**
|
||||
A composite text which uses the terminal number follows the label
|
||||
as closely as one which uses %{label}: both are drawn from the
|
||||
label of the element, and from the formula that label is made of.
|
||||
*/
|
||||
bool usesLabelVariables(const QString &composite_text)
|
||||
{
|
||||
return composite_text.contains(QLatin1String("%{label}"))
|
||||
|| composite_text.contains(
|
||||
QStringLiteral("%{") + QETInformation::ELMT_TERMINAL_NUMBER + QLatin1String("}"));
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicElementTextItem::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (!event->matches(QKeySequence::Paste) || m_text_from != UserText ||
|
||||
@@ -401,8 +415,10 @@ Element *DynamicElementTextItem::elementUseForInfo() const
|
||||
*/
|
||||
void DynamicElementTextItem::refreshLabelConnection()
|
||||
{
|
||||
if ((m_text_from == ElementInfo && m_info_name == "label") ||
|
||||
(m_text_from == CompositeText && m_composite_text.contains("%{label}")))
|
||||
if ((m_text_from == ElementInfo &&
|
||||
(m_info_name == QLatin1String("label")
|
||||
|| m_info_name == QETInformation::ELMT_TERMINAL_NUMBER)) ||
|
||||
(m_text_from == CompositeText && usesLabelVariables(m_composite_text)))
|
||||
{
|
||||
if((m_parent_element.data()->linkType() & Element::AllReport) ||
|
||||
m_parent_element.data()->linkType() == Element::ConductorDefinition)
|
||||
@@ -450,26 +466,34 @@ void DynamicElementTextItem::setTextFrom(DynamicElementTextItem::TextFrom text_f
|
||||
}
|
||||
else if (m_text_from == ElementInfo && elementUseForInfo())
|
||||
{
|
||||
if(m_info_name == "label")
|
||||
if(m_info_name == QLatin1String("label")
|
||||
|| m_info_name == QETInformation::ELMT_TERMINAL_NUMBER)
|
||||
{
|
||||
setupFormulaConnection();
|
||||
updateLabel();
|
||||
}
|
||||
else
|
||||
setPlainText(elementUseForInfo()->elementInformations().value(m_info_name).toString());
|
||||
setPlainText(elementUseForInfo()->infoForDisplay(m_info_name));
|
||||
|
||||
if(old_text_from == UserText)
|
||||
connect(elementUseForInfo(), &Element::elementInfoChange, this, &DynamicElementTextItem::elementInfoChanged);
|
||||
}
|
||||
else if (m_text_from == CompositeText && elementUseForInfo())
|
||||
{
|
||||
if(m_composite_text.contains("%{label}"))
|
||||
if(usesLabelVariables(m_composite_text))
|
||||
{
|
||||
setupFormulaConnection();
|
||||
updateLabel();
|
||||
}
|
||||
else
|
||||
setPlainText(autonum::AssignVariables::replaceVariable(m_composite_text, elementUseForInfo()->elementInformations()));
|
||||
{
|
||||
//The label and the terminal number are drawn the way the
|
||||
//settings say, every other information as it is stored
|
||||
DiagramContext dc = elementUseForInfo()->elementInformations();
|
||||
dc.addValue(QETInformation::ELMT_LABEL, elementUseForInfo()->labelForDisplay());
|
||||
dc.addValue(QETInformation::ELMT_TERMINAL_NUMBER, elementUseForInfo()->terminalNumberForDisplay());
|
||||
setPlainText(autonum::AssignVariables::replaceVariable(m_composite_text, dc));
|
||||
}
|
||||
|
||||
if(old_text_from == UserText)
|
||||
connect(elementUseForInfo(), &Element::elementInfoChange, this, &DynamicElementTextItem::elementInfoChanged);
|
||||
@@ -478,7 +502,16 @@ void DynamicElementTextItem::setTextFrom(DynamicElementTextItem::TextFrom text_f
|
||||
if(m_parent_element.data()->linkType() == Element::Master ||
|
||||
m_parent_element.data()->linkType() == Element::Slave)
|
||||
updateXref();
|
||||
|
||||
|
||||
//A field which becomes, or stops being, the field for the
|
||||
//terminal number changes what the label of the symbol leaves
|
||||
//to it (@sa Element::labelForDisplay)
|
||||
if (m_info_name == QETInformation::ELMT_TERMINAL_NUMBER
|
||||
&& (m_text_from == ElementInfo || old_text_from == ElementInfo)
|
||||
&& parentElement()) {
|
||||
parentElement()->refreshLabelFields();
|
||||
}
|
||||
|
||||
emit textFromChanged(m_text_from);
|
||||
}
|
||||
|
||||
@@ -515,7 +548,8 @@ void DynamicElementTextItem::setInfoName(const QString &info_name)
|
||||
m_info_name = info_name;
|
||||
|
||||
|
||||
if(old_info_name == "label")
|
||||
if(old_info_name == QLatin1String("label")
|
||||
|| old_info_name == QETInformation::ELMT_TERMINAL_NUMBER)
|
||||
{
|
||||
clearFormulaConnection();
|
||||
updateXref();
|
||||
@@ -538,14 +572,25 @@ void DynamicElementTextItem::setInfoName(const QString &info_name)
|
||||
conductorPropertiesChanged();
|
||||
}
|
||||
}
|
||||
else if (m_info_name == "label" && elementUseForInfo())
|
||||
else if ((m_info_name == QLatin1String("label")
|
||||
|| m_info_name == QETInformation::ELMT_TERMINAL_NUMBER)
|
||||
&& elementUseForInfo())
|
||||
{
|
||||
setupFormulaConnection();
|
||||
updateLabel();
|
||||
updateXref();
|
||||
}
|
||||
else if(elementUseForInfo() && m_text_from == DynamicElementTextItem::ElementInfo) {
|
||||
setPlainText(elementUseForInfo()->elementInformations().value(info_name).toString());
|
||||
setPlainText(elementUseForInfo()->infoForDisplay(info_name));
|
||||
}
|
||||
|
||||
//A field which becomes, or stops being, the field for the
|
||||
//terminal number changes what the label of the symbol leaves
|
||||
//to it (@sa Element::labelForDisplay)
|
||||
if (parentElement()
|
||||
&& (info_name == QETInformation::ELMT_TERMINAL_NUMBER
|
||||
|| old_info_name == QETInformation::ELMT_TERMINAL_NUMBER)) {
|
||||
parentElement()->refreshLabelFields();
|
||||
}
|
||||
|
||||
emit infoNameChanged(info_name);
|
||||
@@ -1174,6 +1219,12 @@ void DynamicElementTextItem::elementInfoChanged()
|
||||
Element *element = elementUseForInfo();
|
||||
if(element) {
|
||||
dc = element->elementInformations();
|
||||
//The label and the terminal number are drawn the way the
|
||||
//settings say (@sa QetSettings::terminalLabelSplit): a
|
||||
//composite text which uses them must see the same values the
|
||||
//fields bound to them show
|
||||
dc.addValue(QETInformation::ELMT_LABEL, element->labelForDisplay());
|
||||
dc.addValue(QETInformation::ELMT_TERMINAL_NUMBER, element->terminalNumberForDisplay());
|
||||
}
|
||||
|
||||
QString final_text;
|
||||
@@ -1183,12 +1234,13 @@ void DynamicElementTextItem::elementInfoChanged()
|
||||
{
|
||||
//If the info is the label, then we must make some connection
|
||||
//if the label is created from a formula
|
||||
if(m_info_name == "label")
|
||||
if(m_info_name == QLatin1String("label")
|
||||
|| m_info_name == QETInformation::ELMT_TERMINAL_NUMBER)
|
||||
{
|
||||
setupFormulaConnection();
|
||||
|
||||
if (element) {
|
||||
final_text = element->actualLabel();
|
||||
final_text = element->infoForDisplay(m_info_name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1199,7 +1251,7 @@ void DynamicElementTextItem::elementInfoChanged()
|
||||
{
|
||||
//If the composite have the label variable, we must make some
|
||||
//connection if the label is created from a formula
|
||||
if (m_composite_text.contains("%{label}"))
|
||||
if (usesLabelVariables(m_composite_text))
|
||||
setupFormulaConnection();
|
||||
|
||||
//A report's %{label} is where its partner is, not its own
|
||||
@@ -1367,8 +1419,10 @@ void DynamicElementTextItem::removeConnectionForReportFormula(const QString &for
|
||||
*/
|
||||
void DynamicElementTextItem::setupFormulaConnection()
|
||||
{
|
||||
if ((m_text_from == ElementInfo && m_info_name == "label") ||
|
||||
(m_text_from == CompositeText && m_composite_text.contains("%{label}")))
|
||||
if ((m_text_from == ElementInfo &&
|
||||
(m_info_name == QLatin1String("label")
|
||||
|| m_info_name == QETInformation::ELMT_TERMINAL_NUMBER)) ||
|
||||
(m_text_from == CompositeText && usesLabelVariables(m_composite_text)))
|
||||
{
|
||||
clearFormulaConnection();
|
||||
|
||||
@@ -1458,8 +1512,10 @@ void DynamicElementTextItem::updateReportText()
|
||||
*/
|
||||
void DynamicElementTextItem::updateLabel()
|
||||
{
|
||||
if ((m_text_from == ElementInfo && m_info_name == "label") ||
|
||||
(m_text_from == CompositeText && m_composite_text.contains("%{label}")))
|
||||
if ((m_text_from == ElementInfo &&
|
||||
(m_info_name == QLatin1String("label")
|
||||
|| m_info_name == QETInformation::ELMT_TERMINAL_NUMBER)) ||
|
||||
(m_text_from == CompositeText && usesLabelVariables(m_composite_text)))
|
||||
{
|
||||
DiagramContext dc;
|
||||
Element *element = elementUseForInfo();
|
||||
@@ -1469,19 +1525,21 @@ void DynamicElementTextItem::updateLabel()
|
||||
|
||||
|
||||
if(m_text_from == ElementInfo && element) {
|
||||
QString new_label = element->actualLabel();
|
||||
QString new_label = element->infoForDisplay(m_info_name);
|
||||
if (toPlainText() != new_label) {
|
||||
setPlainText(new_label);
|
||||
}
|
||||
}
|
||||
else if (m_text_from == CompositeText) {
|
||||
// Use actualLabel() to ensure %{label} reflects the current
|
||||
// resolved label (e.g. after a folio/page-number change).
|
||||
// Use the label as it must be drawn, so %{label} and
|
||||
// %{terminal_number} reflect the current resolved label (e.g.
|
||||
// after a folio/page-number change).
|
||||
// A contact not linked to a coil has no element to read from
|
||||
// (bugtracker #345): %{label} then shows empty, as it did
|
||||
// before actualLabel() was used here.
|
||||
if (element) {
|
||||
dc.addValue(QStringLiteral("label"), element->actualLabel());
|
||||
dc.addValue(QETInformation::ELMT_LABEL, element->labelForDisplay());
|
||||
dc.addValue(QETInformation::ELMT_TERMINAL_NUMBER, element->terminalNumberForDisplay());
|
||||
}
|
||||
setPlainText(autonum::AssignVariables::replaceVariable(m_composite_text, dc));
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "../properties/terminaldata.h"
|
||||
#include "../properties/xrefproperties.h"
|
||||
#include "../qetinformation.h"
|
||||
#include "../utils/qetsettings.h"
|
||||
#include "../qetgraphicsitem/conductor.h"
|
||||
#include "../qetgraphicsitem/terminal.h"
|
||||
#include "../ui/elementpropertieswidget.h"
|
||||
@@ -1689,6 +1690,13 @@ void Element::addDynamicTextItem(DynamicElementTextItem *deti)
|
||||
|
||||
m_dynamic_text_list.append(deti);
|
||||
|
||||
//A field of its own for the terminal number is what the label
|
||||
//leaves the number to: the fields which draw the label follow
|
||||
//when such a field lands on the symbol
|
||||
if (deti->infoName() == QETInformation::ELMT_TERMINAL_NUMBER) {
|
||||
refreshLabelFields();
|
||||
}
|
||||
|
||||
//On a mirrored element, the mirror of the text depends on the size
|
||||
//and the rotation of the text, see keepReadable()
|
||||
connect(deti->document()->documentLayout(),
|
||||
@@ -1724,6 +1732,9 @@ void Element::removeDynamicTextItem(DynamicElementTextItem *deti)
|
||||
m_dynamic_text_list.removeOne(deti);
|
||||
deti->setParentItem(nullptr);
|
||||
forget();
|
||||
if (deti->infoName() == QETInformation::ELMT_TERMINAL_NUMBER) {
|
||||
refreshLabelFields();
|
||||
}
|
||||
emit textRemoved(deti);
|
||||
return;
|
||||
}
|
||||
@@ -1736,12 +1747,36 @@ void Element::removeDynamicTextItem(DynamicElementTextItem *deti)
|
||||
m_dynamic_text_list.removeOne(deti);
|
||||
deti->setParentItem(nullptr);
|
||||
forget();
|
||||
if (deti->infoName() == QETInformation::ELMT_TERMINAL_NUMBER) {
|
||||
refreshLabelFields();
|
||||
}
|
||||
emit textRemoved(deti);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::refreshLabelFields
|
||||
The fields which draw the label draw it again: what they show of the
|
||||
label has changed under them (a field for the terminal number added
|
||||
or removed, @sa Element::hasTerminalNumberText), or the terminal
|
||||
labelling setting was switched (@sa QetSettings::terminalLabelSplit).
|
||||
Only the fields which draw a label are refreshed, every other field
|
||||
follows its own information.
|
||||
*/
|
||||
void Element::refreshLabelFields()
|
||||
{
|
||||
for (DynamicElementTextItem *text : m_dynamic_text_list) {
|
||||
text->refreshLabelConnection();
|
||||
}
|
||||
for (ElementTextItemGroup *group : m_texts_group) {
|
||||
for (DynamicElementTextItem *text : group->texts()) {
|
||||
text->refreshLabelConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::dynamicTextItems
|
||||
@return all dynamic text items of this element directly child of this element.
|
||||
@@ -2721,6 +2756,105 @@ QString Element::actualLabel()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::labelForDisplay
|
||||
@return the label as the drawing must show it, the settings of the
|
||||
moment being read (@sa QetSettings::terminalLabelSplit): the whole
|
||||
label ("X1:1") while the labelling is shown in one field; the label
|
||||
alone ("X1") when it is shown split and this symbol has a text field
|
||||
of its own for the terminal number; and the two one under the other
|
||||
when it is split without such a field -- so a symbol drawn before
|
||||
the setting existed still shows all of its label, only shorter.
|
||||
*/
|
||||
QString Element::labelForDisplay()
|
||||
{
|
||||
const QString label = actualLabel();
|
||||
if (!QetSettings::terminalLabelSplit()) {
|
||||
return label;
|
||||
}
|
||||
|
||||
const int colon = label.lastIndexOf(QLatin1Char(':'));
|
||||
if (colon < 0) {
|
||||
return label;
|
||||
}
|
||||
|
||||
if (hasTerminalNumberText()) {
|
||||
return label.left(colon);
|
||||
}
|
||||
|
||||
return label.left(colon) + QLatin1Char('\n') + label.mid(colon + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::terminalNumberForDisplay
|
||||
@return the part of the label behind its last colon ("1" in "X1:1"),
|
||||
or an empty string while the labelling is shown in one field: the
|
||||
number is already there with the label, showing it twice would only
|
||||
be noise. @sa labelForDisplay
|
||||
*/
|
||||
QString Element::terminalNumberForDisplay()
|
||||
{
|
||||
if (!QetSettings::terminalLabelSplit()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
const QString label = actualLabel();
|
||||
const int colon = label.lastIndexOf(QLatin1Char(':'));
|
||||
if (colon < 0) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return label.mid(colon + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::hasTerminalNumberText
|
||||
@return whether this symbol has a text field bound to the terminal
|
||||
number, the field labelForDisplay() leaves the number to.
|
||||
*/
|
||||
bool Element::hasTerminalNumberText() const
|
||||
{
|
||||
auto is_number_field = [](const DynamicElementTextItem *text) {
|
||||
return text
|
||||
&& text->textFrom() == DynamicElementTextItem::ElementInfo
|
||||
&& text->infoName() == QETInformation::ELMT_TERMINAL_NUMBER;
|
||||
};
|
||||
|
||||
for (const DynamicElementTextItem *text : dynamicTextItems()) {
|
||||
if (is_number_field(text)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//The field may just as well live in a text group of the symbol
|
||||
for (const ElementTextItemGroup *group : m_texts_group) {
|
||||
for (const DynamicElementTextItem *text : group->texts()) {
|
||||
if (is_number_field(text)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::infoForDisplay
|
||||
@return what a text field bound to @p info_name must show: the label
|
||||
and the terminal number follow how the labelling is drawn, every
|
||||
other information is the stored one. @sa labelForDisplay
|
||||
*/
|
||||
QString Element::infoForDisplay(const QString &info_name)
|
||||
{
|
||||
if (info_name == QETInformation::ELMT_LABEL) {
|
||||
return labelForDisplay();
|
||||
}
|
||||
if (info_name == QETInformation::ELMT_TERMINAL_NUMBER) {
|
||||
return terminalNumberForDisplay();
|
||||
}
|
||||
|
||||
return m_data.m_informations.value(info_name).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::name
|
||||
@return the human name of this element
|
||||
|
||||
@@ -165,6 +165,24 @@ class Element : public QetGraphicsItem
|
||||
bool isFreezeLabel() const {return m_freeze_label;}
|
||||
void freezeNewAddedElement();
|
||||
QString actualLabel();
|
||||
/**
|
||||
What the drawing shows of the label and of the terminal
|
||||
number, the terminal labelling setting of the moment being
|
||||
read (@sa QetSettings::terminalLabelSplit). The label itself
|
||||
is never changed by any of them.
|
||||
*/
|
||||
QString labelForDisplay();
|
||||
QString terminalNumberForDisplay();
|
||||
QString infoForDisplay(const QString &info_name);
|
||||
bool hasTerminalNumberText() const;
|
||||
/**
|
||||
The fields which draw the label draw it again: called when
|
||||
what they show of the label has changed under them, a
|
||||
field for the terminal number added or removed, or the
|
||||
terminal labelling setting switched (@sa
|
||||
QetSettings::terminalLabelSplit).
|
||||
*/
|
||||
void refreshLabelFields();
|
||||
|
||||
QString name() const override;
|
||||
ElementsLocation location() const;
|
||||
|
||||
@@ -142,6 +142,7 @@ QStringList QETInformation::elementInfoKeys()
|
||||
{
|
||||
QStringList list = { ELMT_FORMULA,
|
||||
ELMT_LABEL,
|
||||
ELMT_TERMINAL_NUMBER,
|
||||
ELMT_PLANT,
|
||||
ELMT_LOCATION,
|
||||
ELMT_COMMENT,
|
||||
@@ -311,6 +312,7 @@ QString QETInformation::translatedInfoKey(const QString &info)
|
||||
else if (info == PROJECT_SAVED_FILE_PATH) return QObject::tr("Saved file path");
|
||||
else if (info == ELMT_FORMULA) return QObject::tr("Label formula");
|
||||
else if (info == ELMT_LABEL) return QObject::tr("Label");
|
||||
else if (info == ELMT_TERMINAL_NUMBER) return QObject::tr("Terminal number");
|
||||
else if (info == ELMT_COMMENT) return QObject::tr("Annotation");
|
||||
else if (info == ELMT_FUNCTION) return QObject::tr("Function");
|
||||
else if (info == ELMT_DESCRIPTION) return QObject::tr("Textual description");
|
||||
|
||||
@@ -39,6 +39,10 @@ namespace QETInformation
|
||||
{
|
||||
/** Default information related to element **/
|
||||
static QString ELMT_LABEL = "label";
|
||||
//The part of the label behind its last colon ("1" in "X1:1"),
|
||||
//shown in a text field of its own when the terminal labelling
|
||||
//is drawn split (@sa QetSettings::terminalLabelSplit)
|
||||
static QString ELMT_TERMINAL_NUMBER = "terminal_number";
|
||||
static QString ELMT_FORMULA = "formula";
|
||||
/**
|
||||
Uuid of the project's element numbering scheme the element's
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <QSettings>
|
||||
|
||||
#include "../../diagram.h"
|
||||
#include "../../qetgraphicsitem/element.h"
|
||||
#include "../../qetproject.h"
|
||||
|
||||
namespace {
|
||||
@@ -161,6 +162,11 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
|
||||
enable(ui->m_wiring_rules_cb->isChecked());
|
||||
connect(ui->m_wiring_rules_cb, &QCheckBox::toggled, this, enable);
|
||||
}
|
||||
if (QetSettings::terminalLabelSplit()) {
|
||||
ui->m_terminal_label_split_rb->setChecked(true);
|
||||
} else {
|
||||
ui->m_terminal_label_combined_rb->setChecked(true);
|
||||
}
|
||||
ui->m_use_gesture_trackpad->setChecked(settings.value("diagramview/gestures", false).toBool());
|
||||
ui->m_save_label_paste->setChecked(settings.value("diagramcommands/erase-label-on-copy", true).toBool());
|
||||
ui->m_autonumber_pasted->setChecked(settings.value("diagramcommands/autonumber-pasted-elements", true).toBool());
|
||||
@@ -415,6 +421,19 @@ void GeneralConfigurationPage::applyConf()
|
||||
if (WiringRules::masterEnabled() && WiringRules::turnsRuleOn(before, rules)) {
|
||||
WiringRulesWarning::show(this);
|
||||
}
|
||||
}
|
||||
//The labelling setting is read where the label is drawn, so the
|
||||
//drawings already open are told to draw it again when it changes
|
||||
const bool label_split = ui->m_terminal_label_split_rb->isChecked();
|
||||
if (QetSettings::terminalLabelSplit() != label_split) {
|
||||
QetSettings::setTerminalLabelSplit(label_split);
|
||||
for (QETProject *project : QETApp::registeredProjects()) {
|
||||
for (Diagram *diagram : project->diagrams()) {
|
||||
for (Element *element : diagram->elements()) {
|
||||
element->refreshLabelFields();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
settings.setValue("diagrameditor/autosave-interval", ui->m_autosave_sb->value());
|
||||
settings.setValue("projectlock/enabled", ui->m_project_lock->isChecked());
|
||||
|
||||
@@ -140,6 +140,48 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="m_terminal_label_group">
|
||||
<property name="title">
|
||||
<string>Display of the terminal labelling</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="m_terminal_label_layout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="m_terminal_label_combined_rb">
|
||||
<property name="toolTip">
|
||||
<string>A terminal's label (X1:1) is drawn as a whole, the way it has always been.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show the label and the terminal number in one field</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="m_terminal_label_split_rb">
|
||||
<property name="toolTip">
|
||||
<string>The label (X1) is drawn in one field and the terminal number (1) in another, which a terminal symbol may place where it wants -- and hide when it must. A symbol without such a field shows the two, one under the other.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Split the label and the terminal number</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="m_terminal_label_help">
|
||||
<property name="text">
|
||||
<string>Only the drawing changes: what is written in the element, the numbering, the sorting and the exports keep the whole label.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -290,4 +290,28 @@ namespace QetSettings
|
||||
QSettings settings;
|
||||
settings.setValue(QStringLiteral("diagrameditor/sheet_background_recent"), colors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief terminalLabelSplit
|
||||
* @return whether a terminal's label is drawn split, the label and
|
||||
* the terminal number each in their own text field, instead of the
|
||||
* whole label ("X1:1") in one field. Off unless the user turned it
|
||||
* on, so an existing drawing keeps its look. @sa setTerminalLabelSplit
|
||||
*/
|
||||
bool terminalLabelSplit()
|
||||
{
|
||||
QSettings settings;
|
||||
return settings.value(QStringLiteral("element/terminal_label_split"), false).toBool();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief setTerminalLabelSplit
|
||||
* Store whether a terminal's label is drawn split. @sa terminalLabelSplit
|
||||
* @param split
|
||||
*/
|
||||
void setTerminalLabelSplit(bool split)
|
||||
{
|
||||
QSettings settings;
|
||||
settings.setValue(QStringLiteral("element/terminal_label_split"), split);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,20 @@ namespace QetSettings
|
||||
|
||||
QStringList sheetBackgroundRecentColors();
|
||||
void setSheetBackgroundRecentColors(const QStringList &colors);
|
||||
|
||||
/**
|
||||
@brief How a terminal's own label is drawn.
|
||||
|
||||
The label is stored as it is written ("X1:1"). With the split on,
|
||||
the drawing shows the label ("X1") and the terminal number ("1")
|
||||
as two parts, so a terminal symbol can keep the number in its own
|
||||
text field and place it where it wants. Only the drawing reacts:
|
||||
what the element stores, the numbering, the sorting in the
|
||||
terminal strip editor and every export keep the whole label.
|
||||
Off by default, so a drawing keeps the look it was made with.
|
||||
*/
|
||||
bool terminalLabelSplit();
|
||||
void setTerminalLabelSplit(bool split);
|
||||
}
|
||||
|
||||
#endif // QETSETTINGS_H
|
||||
|
||||
@@ -323,6 +323,13 @@ qet_add_app_test(tst_reportfoliotitle tst_reportfoliotitle.cpp)
|
||||
# what was typed in, and nothing stale is written into the element.
|
||||
qet_add_app_test(tst_terminalcableauto tst_terminalcableauto.cpp)
|
||||
|
||||
# A terminal's label is drawn whole in one field, or split into its label
|
||||
# and its terminal number: in their own fields when the symbol carries a
|
||||
# field for the number, one under the other when it does not. Only the
|
||||
# drawing changes; the stored label, the numbering and the exports keep
|
||||
# the whole label.
|
||||
qet_add_app_test(tst_terminallabeldisplay tst_terminallabeldisplay.cpp)
|
||||
|
||||
# Escape during a picture's resize, rotate or pivot drag puts it back, keeps
|
||||
# it selected and records no undo step (#1414); the key goes to the view.
|
||||
qet_add_app_test(tst_imagehandleescape tst_imagehandleescape.cpp)
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech 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 QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qetapptest.h"
|
||||
#include "TerminalStrip/realterminal.h"
|
||||
#include "TerminalStrip/terminalstrip.h"
|
||||
#include "qetgraphicsitem/dynamicelementtextitem.h"
|
||||
#include "qetgraphicsitem/element.h"
|
||||
#include "qetgraphicsitem/terminal.h"
|
||||
#include "qetinformation.h"
|
||||
#include "qetproject.h"
|
||||
#include "utils/qetsettings.h"
|
||||
|
||||
/**
|
||||
How a terminal's own label is drawn, the setting of the moment being
|
||||
read (@sa QetSettings::terminalLabelSplit).
|
||||
|
||||
The label stays whole wherever it is used as data: what the element
|
||||
stores, the numbering, the sorting in the terminal strip editor and
|
||||
the exports are never touched by the setting. Only the drawing reacts:
|
||||
with the labelling split, the label ("X1") and the terminal number
|
||||
("1") are two parts -- in their own fields when the symbol has a
|
||||
field for the number, one under the other when it has not.
|
||||
|
||||
fixtures/every_feature.qet has the strip X1 whose terminals are
|
||||
plain terminal symbols: a field tagged "label", no field for the
|
||||
number, and -- as every element of the fixture -- a label the test
|
||||
gives them before it looks at the drawing.
|
||||
*/
|
||||
class tst_terminallabeldisplay : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
//A terminal element of the fixture's strip X1, given @p label
|
||||
static Element *terminalWithLabel(QETProject &project, const QString &label)
|
||||
{
|
||||
const QVector<TerminalStrip *> strips = project.terminalStrip();
|
||||
if (strips.isEmpty()) return nullptr;
|
||||
for (const QSharedPointer<RealTerminal> &real_t
|
||||
: strips.first()->realTerminals())
|
||||
{
|
||||
Element *element = real_t ? real_t->element() : nullptr;
|
||||
if (!element || element->terminals().isEmpty()) continue;
|
||||
|
||||
DiagramContext dc = element->elementInformations();
|
||||
dc.addValue(QStringLiteral("label"), label);
|
||||
element->setElementInformations(dc);
|
||||
if (element->actualLabel() == label) return element;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//The text field of @p element bound to @p info_name, the field the
|
||||
//symbol carries for it
|
||||
static DynamicElementTextItem *fieldBoundTo(Element *element, const QString &info_name)
|
||||
{
|
||||
for (DynamicElementTextItem *text : element->dynamicTextItems())
|
||||
if (text->infoName() == info_name) return text;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//A text field as a symbol made for the split would carry one: bound
|
||||
//to the terminal number, and nothing else
|
||||
static DynamicElementTextItem *addNumberField(Element *element)
|
||||
{
|
||||
DynamicElementTextItem *number = new DynamicElementTextItem(element);
|
||||
element->addDynamicTextItem(number);
|
||||
number->setInfoName(QETInformation::ELMT_TERMINAL_NUMBER);
|
||||
number->setTextFrom(DynamicElementTextItem::ElementInfo);
|
||||
return number;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void cleanup()
|
||||
{
|
||||
//Whatever a test left behind, the next one (and the rest of
|
||||
//the suite) starts from the shipped default
|
||||
QetSettings::setTerminalLabelSplit(false);
|
||||
}
|
||||
|
||||
//The shipped default: one field with the whole label, the way it has
|
||||
//always been drawn
|
||||
void oneFieldKeepsTheWholeLabel()
|
||||
{
|
||||
QetSettings::setTerminalLabelSplit(false);
|
||||
|
||||
const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
|
||||
QETProject project(fixture);
|
||||
QCOMPARE(project.state(), QETProject::Ok);
|
||||
|
||||
Element *element = terminalWithLabel(project, QStringLiteral("X1:1"));
|
||||
QVERIFY2(element, "the fixture has a terminal of the strip X1");
|
||||
|
||||
QCOMPARE(element->actualLabel(), QStringLiteral("X1:1"));
|
||||
QCOMPARE(element->labelForDisplay(), QStringLiteral("X1:1"));
|
||||
QVERIFY(element->terminalNumberForDisplay().isEmpty());
|
||||
QVERIFY(element->infoForDisplay(QETInformation::ELMT_TERMINAL_NUMBER).isEmpty());
|
||||
QVERIFY(!element->hasTerminalNumberText());
|
||||
|
||||
//The field the symbol carries shows the whole label
|
||||
DynamicElementTextItem *label = fieldBoundTo(element, QETInformation::ELMT_LABEL);
|
||||
QVERIFY2(label, "the terminal symbol has a field for its label");
|
||||
QCOMPARE(label->toPlainText(), QStringLiteral("X1:1"));
|
||||
}
|
||||
|
||||
//Split, and the symbol has no field for the number: the number stays
|
||||
//with the label, on its own line, so that switching the setting on
|
||||
//can never make a number vanish
|
||||
void splitWithoutNumberFieldShowsTwoLines()
|
||||
{
|
||||
QetSettings::setTerminalLabelSplit(true);
|
||||
|
||||
const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
|
||||
QETProject project(fixture);
|
||||
QCOMPARE(project.state(), QETProject::Ok);
|
||||
|
||||
Element *element = terminalWithLabel(project, QStringLiteral("X1:1"));
|
||||
QVERIFY(element);
|
||||
|
||||
QCOMPARE(element->labelForDisplay(), QStringLiteral("X1\n1"));
|
||||
QCOMPARE(element->terminalNumberForDisplay(), QStringLiteral("1"));
|
||||
QCOMPARE(element->infoForDisplay(QETInformation::ELMT_TERMINAL_NUMBER),
|
||||
QStringLiteral("1"));
|
||||
|
||||
DynamicElementTextItem *label = fieldBoundTo(element, QETInformation::ELMT_LABEL);
|
||||
QVERIFY(label);
|
||||
QCOMPARE(label->toPlainText(), QStringLiteral("X1\n1"));
|
||||
|
||||
//A text which uses the label as a variable follows the same
|
||||
//rule as the field bound to the label itself
|
||||
DynamicElementTextItem *composite = new DynamicElementTextItem(element);
|
||||
composite->setCompositeText(QStringLiteral("%{label}"));
|
||||
composite->setTextFrom(DynamicElementTextItem::CompositeText);
|
||||
QCOMPARE(composite->toPlainText(), QStringLiteral("X1\n1"));
|
||||
}
|
||||
|
||||
//Split, and the symbol has a field of its own for the number: each
|
||||
//part in its field, the label no longer carrying the number
|
||||
void splitWithNumberFieldShowsEachInItsOwnField()
|
||||
{
|
||||
QetSettings::setTerminalLabelSplit(true);
|
||||
|
||||
const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
|
||||
QETProject project(fixture);
|
||||
QCOMPARE(project.state(), QETProject::Ok);
|
||||
|
||||
Element *element = terminalWithLabel(project, QStringLiteral("X1:1"));
|
||||
QVERIFY(element);
|
||||
|
||||
DynamicElementTextItem *number = addNumberField(element);
|
||||
QVERIFY(element->hasTerminalNumberText());
|
||||
QCOMPARE(number->toPlainText(), QStringLiteral("1"));
|
||||
|
||||
QCOMPARE(element->labelForDisplay(), QStringLiteral("X1"));
|
||||
DynamicElementTextItem *label = fieldBoundTo(element, QETInformation::ELMT_LABEL);
|
||||
QVERIFY(label);
|
||||
QCOMPARE(label->toPlainText(), QStringLiteral("X1"));
|
||||
}
|
||||
|
||||
//A label with no colon -- every label which is not a terminal's, and
|
||||
//a terminal named by hand -- is drawn as it is stored, whatever the
|
||||
//setting says
|
||||
void splitLeavesLabelsWithoutColonAlone()
|
||||
{
|
||||
QetSettings::setTerminalLabelSplit(true);
|
||||
|
||||
const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
|
||||
QETProject project(fixture);
|
||||
QCOMPARE(project.state(), QETProject::Ok);
|
||||
|
||||
Element *element = terminalWithLabel(project, QStringLiteral("S7"));
|
||||
QVERIFY(element);
|
||||
|
||||
QCOMPARE(element->labelForDisplay(), QStringLiteral("S7"));
|
||||
QVERIFY(element->terminalNumberForDisplay().isEmpty());
|
||||
|
||||
DynamicElementTextItem *label = fieldBoundTo(element, QETInformation::ELMT_LABEL);
|
||||
QVERIFY(label);
|
||||
QCOMPARE(label->toPlainText(), QStringLiteral("S7"));
|
||||
}
|
||||
|
||||
//The setting is read where it is drawn: the settings page tells the
|
||||
//drawings already open to draw it again, and the whole label comes
|
||||
//back without anything to rewrite first
|
||||
void switchingBackGivesTheWholeLabel()
|
||||
{
|
||||
const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
|
||||
QETProject project(fixture);
|
||||
QCOMPARE(project.state(), QETProject::Ok);
|
||||
|
||||
QetSettings::setTerminalLabelSplit(true);
|
||||
Element *element = terminalWithLabel(project, QStringLiteral("X1:1"));
|
||||
QVERIFY(element);
|
||||
DynamicElementTextItem *label = fieldBoundTo(element, QETInformation::ELMT_LABEL);
|
||||
QVERIFY(label);
|
||||
QCOMPARE(label->toPlainText(), QStringLiteral("X1\n1"));
|
||||
|
||||
QetSettings::setTerminalLabelSplit(false);
|
||||
element->refreshLabelFields();
|
||||
QCOMPARE(label->toPlainText(), QStringLiteral("X1:1"));
|
||||
QCOMPARE(element->actualLabel(), QStringLiteral("X1:1"));
|
||||
}
|
||||
};
|
||||
|
||||
QET_APP_TEST_MAIN(tst_terminallabeldisplay)
|
||||
#include "tst_terminallabeldisplay.moc"
|
||||
Reference in New Issue
Block a user