mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-14 09:14:14 +02:00
Merge pull request #1456 from Kellermorph/terminal-potential
Terminal: rename potential separation to function separation
This commit is contained in:
@@ -226,9 +226,12 @@ void SearchAndReplaceWorker::replaceConductor(QList<Conductor *> list)
|
||||
project_->undoStack()->beginMacro(QObject::tr("Search / replace conductors properties."));
|
||||
for (Conductor *c : list)
|
||||
{
|
||||
ConductorProperties cp = applyChange(c->properties(), m_conductor_properties);
|
||||
//Captured before the pushes below: QPropertyUndoCommand applies
|
||||
//on push, so reading it afterwards would give back @a cp.
|
||||
const ConductorProperties old_properties = c->properties();
|
||||
ConductorProperties cp = applyChange(old_properties, m_conductor_properties);
|
||||
|
||||
if (cp != c->properties())
|
||||
if (cp != old_properties)
|
||||
{
|
||||
QSet <Conductor *> conductors_list = c->relatedPotentialConductors(true);
|
||||
conductors_list << c;
|
||||
@@ -239,6 +242,26 @@ void SearchAndReplaceWorker::replaceConductor(QList<Conductor *> list)
|
||||
new_value.setValue(cp);
|
||||
project_->undoStack()->push(new QPropertyUndoCommand(cc, "properties", old_value, new_value));
|
||||
}
|
||||
|
||||
//The other side of a function separated terminal element
|
||||
//only receives the voltage / protocol, and only when this
|
||||
//replacement really changed it: the comparison is this
|
||||
//replacement's own before / after (@a old_properties vs
|
||||
//@a cp), never the far wire's own value, which would make
|
||||
//every replacement overwrite it (@see
|
||||
//Conductor::functionSeparatedConductors).
|
||||
for (Conductor *cc : c->functionSeparatedConductors(true))
|
||||
{
|
||||
ConductorProperties separated_cp = cc->properties();
|
||||
separated_cp.applyTensionProtocolChange(old_properties, cp);
|
||||
if (separated_cp == cc->properties())
|
||||
continue;
|
||||
|
||||
QVariant old_value, new_value;
|
||||
old_value.setValue(cc->properties());
|
||||
new_value.setValue(separated_cp);
|
||||
project_->undoStack()->push(new QPropertyUndoCommand(cc, "properties", old_value, new_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
project_->undoStack()->endMacro();
|
||||
@@ -351,6 +374,25 @@ void SearchAndReplaceWorker::replaceAdvanced(
|
||||
new_value.setValue(new_properties);
|
||||
project_->undoStack()->push(new QPropertyUndoCommand(c, "properties", old_value, new_value));
|
||||
}
|
||||
|
||||
//The other side of a function separated terminal element
|
||||
//only receives the voltage / protocol, and only when
|
||||
//this replacement really changed it: the comparison is
|
||||
//this replacement's own before / after, never the far
|
||||
//wire's own value (@see
|
||||
//Conductor::functionSeparatedConductors).
|
||||
for (Conductor *c : conductor->functionSeparatedConductors(true))
|
||||
{
|
||||
ConductorProperties separated_properties = c->properties();
|
||||
separated_properties.applyTensionProtocolChange(old_properties, new_properties);
|
||||
if (separated_properties == c->properties())
|
||||
continue;
|
||||
|
||||
QVariant old_value, new_value;
|
||||
old_value.setValue(c->properties());
|
||||
new_value.setValue(separated_properties);
|
||||
project_->undoStack()->push(new QPropertyUndoCommand(c, "properties", old_value, new_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,33 +62,80 @@ namespace ConductorMultiEdit
|
||||
@brief targets
|
||||
@param selected : the edited conductors
|
||||
@param apply_all : true to add every conductor of their potentials
|
||||
@param function_separated : set to the conductors that share the
|
||||
potential of an edited one only by crossing a function separated
|
||||
terminal element -- conductors undo() then gives the voltage /
|
||||
protocol only, and no other property. nullptr, the default, leaves
|
||||
those conductors out of the returned list entirely.
|
||||
|
||||
A conductor the user picked themselves is never part of it: the
|
||||
selection is the edit reaching that conductor, so it takes the
|
||||
full edit however remote it is from the other selected ones --
|
||||
picking a wire on each side of a separation and editing them is
|
||||
exactly that. Nor is a conductor that belongs to a potential, on
|
||||
any path, however far that potential is reached.
|
||||
@return each conductor an edit reaches, once
|
||||
*/
|
||||
template <typename T>
|
||||
QList<T *> targets(const QList<T *> &selected, bool apply_all)
|
||||
QList<T *> targets(const QList<T *> &selected, bool apply_all,
|
||||
QSet<T *> *function_separated = nullptr)
|
||||
{
|
||||
QList<T *> list;
|
||||
QSet<T *> seen;
|
||||
//The explicitly picked ones, so a separation met while walking
|
||||
//the list cannot demote a wire the user asked to edit.
|
||||
QSet<T *> chosen;
|
||||
for (T *conductor : selected)
|
||||
if (conductor)
|
||||
chosen.insert(conductor);
|
||||
//What the potentials reach, and what only a function separation
|
||||
//reaches. A conductor can be in both -- wired normally on one
|
||||
//path and across a separation on another -- and then belongs to
|
||||
//the potential.
|
||||
QSet<T *> potential_reached, separated_reached;
|
||||
|
||||
for (T *conductor : selected)
|
||||
{
|
||||
//Already reached through an earlier conductor's potential:
|
||||
//its own potential is the same one.
|
||||
if (!conductor || seen.contains(conductor))
|
||||
if (!conductor)
|
||||
continue;
|
||||
seen.insert(conductor);
|
||||
list << conductor;
|
||||
if (!apply_all)
|
||||
//Already reached through an earlier conductor's potential or
|
||||
//separation: its own potential adds nothing new to walk over
|
||||
//-- unless the user picked it, because a separation may have
|
||||
//put it in the list before its potential was ever reached.
|
||||
const bool fresh = !seen.contains(conductor);
|
||||
if (fresh)
|
||||
{
|
||||
seen.insert(conductor);
|
||||
list << conductor;
|
||||
}
|
||||
if (!apply_all || (!fresh && !chosen.contains(conductor)))
|
||||
continue;
|
||||
const QSet<T *> potential = conductor->relatedPotentialConductors();
|
||||
for (T *other : potential)
|
||||
{
|
||||
potential_reached.insert(other);
|
||||
if (!seen.contains(other))
|
||||
{
|
||||
seen.insert(other);
|
||||
list << other;
|
||||
}
|
||||
}
|
||||
if (function_separated)
|
||||
{
|
||||
const QSet<T *> separated = conductor->functionSeparatedConductors();
|
||||
for (T *other : separated)
|
||||
{
|
||||
separated_reached.insert(other);
|
||||
if (!seen.contains(other))
|
||||
{
|
||||
seen.insert(other);
|
||||
list << other;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (function_separated)
|
||||
*function_separated = separated_reached - potential_reached - chosen;
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -97,13 +144,18 @@ namespace ConductorMultiEdit
|
||||
@param targets : the conductors to change, see targets()
|
||||
@param shown : the properties as the panel showed them
|
||||
@param edited : the properties after the user's edit
|
||||
@param function_separated : the targets of targets() that only a
|
||||
function separated terminal element links to the edited
|
||||
conductors: they get the voltage / protocol and nothing else
|
||||
(@see ConductorProperties::applyTensionProtocolChange)
|
||||
@return one undo step giving each target the fields that differ
|
||||
between shown and edited, or nullptr if no conductor changes
|
||||
*/
|
||||
template <typename T>
|
||||
QUndoCommand *undo(const QList<T *> &targets,
|
||||
const ConductorProperties &shown,
|
||||
const ConductorProperties &edited)
|
||||
const ConductorProperties &edited,
|
||||
const QSet<T *> &function_separated = QSet<T *>())
|
||||
{
|
||||
if (edited == shown)
|
||||
return nullptr;
|
||||
@@ -114,7 +166,10 @@ namespace ConductorMultiEdit
|
||||
{
|
||||
const ConductorProperties old_properties = conductor->properties();
|
||||
ConductorProperties properties = old_properties;
|
||||
properties.applyChanges(shown, edited);
|
||||
if (function_separated.contains(conductor))
|
||||
properties.applyTensionProtocolChange(shown, edited);
|
||||
else
|
||||
properties.applyChanges(shown, edited);
|
||||
if (properties == old_properties)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -851,6 +851,32 @@ void ConductorProperties::applyChanges(const ConductorProperties &before,
|
||||
singleLineProperties.setPhasesCount(slp_after.phasesCount());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ConductorProperties::applyTensionProtocolChange
|
||||
Copy into this the voltage / protocol when it differs between before
|
||||
and after, and leave every other attribute as it is. This is the one
|
||||
property a function separated terminal element lets through
|
||||
(@see Conductor::functionSeparatedConductors): the voltage /
|
||||
protocol describes the electrical node itself, while the text, the
|
||||
function, the wire color... describe one side of the separation and
|
||||
stay local to it.
|
||||
|
||||
Both arguments describe one edit -- what was shown to the user, and
|
||||
what the user made of it -- so that only an edit which really
|
||||
changed the voltage / protocol passes it on. Passing the far wire's
|
||||
own properties as @a before instead would make every edit overwrite
|
||||
its voltage: the two sides differ on that field just as often as
|
||||
not, so the comparison would hold no matter what was edited.
|
||||
@param before : the properties as they were shown to the user
|
||||
@param after : the properties after the user's edit
|
||||
*/
|
||||
void ConductorProperties::applyTensionProtocolChange(const ConductorProperties &before,
|
||||
const ConductorProperties &after)
|
||||
{
|
||||
if (before.m_tension_protocol != after.m_tension_protocol)
|
||||
m_tension_protocol = after.m_tension_protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ConductorProperties::defaultProperties
|
||||
@return the default properties stored in the setting file
|
||||
|
||||
@@ -139,6 +139,8 @@ class ConductorProperties
|
||||
void applyForEqualAttributes(QList<ConductorProperties> list);
|
||||
void applyChanges(const ConductorProperties &before,
|
||||
const ConductorProperties &after);
|
||||
void applyTensionProtocolChange(const ConductorProperties &before,
|
||||
const ConductorProperties &after);
|
||||
|
||||
static ConductorProperties defaultProperties();
|
||||
|
||||
|
||||
@@ -255,7 +255,7 @@
|
||||
<string>margin: 5px; font-weight: bold;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Potential separation</string>
|
||||
<string>Function separation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -107,10 +107,11 @@ class TerminalData : public PropertiesInterface
|
||||
@brief m_potential
|
||||
An optional, symbol-author-chosen grouping identifier shared by
|
||||
terminals that belong to the same physical terminal within
|
||||
a multi-terminal block. When potential_isolating is enabled
|
||||
a multi-terminal block. When the function separation checkbox
|
||||
(element information potential_isolating) is enabled
|
||||
on the parent element, terminals sharing a non-empty,
|
||||
matching m_potential stay linked to each other; terminals
|
||||
with different (or empty) values become isolated from each
|
||||
with different (or empty) values become separated from each
|
||||
other. Empty by default.
|
||||
*/
|
||||
QString m_potential;
|
||||
|
||||
@@ -2005,9 +2005,16 @@ void Conductor::displayedTextChanged()
|
||||
@param all_diagram : if true search in all diagram of the project,
|
||||
false search only in the parent diagram of this conductor
|
||||
@param t_list : a list of terminal already found for this potential.
|
||||
@param ignore_function_separation : if true, a terminal element whose
|
||||
function separation is enabled does not stop the search, and the
|
||||
conductors of both its sides are returned as one potential. Only
|
||||
functionSeparatedConductors() passes true.
|
||||
@sa functionSeparatedConductors
|
||||
@return a QSet of conductor at the same potential.
|
||||
*/
|
||||
QSet<Conductor *> Conductor::relatedPotentialConductors(const bool all_diagram, QList <Terminal *> *t_list)
|
||||
QSet<Conductor *> Conductor::relatedPotentialConductors(const bool all_diagram,
|
||||
QList <Terminal *> *t_list,
|
||||
const bool ignore_function_separation)
|
||||
{
|
||||
bool declar_t_list = false;
|
||||
if (t_list == nullptr)
|
||||
@@ -2030,7 +2037,8 @@ QSet<Conductor *> Conductor::relatedPotentialConductors(const bool all_diagram,
|
||||
|
||||
//Get the other terminals of the parent element of @terminal, who share the same potential
|
||||
//This is use for element type "folio report" and "terminal element"
|
||||
for (Terminal *t : relatedPotentialTerminal(terminal, all_diagram))
|
||||
for (Terminal *t : relatedPotentialTerminal(terminal, all_diagram,
|
||||
ignore_function_separation))
|
||||
{
|
||||
if (!t_list->contains(t))
|
||||
{
|
||||
@@ -2042,7 +2050,8 @@ QSet<Conductor *> Conductor::relatedPotentialConductors(const bool all_diagram,
|
||||
other_conductors_list_t.removeAll(this);
|
||||
//Get the conductors at the same potential for each conductors of other_conductors_list_t
|
||||
for (Conductor *c : other_conductors_list_t) {
|
||||
other_conductors += c->relatedPotentialConductors(all_diagram, t_list);
|
||||
other_conductors += c->relatedPotentialConductors(all_diagram, t_list,
|
||||
ignore_function_separation);
|
||||
}
|
||||
|
||||
other_conductors += QSet<Conductor*>(other_conductors_list_t.begin(),other_conductors_list_t.end());
|
||||
@@ -2055,6 +2064,36 @@ QSet<Conductor *> Conductor::relatedPotentialConductors(const bool all_diagram,
|
||||
return(other_conductors);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Conductor::functionSeparatedConductors
|
||||
Return the conductors that belong to this conductor's potential only
|
||||
by crossing a function separated terminal element -- a terminal
|
||||
element whose function separation checkbox (element information
|
||||
potential_isolating) is enabled, the checkbox the user ticks to stop
|
||||
sharing a terminal's properties with the other side of the terminal.
|
||||
|
||||
Those conductors are deliberately not part of
|
||||
relatedPotentialConductors(): no property may be copied over them
|
||||
by default. One does cross that separation, though: the voltage /
|
||||
protocol, which describes the electrical node itself. Callers that
|
||||
push it over the whole potential use this method to reach the other
|
||||
side (@see ConductorProperties::applyTensionProtocolChange).
|
||||
|
||||
It is simply the potential computed with the separations ignored,
|
||||
minus the potential that respects them.
|
||||
@param all_diagram : if true search in all diagram of the project,
|
||||
false search only in the parent diagram of this conductor
|
||||
@return a QSet of conductor, this conductor excluded
|
||||
*/
|
||||
QSet<Conductor *> Conductor::functionSeparatedConductors(const bool all_diagram)
|
||||
{
|
||||
QSet<Conductor *> separated = relatedPotentialConductors(all_diagram, nullptr, true);
|
||||
separated.subtract(relatedPotentialConductors(all_diagram));
|
||||
separated.remove(this);
|
||||
|
||||
return separated;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Conductor::diagramEditor
|
||||
@return The parent diagram editor or nullptr;
|
||||
|
||||
@@ -151,7 +151,10 @@ class Conductor : public QGraphicsObject
|
||||
virtual void setHighlighted(Highlight);
|
||||
QSet<Conductor *> relatedPotentialConductors(
|
||||
const bool all_diagram = true,
|
||||
QList <Terminal *> *t_list=nullptr);
|
||||
QList <Terminal *> *t_list=nullptr,
|
||||
const bool ignore_function_separation = false);
|
||||
QSet<Conductor *> functionSeparatedConductors(
|
||||
const bool all_diagram = true);
|
||||
QETDiagramEditor* diagramEditor() const;
|
||||
void editProperty ();
|
||||
|
||||
|
||||
@@ -1082,10 +1082,19 @@ void Terminal::setMasterLabelIndex(int index)
|
||||
@param terminal : to start search
|
||||
@param all_diagram :if true return all related terminal,
|
||||
false return only terminal in the same diagram of t
|
||||
@param ignore_function_separation : if true, a parent element whose
|
||||
function separation (element information potential_isolating) is
|
||||
enabled does not keep its terminals apart: they all count as one
|
||||
potential, the way they do when the option is disabled. Only the
|
||||
callers that need the conductors a separation hides -- so that the
|
||||
one property still allowed to cross it, the voltage / protocol, can
|
||||
be applied there (@see Conductor::functionSeparatedConductors) --
|
||||
pass true; every other caller keeps the default.
|
||||
@return the list of terminal at the same potential
|
||||
*/
|
||||
QList<Terminal *> relatedPotentialTerminal (
|
||||
const Terminal *terminal, const bool all_diagram)
|
||||
const Terminal *terminal, const bool all_diagram,
|
||||
const bool ignore_function_separation)
|
||||
{
|
||||
// If terminal parent element is a folio report.
|
||||
if (all_diagram && terminal -> parentElement() -> linkType() & Element::AllReport)
|
||||
@@ -1110,14 +1119,18 @@ QList<Terminal *> relatedPotentialTerminal (
|
||||
// If terminal parent element is a Terminal element.
|
||||
else if (terminal -> parentElement() -> linkType() & Element::Terminale)
|
||||
{
|
||||
// English: Check if the user activated the potential isolation checkbox for this terminal
|
||||
if (QET::infoFlagIsTrue(terminal->parentElement()->elementInformations().value(QStringLiteral("potential_isolating")).toString())) {
|
||||
// English: Potential is isolated -- but terminals sharing this
|
||||
// terminal's own, non-empty potential-group identifier
|
||||
// (@see TerminalData::m_potential, set per-terminal in the
|
||||
// element editor) still belong to the same physical terminal
|
||||
// English: Check if the user activated the function separation
|
||||
// checkbox for this terminal (the checkbox that used to be called
|
||||
// potential separation -- the stored flag is still
|
||||
// "potential_isolating" so existing elements keep their setting).
|
||||
if (!ignore_function_separation
|
||||
&& QET::infoFlagIsTrue(terminal->parentElement()->elementInformations().value(QStringLiteral("potential_isolating")).toString())) {
|
||||
// English: The terminals are function separated -- but terminals
|
||||
// sharing this terminal's own, non-empty potential-group
|
||||
// identifier (@see TerminalData::m_potential, set per-terminal in
|
||||
// the element editor) still belong to the same physical terminal
|
||||
// and stay linked to each other. An empty/unset potential on
|
||||
// every terminal reproduces the previous, fully-isolated
|
||||
// every terminal reproduces the previous, fully-separated
|
||||
// behavior exactly, so existing elements are unaffected.
|
||||
const QString this_potential = terminal->potential();
|
||||
QList<Terminal *> same_potential;
|
||||
|
||||
@@ -168,6 +168,7 @@ inline int Terminal::conductorsCount() const
|
||||
}
|
||||
|
||||
QList<Terminal *> relatedPotentialTerminal (const Terminal *terminal,
|
||||
const bool all_diagram = true);
|
||||
const bool all_diagram = true,
|
||||
const bool ignore_function_separation = false);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1189,6 +1189,10 @@ QString QetScriptApi::conductorProperty(int folioIndex, const QString &elementUu
|
||||
describes a potential and not one drawn segment. Setting it on one
|
||||
conductor and leaving the rest of the potential disagreeing would
|
||||
produce a file no GUI action could have produced.
|
||||
|
||||
One thing stops at a terminal element with its function separation
|
||||
enabled: every property but the voltage / protocol, which still
|
||||
crosses it (@see Conductor::functionSeparatedConductors).
|
||||
@return true if anything was changed, or if it already held that value
|
||||
*/
|
||||
bool QetScriptApi::setConductorProperty(int folioIndex, const QString &elementUuid,
|
||||
@@ -1209,13 +1213,17 @@ bool QetScriptApi::setConductorProperty(int folioIndex, const QString &elementUu
|
||||
Conductor *conductor = findConductor(folioIndex, elementUuid, terminalIndex, caller);
|
||||
if (!conductor) return false;
|
||||
|
||||
ConductorProperties properties = conductor->properties();
|
||||
//Captured before the pushes below: QPropertyUndoCommand applies on
|
||||
//push, so reading the properties afterwards would already give back
|
||||
//@a properties.
|
||||
const ConductorProperties before = conductor->properties();
|
||||
ConductorProperties properties = before;
|
||||
if (!setConductorPropertyValue(properties, property, value)) {
|
||||
log(QStringLiteral("qet.%1: '%2' is not a valid value for %3")
|
||||
.arg(caller, value, property));
|
||||
return false;
|
||||
}
|
||||
if (properties == conductor->properties()) return true; // already so
|
||||
if (properties == before) return true; // already so
|
||||
|
||||
QSet<Conductor *> potential = conductor->relatedPotentialConductors(true);
|
||||
potential << conductor;
|
||||
@@ -1227,6 +1235,25 @@ bool QetScriptApi::setConductorProperty(int folioIndex, const QString &elementUu
|
||||
old_value.setValue(c->properties());
|
||||
new_value.setValue(properties);
|
||||
m_project->undoStack()->push(new QPropertyUndoCommand(c, "properties", old_value, new_value));
|
||||
}
|
||||
//The other side of a function separated terminal element gets the
|
||||
//voltage / protocol only: it is the one property that still
|
||||
//describes the electrical node rather than one side of it. And it
|
||||
//only arrives when this call really changed it -- before / after
|
||||
//is the edit, not the far wire's own value, which differs from it
|
||||
//just as often as not and would then be overwritten by every call,
|
||||
//colour included.
|
||||
for (Conductor *c : conductor->functionSeparatedConductors(true))
|
||||
{
|
||||
ConductorProperties separated_properties = c->properties();
|
||||
separated_properties.applyTensionProtocolChange(before, properties);
|
||||
if (separated_properties == c->properties())
|
||||
continue;
|
||||
|
||||
QVariant old_value, new_value;
|
||||
old_value.setValue(c->properties());
|
||||
new_value.setValue(separated_properties);
|
||||
m_project->undoStack()->push(new QPropertyUndoCommand(c, "properties", old_value, new_value));
|
||||
}
|
||||
m_project->undoStack()->endMacro();
|
||||
return true;
|
||||
|
||||
@@ -88,6 +88,37 @@ void ConductorPropertiesDialog::PropertiesDialog(Conductor *conductor,
|
||||
}
|
||||
}
|
||||
|
||||
//A function separated terminal element (element information
|
||||
//potential_isolating) keeps the two sides of the terminal apart:
|
||||
//every property but one stays local to the side it was edited on.
|
||||
//The voltage / protocol still crosses, because it describes the
|
||||
//electrical node and not one side of it.
|
||||
if (cpd.applyAll())
|
||||
{
|
||||
//Only an edit that really changed the voltage / protocol passes
|
||||
//it on, so the comparison is the edit itself -- what the dialog
|
||||
//was filled with, against what the user left in it -- and never
|
||||
//the far wire's own value, which differs from it just as often
|
||||
//as not (a 24 V side against a 0 V one, say) and would then be
|
||||
//overwritten by every edit, voltage included.
|
||||
const ConductorProperties shown = conductor->properties();
|
||||
foreach (Conductor *separated_conductor, conductor->functionSeparatedConductors())
|
||||
{
|
||||
ConductorProperties separated_properties = separated_conductor->properties();
|
||||
separated_properties.applyTensionProtocolChange(
|
||||
shown,
|
||||
cpd.properties());
|
||||
if (separated_properties == separated_conductor->properties())
|
||||
continue;
|
||||
|
||||
QVariant separated_old_value, separated_new_value;
|
||||
separated_old_value.setValue(separated_conductor->properties());
|
||||
separated_new_value.setValue(separated_properties);
|
||||
new QPropertyUndoCommand (separated_conductor, "properties",
|
||||
separated_old_value, separated_new_value, undo);
|
||||
}
|
||||
}
|
||||
|
||||
conductor->diagram()->undoStack().push(undo);
|
||||
}
|
||||
|
||||
|
||||
@@ -346,7 +346,10 @@ void ConductorPropertiesEditorWidget::updateUi()
|
||||
When "apply to all" is ticked, every conductor on the same potential as
|
||||
an edited one is updated too, in the same undo step (one undo reverts
|
||||
them all), as the modal dialog does
|
||||
(ConductorPropertiesDialog::PropertiesDialog).
|
||||
(ConductorPropertiesDialog::PropertiesDialog). A terminal element with
|
||||
its function separation enabled is not crossed by any of that -- its
|
||||
other side keeps its own text, function, color... -- but the voltage /
|
||||
protocol still crosses (@see Conductor::functionSeparatedConductors).
|
||||
*/
|
||||
QUndoCommand *ConductorPropertiesEditorWidget::associatedUndo() const
|
||||
{
|
||||
@@ -360,10 +363,12 @@ QUndoCommand *ConductorPropertiesEditorWidget::associatedUndo() const
|
||||
if (c)
|
||||
selected << c.data();
|
||||
|
||||
return ConductorMultiEdit::undo(
|
||||
ConductorMultiEdit::targets(
|
||||
selected, m_apply_all_cb && m_apply_all_cb->isChecked()),
|
||||
m_shown, edited);
|
||||
QSet<Conductor *> function_separated;
|
||||
const QList<Conductor *> targets = ConductorMultiEdit::targets(
|
||||
selected, m_apply_all_cb && m_apply_all_cb->isChecked(),
|
||||
&function_separated);
|
||||
|
||||
return ConductorMultiEdit::undo(targets, m_shown, edited, function_separated);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -313,8 +313,9 @@ void ElementInfoWidget::buildInterface()
|
||||
|
||||
ui->scroll_vlayout->addStretch();
|
||||
|
||||
// Existing potential isolating checkbox
|
||||
m_potential_isolating_cb = new QCheckBox(tr("Potential separation"), this);
|
||||
// Existing function separation checkbox (stored as the
|
||||
// "potential_isolating" element information)
|
||||
m_potential_isolating_cb = new QCheckBox(tr("Function separation"), this);
|
||||
m_potential_isolating_cb->setStyleSheet(QStringLiteral("margin: 5px; font-weight: bold;"));
|
||||
|
||||
// English: Initialize and style the BOM exclusion checkbox
|
||||
|
||||
@@ -29,6 +29,10 @@ class FakeWire : public QObject
|
||||
ConductorProperties properties() const { return m_properties; }
|
||||
void setProperties(const ConductorProperties &p) { m_properties = p; }
|
||||
QSet<FakeWire *> relatedPotentialConductors() const { return m_potential; }
|
||||
// The wires of the other side of a function separated terminal
|
||||
// element: same electrical node, but only the voltage /
|
||||
// protocol crosses.
|
||||
QSet<FakeWire *> functionSeparatedConductors() const { return m_separated; }
|
||||
QPointF pos() const { return m_pos; }
|
||||
|
||||
// Joins wires into one potential; like the real one, a wire's
|
||||
@@ -41,10 +45,24 @@ class FakeWire : public QObject
|
||||
w->m_potential.insert(o);
|
||||
}
|
||||
|
||||
// Marks two groups as separated by a function separated
|
||||
// terminal element, without joining their potentials.
|
||||
static void separate(const QList<FakeWire *> &one,
|
||||
const QList<FakeWire *> &other)
|
||||
{
|
||||
for (FakeWire *w : one)
|
||||
for (FakeWire *o : other)
|
||||
{
|
||||
w->m_separated.insert(o);
|
||||
o->m_separated.insert(w);
|
||||
}
|
||||
}
|
||||
|
||||
ConductorProperties m_properties;
|
||||
|
||||
private:
|
||||
QSet<FakeWire *> m_potential;
|
||||
QSet<FakeWire *> m_separated;
|
||||
QPointF m_pos;
|
||||
};
|
||||
|
||||
@@ -102,6 +120,143 @@ class tst_conductormultiedit : public QObject
|
||||
(QSet<FakeWire *> {&a, &b, &c, &d}));
|
||||
}
|
||||
|
||||
// A function separated terminal element: the other side of the
|
||||
// terminal is reached too, but only the voltage / protocol
|
||||
// crosses it -- not the function, not the number.
|
||||
void functionSeparatedGetsVoltageProtocolOnly()
|
||||
{
|
||||
FakeWire a("1", "fnA", "", {}), b("2", "fnB", "", {}),
|
||||
c("3", "fnC", "", {});
|
||||
FakeWire::join({&a, &b});
|
||||
FakeWire::separate({&a}, {&c});
|
||||
|
||||
QSet<FakeWire *> separated;
|
||||
const Wires t = ConductorMultiEdit::targets(Wires {&a}, true,
|
||||
&separated);
|
||||
QCOMPARE(QSet<FakeWire *>(t.begin(), t.end()),
|
||||
(QSet<FakeWire *> {&a, &b, &c}));
|
||||
QCOMPARE(separated, (QSet<FakeWire *> {&c}));
|
||||
// A caller that does not know about the rule gets the
|
||||
// separated side left out, as before
|
||||
QCOMPARE(ConductorMultiEdit::targets(Wires {&a}, true),
|
||||
(Wires {&a, &b}));
|
||||
|
||||
const ConductorProperties shown = a.properties();
|
||||
ConductorProperties after = edited(shown,
|
||||
&ConductorProperties::m_function, "PWR");
|
||||
after.m_tension_protocol = "24V";
|
||||
|
||||
QUndoStack stack;
|
||||
stack.push(ConductorMultiEdit::undo(t, shown, after, separated));
|
||||
QCOMPARE(stack.count(), 1);
|
||||
|
||||
for (FakeWire *w : {&a, &b})
|
||||
{
|
||||
QCOMPARE(w->m_properties.m_function, QStringLiteral("PWR"));
|
||||
QCOMPARE(w->m_properties.m_tension_protocol,
|
||||
QStringLiteral("24V"));
|
||||
}
|
||||
QCOMPARE(c.m_properties.m_function, QStringLiteral("fnC"));
|
||||
QCOMPARE(c.m_properties.text, QStringLiteral("3"));
|
||||
QCOMPARE(c.m_properties.m_tension_protocol, QStringLiteral("24V"));
|
||||
|
||||
stack.undo();
|
||||
QVERIFY(c.properties().m_tension_protocol.isEmpty());
|
||||
QCOMPARE(c.m_properties.m_function, QStringLiteral("fnC"));
|
||||
}
|
||||
|
||||
// The explicitly picked side of a separation: selecting one
|
||||
// wire on each side and editing them edits them both, in
|
||||
// full -- however the selection happens to be walked (#review)
|
||||
void selectedWireIsNeverSeparated()
|
||||
{
|
||||
FakeWire a("1", "fnA", "", {}), c("3", "fnC", "", {});
|
||||
FakeWire::separate({&a}, {&c});
|
||||
|
||||
const ConductorProperties original_a = a.properties();
|
||||
const ConductorProperties original_c = c.properties();
|
||||
const ConductorProperties after = edited(original_a,
|
||||
&ConductorProperties::m_function, "PWR");
|
||||
|
||||
for (const Wires &selection : {Wires {&a, &c}, Wires {&c, &a}})
|
||||
{
|
||||
//Each order starts from the same, unedited state
|
||||
a.setProperties(original_a);
|
||||
c.setProperties(original_c);
|
||||
|
||||
QSet<FakeWire *> separated;
|
||||
const Wires t = ConductorMultiEdit::targets(selection, true,
|
||||
&separated);
|
||||
//c is picked, so it is not "the far side" of anything
|
||||
QCOMPARE(separated, (QSet<FakeWire *> {}));
|
||||
|
||||
QUndoStack stack;
|
||||
QUndoCommand *undo = ConductorMultiEdit::undo(t, original_a,
|
||||
after, separated);
|
||||
QVERIFY(undo);
|
||||
stack.push(undo);
|
||||
QCOMPARE(a.m_properties.m_function, QStringLiteral("PWR"));
|
||||
QCOMPARE(c.m_properties.m_function, QStringLiteral("PWR"));
|
||||
}
|
||||
}
|
||||
|
||||
// A wire that belongs to the potential as well -- on any path,
|
||||
// however far that path runs -- takes the full edit, even when a
|
||||
// separation also reaches it. The fake's potential is one hop
|
||||
// deep, unlike the real one, so the shared potential is stated
|
||||
// in full here.
|
||||
void wireReachableBothWaysIsNotSeparated()
|
||||
{
|
||||
FakeWire a("1", "fnA", "", {}), b("2", "fnB", "", {}),
|
||||
c("3", "fnC", "", {});
|
||||
FakeWire::join({&a, &b, &c});
|
||||
FakeWire::separate({&a}, {&c});
|
||||
|
||||
QSet<FakeWire *> separated;
|
||||
const Wires t = ConductorMultiEdit::targets(Wires {&a}, true,
|
||||
&separated);
|
||||
QCOMPARE(QSet<FakeWire *>(t.begin(), t.end()),
|
||||
(QSet<FakeWire *> {&a, &b, &c}));
|
||||
QCOMPARE(separated, (QSet<FakeWire *> {}));
|
||||
|
||||
const ConductorProperties shown = a.properties();
|
||||
QUndoStack stack;
|
||||
stack.push(ConductorMultiEdit::undo(t, shown, edited(shown,
|
||||
&ConductorProperties::m_function, "PWR"), separated));
|
||||
QCOMPARE(c.m_properties.m_function, QStringLiteral("PWR"));
|
||||
}
|
||||
|
||||
// The far side only takes the voltage when the edit changed it:
|
||||
// editing the function of a 24 V wire must leave the 0 V one
|
||||
// at 0 V, not drag it along (#review)
|
||||
void separatedWireKeepsVoltageWhenNotEdited()
|
||||
{
|
||||
FakeWire a("1", "fnA", "", {}), c("3", "fnC", "", {});
|
||||
FakeWire::separate({&a}, {&c});
|
||||
a.m_properties.m_tension_protocol = "24V";
|
||||
c.m_properties.m_tension_protocol = "0V";
|
||||
|
||||
QSet<FakeWire *> separated;
|
||||
const Wires t = ConductorMultiEdit::targets(Wires {&a}, true,
|
||||
&separated);
|
||||
const ConductorProperties shown = a.properties();
|
||||
QUndoStack stack;
|
||||
|
||||
//Only the function changes: the far side changes nothing
|
||||
stack.push(ConductorMultiEdit::undo(t, shown, edited(shown,
|
||||
&ConductorProperties::m_function, "PWR"), separated));
|
||||
QCOMPARE(c.m_properties.m_function, QStringLiteral("fnC"));
|
||||
QCOMPARE(c.m_properties.m_tension_protocol, QStringLiteral("0V"));
|
||||
|
||||
//Now the voltage changes too: it crosses, and only it
|
||||
const ConductorProperties shown_now = a.properties();
|
||||
stack.push(ConductorMultiEdit::undo(t, shown_now, edited(shown_now,
|
||||
&ConductorProperties::m_tension_protocol, "30V"), separated));
|
||||
QCOMPARE(c.m_properties.m_tension_protocol, QStringLiteral("30V"));
|
||||
QCOMPARE(c.m_properties.m_function, QStringLiteral("fnC"));
|
||||
QCOMPARE(a.m_properties.m_tension_protocol, QStringLiteral("30V"));
|
||||
}
|
||||
|
||||
// One edit of three wires: each takes the function, keeps its
|
||||
// own number and cable; one undo restores all three exactly
|
||||
void undoRedoThreeWires()
|
||||
|
||||
Reference in New Issue
Block a user