mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-22 22:34:13 +02:00
Add a Target column to the terminal strip editor
Reading where a cable lands meant going back to the drawing: the strip editor said which cable a terminal carries and which core, but never what the cable goes to. A single core (1x16) could not be followed from the terminal to its piece at all. The new Target column names it: Installation, Location and Label (BMK) of the piece the wires land on, past this strip, joined in one line -- the very three fields the strip drawing writes in the box under its cable, in the same order (RealTerminal::cableTarget()). It is worked out of the project like the Cable cells and so follows their rule: a target the drawing names is read only, for only the drawing decides it, and a cell nothing is worked out for takes an edit, so a target the drawing cannot find -- a cable landing on a piece with no Installation, Location nor Label set, a cable going to another strip -- is still worth naming by hand. The text typed in is stored in the element (RealTerminal::cableTargetInfoKey()) and kept until a cable works a target out again, and back once that cable goes, exactly like a cable designation typed by hand: the automatic value is never written, so no stale text can be left behind. The column takes the width of its own text, so a long Installation is never cut off. A text typed in is written the way the fields are shown in the column, "Installation / Location / Label", and gives one line per field: the box under the cable draws three lines without any slash in them, just like a target worked out from the project, instead of one long line carrying its separators as text. tst_terminalcableauto checks the column is empty -- and editable -- without a cable, reads "Plant 7 / Cabinet 7 / -S7" with one, goes empty -- and editable again -- when the core is removed, takes no edit while the drawing names the target, and is headed "Target"; a second case checks a target typed in by hand is taken by the cell, stored by Apply, shown again by a fresh model, set aside for the read only target of the drawing once a cable lands somewhere worth naming, and back once that cable goes; a third one the line per field. tst_cable target paints a strip whose cable ends on one field and the same strip ending on three, the second box two lines deeper than the first.
This commit is contained in:
@@ -407,6 +407,57 @@ bool RealTerminal::isShield() const {
|
||||
|
||||
/**
|
||||
* @brief RealTerminal::cableTarget
|
||||
* Where the cable of this terminal goes at its far end: the lines to
|
||||
* write in the box under the cable. What the project itself says when
|
||||
* a cable lands on a piece (see automaticCableTarget()), and the text
|
||||
* typed in by hand when none does -- the Target cell of the terminal
|
||||
* strip editor is read only in the first case, so a target the drawing
|
||||
* cannot work out is still worth naming by hand. A text typed in is
|
||||
* written the way the fields are shown in the column,
|
||||
* "Installation / Location / Label", and gives one line per field.
|
||||
* @return the lines to write in the box under the cable
|
||||
*/
|
||||
QVector<QString> RealTerminal::cableTarget() const
|
||||
{
|
||||
const auto automatic_{automaticCableTarget()};
|
||||
if (!automatic_.isEmpty()) {
|
||||
return automatic_;
|
||||
}
|
||||
|
||||
if (hasData())
|
||||
{
|
||||
const auto typed_{terminalData().m_informations
|
||||
.value(cableTargetInfoKey()).toString()};
|
||||
if (!typed_.isEmpty())
|
||||
{
|
||||
//Written the way the fields are shown in the column,
|
||||
//"Installation / Location / Label": the box draws one line
|
||||
//per field, without the separators, like it does for a
|
||||
//target worked out from the project
|
||||
QVector<QString> lines_;
|
||||
for (const QString &field_
|
||||
: typed_.split(QStringLiteral(" / "), Qt::SkipEmptyParts)) {
|
||||
lines_ << field_;
|
||||
}
|
||||
return lines_;
|
||||
}
|
||||
}
|
||||
return QVector<QString>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RealTerminal::cableTargetIsAutomatic
|
||||
* @return true when the target of this terminal is worked out from the
|
||||
* project -- one of its cables lands on a piece worth naming -- and
|
||||
* false when only a text typed in by hand is there to show.
|
||||
*/
|
||||
bool RealTerminal::cableTargetIsAutomatic() const
|
||||
{
|
||||
return !automaticCableTarget().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RealTerminal::automaticCableTarget
|
||||
* Where the cable of this terminal goes at its far end: the
|
||||
* Installation, Location and Label (BMK) of the first piece the
|
||||
* wires of the cable land on, past the strip's own terminals, in
|
||||
@@ -420,7 +471,7 @@ bool RealTerminal::isShield() const {
|
||||
* its name among the cables of the project.
|
||||
* @return the lines to write in the box under the cable
|
||||
*/
|
||||
QVector<QString> RealTerminal::cableTarget() const
|
||||
QVector<QString> RealTerminal::automaticCableTarget() const
|
||||
{
|
||||
if (m_spare || m_element.isNull()) {
|
||||
return QVector<QString>();
|
||||
|
||||
@@ -55,6 +55,11 @@ class RealTerminal
|
||||
|
||||
void setPhysicalTerminal(const QSharedPointer<PhysicalTerminal> &phy_t);
|
||||
|
||||
///Where the wires of a cable land, worked out from the project:
|
||||
///empty when no cable lands on a piece worth naming (cableTarget()
|
||||
///then falls back on the text typed in by hand).
|
||||
QVector<QString> automaticCableTarget() const;
|
||||
|
||||
public:
|
||||
~RealTerminal();
|
||||
static QSharedPointer<RealTerminal> createSpare(const ElementData &data, const QUuid &uuid = QUuid());
|
||||
@@ -76,6 +81,9 @@ class RealTerminal
|
||||
bool cableIsAutomatic() const;
|
||||
bool isShield() const;
|
||||
QVector<QString> cableTarget() const;
|
||||
///True when cableTarget() is worked out from the project (read only),
|
||||
///false when it is the text typed in by hand (which may be edited)
|
||||
bool cableTargetIsAutomatic() const;
|
||||
QColor color() const;
|
||||
QColor stripeColor() const;
|
||||
qreal section() const;
|
||||
@@ -86,6 +94,8 @@ class RealTerminal
|
||||
//Keys used to store the cable data in the element informations
|
||||
static QString cableInfoKey() { return QStringLiteral("terminal_cable"); }
|
||||
static QString cableWireInfoKey() { return QStringLiteral("terminal_cable_wire"); }
|
||||
//Target typed in by hand, only read when the cables give none
|
||||
static QString cableTargetInfoKey() { return QStringLiteral("terminal_cable_target"); }
|
||||
static QString shieldInfoKey() { return QStringLiteral("terminal_shield"); }
|
||||
//Keys used to store the color and the section (mm2) of the terminal
|
||||
static QString colorInfoKey() { return QStringLiteral("terminal_color"); }
|
||||
|
||||
@@ -20,11 +20,30 @@
|
||||
|
||||
#include <QColor>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include "../../qetgraphicsitem/element.h"
|
||||
#include "../realterminal.h"
|
||||
|
||||
struct modelRealTerminalData
|
||||
{
|
||||
///The Installation, Location and Label (BMK) of the piece the cable
|
||||
///lands on, joined in one line : what the strip draws in the box
|
||||
///under its cable (RealTerminal::cableTarget), in the same order.
|
||||
///A target typed in by hand is one single line, and nothing is
|
||||
///shown when the cable lands on nothing worth naming and no text
|
||||
///was ever written in.
|
||||
static QString targetText(const QVector<QString> &target_)
|
||||
{
|
||||
QStringList fields_;
|
||||
for (const QString &field_ : target_)
|
||||
{
|
||||
if (!field_.isEmpty()) {
|
||||
fields_ << field_;
|
||||
}
|
||||
}
|
||||
return fields_.join(QStringLiteral(" / "));
|
||||
}
|
||||
|
||||
static modelRealTerminalData data(const QSharedPointer<RealTerminal> &real_t)
|
||||
{
|
||||
modelRealTerminalData mrtd;
|
||||
@@ -35,6 +54,8 @@ struct modelRealTerminalData
|
||||
mrtd.Xref_ = real_t->Xref();
|
||||
mrtd.cable_ = real_t->cable();
|
||||
mrtd.cable_wire = real_t->cableWire();
|
||||
mrtd.cable_target_ = targetText(real_t->cableTarget());
|
||||
mrtd.cable_target_auto_ = real_t->cableTargetIsAutomatic();
|
||||
mrtd.cable_auto_ = real_t->cableIsAutomatic();
|
||||
mrtd.conductor_ = real_t->conductor();
|
||||
mrtd.led_ = real_t->isLed();
|
||||
@@ -61,6 +82,11 @@ struct modelRealTerminalData
|
||||
QString Xref_;
|
||||
QString cable_;
|
||||
QString cable_wire;
|
||||
//Where the cable lands, past this strip : Installation / Location / Label
|
||||
QString cable_target_;
|
||||
//True when cable_target_ comes from the project (read only),
|
||||
//false when it is empty or was typed in by hand (editable)
|
||||
bool cable_target_auto_ = false;
|
||||
bool cable_auto_ = false; //True when cable_ and cable_wire come from the cables of the project
|
||||
QString conductor_;
|
||||
bool led_ = false;
|
||||
|
||||
@@ -249,6 +249,10 @@ void TerminalStripEditor::setCurrentStrip(TerminalStrip *strip_)
|
||||
{
|
||||
m_model = new TerminalStripModel{strip_, this};
|
||||
ui->m_table_widget->setModel(m_model);
|
||||
//The Target column is worked out from the drawing: it takes
|
||||
//the width of its own text, never a cut off Installation
|
||||
ui->m_table_widget->horizontalHeader()->setSectionResizeMode(
|
||||
TerminalStripModel::CableTarget, QHeaderView::ResizeToContents);
|
||||
m_model->buildBridgePixmap(setUpBridgeCellWidth());
|
||||
connect(ui->m_table_widget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &TerminalStripEditor::selectionChanged);
|
||||
}
|
||||
@@ -335,6 +339,12 @@ void TerminalStripEditor::apply()
|
||||
if (!data_.cable_auto_) {
|
||||
set_info(RealTerminal::cableInfoKey(), data_.cable_);
|
||||
set_info(RealTerminal::cableWireInfoKey(), data_.cable_wire);
|
||||
}
|
||||
//The same for the target: a target worked out from the
|
||||
//project is never written in the element, only the one
|
||||
//typed in by hand is stored
|
||||
if (!data_.cable_target_auto_) {
|
||||
set_info(RealTerminal::cableTargetInfoKey(), data_.cable_target_);
|
||||
}
|
||||
set_info(RealTerminal::shieldInfoKey(), data_.shield_ ? QStringLiteral("true") : QString());
|
||||
//The color and the section are stored with the dot as decimal separator, whatever the locale
|
||||
@@ -790,7 +800,8 @@ void TerminalStripEditor::on_m_led_cb_activated(int index)
|
||||
namespace {
|
||||
/**
|
||||
* @return true if the cell at @a index contain a free text
|
||||
* (label, cable, wire of the cable, color, section or width), so a text can be pasted in it.
|
||||
* (label, cable, wire of the cable, target of the cable, color, section
|
||||
* or width), so a text can be pasted in it.
|
||||
*/
|
||||
bool cellAcceptText(const QModelIndex &index)
|
||||
{
|
||||
@@ -798,6 +809,7 @@ bool cellAcceptText(const QModelIndex &index)
|
||||
return column_ == TerminalStripModel::Label
|
||||
|| column_ == TerminalStripModel::Cable
|
||||
|| column_ == TerminalStripModel::CableWire
|
||||
|| column_ == TerminalStripModel::CableTarget
|
||||
|| column_ == TerminalStripModel::Color
|
||||
|| column_ == TerminalStripModel::Section
|
||||
|| column_ == TerminalStripModel::Width;
|
||||
|
||||
@@ -48,16 +48,17 @@ const int CONDUCTOR_CELL = 7;
|
||||
const int XREF_CELL = 8;
|
||||
const int CABLE_CELL = 9;
|
||||
const int CABLE_WIRE_CELL = 10;
|
||||
const int TYPE_CELL = 11;
|
||||
const int FUNCTION_CELL = 12;
|
||||
const int LED_CELL = 13;
|
||||
const int SHIELD_CELL = 14;
|
||||
const int COLOR_CELL = 15;
|
||||
const int SECTION_CELL = 16;
|
||||
const int WIDTH_CELL = 17;
|
||||
const int SEPARATOR_CELL = 18;
|
||||
const int CABLE_TARGET_CELL = 11;
|
||||
const int TYPE_CELL = 12;
|
||||
const int FUNCTION_CELL = 13;
|
||||
const int LED_CELL = 14;
|
||||
const int SHIELD_CELL = 15;
|
||||
const int COLOR_CELL = 16;
|
||||
const int SECTION_CELL = 17;
|
||||
const int WIDTH_CELL = 18;
|
||||
const int SEPARATOR_CELL = 19;
|
||||
|
||||
const int COLUMN_COUNT = 19;
|
||||
const int COLUMN_COUNT = 20;
|
||||
|
||||
static QVector<bool> UNMODIFIED_CELL_VECTOR(COLUMN_COUNT, false);
|
||||
|
||||
@@ -132,14 +133,15 @@ TerminalStripModel::Column TerminalStripModel::columnTypeForIndex(const QModelIn
|
||||
case 8 : return XRef;
|
||||
case 9 : return Cable;
|
||||
case 10 : return CableWire;
|
||||
case 11 : return Type;
|
||||
case 12 : return Function;
|
||||
case 13 : return Led;
|
||||
case 14 : return Shield;
|
||||
case 15 : return Color;
|
||||
case 16 : return Section;
|
||||
case 17 : return Width;
|
||||
case 18 : return Separator;
|
||||
case 11 : return CableTarget;
|
||||
case 12 : return Type;
|
||||
case 13 : return Function;
|
||||
case 14 : return Led;
|
||||
case 15 : return Shield;
|
||||
case 16 : return Color;
|
||||
case 17 : return Section;
|
||||
case 18 : return Width;
|
||||
case 19 : return Separator;
|
||||
default : return Invalid;
|
||||
}
|
||||
}
|
||||
@@ -215,6 +217,7 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const
|
||||
case XREF_CELL : return mrtd.spare_ ? tr("Spare") : mrtd.Xref_;
|
||||
case CABLE_CELL : return mrtd.cable_;
|
||||
case CABLE_WIRE_CELL : return mrtd.cable_wire;
|
||||
case CABLE_TARGET_CELL : return mrtd.cable_target_;
|
||||
case TYPE_CELL : return ElementData::translatedTerminalType(mrtd.type_);
|
||||
case FUNCTION_CELL : return ElementData::translatedTerminalFunction(mrtd.function_);
|
||||
case COLOR_CELL : return TerminalColor::displayName(mrtd.color_, mrtd.stripe_color_);
|
||||
@@ -235,6 +238,7 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const
|
||||
case LABEL_CELL : return mrtd.label_;
|
||||
case CABLE_CELL : return mrtd.cable_;
|
||||
case CABLE_WIRE_CELL : return mrtd.cable_wire;
|
||||
case CABLE_TARGET_CELL : return mrtd.cable_target_;
|
||||
case COLOR_CELL : return TerminalColor::toSpec(mrtd.color_, mrtd.stripe_color_);
|
||||
case SECTION_CELL : return mrtd.section_ > 0 ? QLocale().toString(mrtd.section_, 'g', 6) : QString();
|
||||
case WIDTH_CELL : return mrtd.width_mm_ > 0 ? QLocale().toString(mrtd.width_mm_, 'g', 6) : QString();
|
||||
@@ -309,6 +313,10 @@ bool TerminalStripModel::setData(const QModelIndex &index, const QVariant &value
|
||||
&& mrtd.cable_auto_) {
|
||||
return false;
|
||||
}
|
||||
if (column_ == CABLE_TARGET_CELL
|
||||
&& mrtd.cable_target_auto_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (column_ == LEVEL_CELL &&
|
||||
role == Qt::EditRole)
|
||||
@@ -361,6 +369,14 @@ bool TerminalStripModel::setData(const QModelIndex &index, const QVariant &value
|
||||
modified_ = true;
|
||||
modified_cell = CABLE_WIRE_CELL;
|
||||
}
|
||||
else if (column_ == CABLE_TARGET_CELL &&
|
||||
role == Qt::EditRole &&
|
||||
mrtd.cable_target_ != value.toString())
|
||||
{
|
||||
mrtd.cable_target_ = value.toString();
|
||||
modified_ = true;
|
||||
modified_cell = CABLE_TARGET_CELL;
|
||||
}
|
||||
else if (column_ == SHIELD_CELL)
|
||||
{
|
||||
mrtd.shield_ = value.toBool();
|
||||
@@ -484,6 +500,7 @@ QVariant TerminalStripModel::headerData(int section, Qt::Orientation orientation
|
||||
case XREF_CELL: return tr("Cross-reference");
|
||||
case CABLE_CELL: return tr("Cable");
|
||||
case CABLE_WIRE_CELL: return tr("Color / wire number of the cable");
|
||||
case CABLE_TARGET_CELL: return tr("Target");
|
||||
case TYPE_CELL: return tr("Type");
|
||||
case FUNCTION_CELL : return tr("Function");
|
||||
case LED_CELL: return tr("led");
|
||||
@@ -496,6 +513,13 @@ QVariant TerminalStripModel::headerData(int section, Qt::Orientation orientation
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (role == Qt::ToolTipRole &&
|
||||
orientation == Qt::Horizontal &&
|
||||
section == CABLE_TARGET_CELL)
|
||||
{
|
||||
//Same three fields as the box drawn under the cable
|
||||
return tr("Installation, Location and Label (BMK) of the piece the cable lands on, past this strip");
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
@@ -510,6 +534,12 @@ Qt::ItemFlags TerminalStripModel::flags(const QModelIndex &index) const
|
||||
if ((c == CABLE_CELL || c == CABLE_WIRE_CELL)
|
||||
&& !dataAtRow(index.row()).cable_auto_)
|
||||
flags = flags | Qt::ItemIsEditable;
|
||||
//The target the project works out is read only: only the drawing
|
||||
//decides it. No target to show, or one typed in by hand, may be
|
||||
//written -- the same rule as the cable cells.
|
||||
if (c == CABLE_TARGET_CELL
|
||||
&& !dataAtRow(index.row()).cable_target_auto_)
|
||||
flags = flags | Qt::ItemIsEditable;
|
||||
if (c == LABEL_CELL || c == TYPE_CELL || c == FUNCTION_CELL
|
||||
|| c == COLOR_CELL || c == SECTION_CELL || c == WIDTH_CELL)
|
||||
flags = flags | Qt::ItemIsEditable;
|
||||
|
||||
@@ -58,14 +58,15 @@ class TerminalStripModel : public QAbstractTableModel
|
||||
XRef = 8,
|
||||
Cable = 9,
|
||||
CableWire = 10,
|
||||
Type = 11,
|
||||
Function = 12,
|
||||
Led = 13,
|
||||
Shield = 14,
|
||||
Color = 15,
|
||||
Section = 16,
|
||||
Width = 17,
|
||||
Separator = 18,
|
||||
CableTarget = 11,
|
||||
Type = 12,
|
||||
Function = 13,
|
||||
Led = 14,
|
||||
Shield = 15,
|
||||
Color = 16,
|
||||
Section = 17,
|
||||
Width = 18,
|
||||
Separator = 19,
|
||||
Invalid = 99
|
||||
};
|
||||
|
||||
|
||||
@@ -50,7 +50,10 @@
|
||||
|
||||
Also here: the box at the end of a cable is written at the font of
|
||||
the drawing -- the end zone the settings leave is what gives it the
|
||||
room, so three lines never end up squeezed into a tiny text.
|
||||
room, so three lines never end up squeezed into a tiny text. A
|
||||
target typed in by hand is written the way the fields are shown in
|
||||
the column, "Installation / Location / Label", and the box draws one
|
||||
line per field, with no slash in it.
|
||||
|
||||
Both drawing styles are covered: the schematic one and the
|
||||
realistic one (the strip seen from above), which paint the same
|
||||
@@ -174,6 +177,7 @@ private slots:
|
||||
void paintsWithTargetBox();
|
||||
void wireLabelStaysOutOfTheTerminal();
|
||||
void targetBoxKeepsTheDrawingFont();
|
||||
void typedTargetIsDrawnInItsOwnLines();
|
||||
void realisticStyleDrawsTheCable();
|
||||
};
|
||||
|
||||
@@ -520,6 +524,94 @@ void tst_cabletarget::realisticStyleDrawsTheCable()
|
||||
QVERIFY(without_bounds.height() < with_bounds.height());
|
||||
}
|
||||
|
||||
/**
|
||||
A target typed in by hand is written the way the fields are shown in
|
||||
the column, "Installation / Location / Label": the box under the
|
||||
cable draws one line per field, with no slash in it. The picture of
|
||||
a strip whose cable ends on three fields is therefore that much
|
||||
deeper than the picture of the same strip with one single field --
|
||||
two lines of the font of the drawing.
|
||||
*/
|
||||
void tst_cabletarget::typedTargetIsDrawnInItsOwnLines()
|
||||
{
|
||||
//The cable lands on a piece which names nothing, so there is no
|
||||
//target of the drawing and the box takes what is typed in
|
||||
QVERIFY(wireCableToTheContact());
|
||||
Element *contact_ = element(
|
||||
QStringLiteral("{fc9cc920-5822-421a-916e-a17100acdcf6}"));
|
||||
QVERIFY(contact_);
|
||||
ElementData contact_data_{contact_->elementData()};
|
||||
contact_data_.m_informations.addValue(QETInformation::ELMT_PLANT, QString());
|
||||
contact_data_.m_informations.addValue(QETInformation::ELMT_LOCATION, QString());
|
||||
contact_data_.m_informations.addValue(QETInformation::ELMT_LABEL, QString());
|
||||
contact_->setElementData(contact_data_);
|
||||
|
||||
const auto a_ = terminalInStrip(
|
||||
QStringLiteral("{891b70f2-2822-41c3-9f94-28efb448b5c4}"));
|
||||
QVERIFY(a_);
|
||||
QVERIFY(a_->cableTarget().isEmpty());
|
||||
Element *terminal_ = a_->element();
|
||||
QVERIFY(terminal_);
|
||||
|
||||
auto pattern_ = QSharedPointer<TerminalStripLayoutPattern>{new TerminalStripLayoutPattern};
|
||||
const auto strips_ = m_project->terminalStrip();
|
||||
QVERIFY(!strips_.isEmpty());
|
||||
TerminalStripDrawer::TerminalStripDrawer drawer{
|
||||
QSharedPointer<TerminalStripDrawer::TrueTerminalStrip>{
|
||||
new TerminalStripDrawer::TrueTerminalStrip{strips_.first()}},
|
||||
pattern_};
|
||||
|
||||
const QRectF bounds{drawer.boundingRect()};
|
||||
QVERIFY(!bounds.isEmpty());
|
||||
|
||||
const auto render = [&drawer, &bounds]() {
|
||||
QImage image{bounds.size().toSize() + QSize{4, 4},
|
||||
QImage::Format_ARGB32_Premultiplied};
|
||||
image.fill(Qt::transparent);
|
||||
QPainter painter{&image};
|
||||
painter.translate(-bounds.topLeft() + QPointF{2, 2});
|
||||
drawer.paint(&painter);
|
||||
painter.end();
|
||||
return image;
|
||||
};
|
||||
const auto lowest_row = [](const QImage &image_) {
|
||||
qreal lowest{-1};
|
||||
for (auto y = 0 ; y < image_.height() ; ++y)
|
||||
{
|
||||
for (auto x = 0 ; x < image_.width() ; ++x)
|
||||
{
|
||||
if (image_.pixel(x, y) != qRgba(0, 0, 0, 0)) {
|
||||
lowest = y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lowest;
|
||||
};
|
||||
const auto type_in = [terminal_](const QString &text_) {
|
||||
ElementData data_{terminal_->elementData()};
|
||||
data_.m_informations.addValue(RealTerminal::cableTargetInfoKey(), text_);
|
||||
terminal_->setElementData(data_);
|
||||
};
|
||||
|
||||
//One field: the box holds one single line
|
||||
type_in(QStringLiteral("Boiler room"));
|
||||
const qreal one_line{lowest_row(render())};
|
||||
QVERIFY(one_line >= 0);
|
||||
|
||||
//Three fields: the box is two lines deeper, at the font of the
|
||||
//drawing -- the slashes are only there to separate the fields in
|
||||
//the column, the box never draws them
|
||||
type_in(QStringLiteral("Boiler room / Cabinet 3 / -K3"));
|
||||
QCOMPARE(a_->cableTarget(), (QVector<QString>{QStringLiteral("Boiler room"),
|
||||
QStringLiteral("Cabinet 3"),
|
||||
QStringLiteral("-K3")}));
|
||||
const qreal three_lines{lowest_row(render())};
|
||||
const QFontMetricsF metrics{pattern_->font()};
|
||||
QVERIFY2(three_lines - one_line > 1.5 * metrics.height(),
|
||||
"three fields must give a box two lines deeper than one field");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QStandardPaths::setTestModeEnabled(true);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qetapptest.h"
|
||||
#include "TerminalStrip/physicalterminal.h"
|
||||
#include "TerminalStrip/realterminal.h"
|
||||
#include "TerminalStrip/terminalstrip.h"
|
||||
#include "TerminalStrip/ui/terminalstripeditor.h"
|
||||
@@ -25,6 +26,7 @@
|
||||
#include "qetgraphicsitem/conductor.h"
|
||||
#include "qetgraphicsitem/element.h"
|
||||
#include "qetgraphicsitem/terminal.h"
|
||||
#include "qetinformation.h"
|
||||
#include "qetproject.h"
|
||||
|
||||
#include <QAbstractItemView>
|
||||
@@ -37,6 +39,17 @@
|
||||
cannot leave a stale value behind. A terminal no cable is wired to
|
||||
keeps the value typed in by hand, cell and all.
|
||||
|
||||
The Target column follows the same rule: it names where the cable
|
||||
lands past this strip (Installation, Location and Label), the very
|
||||
three fields the strip drawing writes in its box. Worked out from a
|
||||
cable it is read only -- only the drawing decides it -- and with no
|
||||
cable landing anywhere it is there to be typed in, just like the
|
||||
Cable cell, the text then stored in the element and kept until a
|
||||
cable works a target out again. A text typed in is written the way
|
||||
the fields are shown in the column, "Installation / Location /
|
||||
Label", so the box draws one line per field and not one long line
|
||||
needing the slashes.
|
||||
|
||||
fixtures/every_feature.qet has the strip X1 whose two terminals are
|
||||
wired to conductors on the folio, and no cable at all.
|
||||
*/
|
||||
@@ -82,6 +95,37 @@ class tst_terminalcableauto : public QObject
|
||||
return conductors.isEmpty() ? nullptr : conductors.first();
|
||||
}
|
||||
|
||||
// The wire which leaves the strip: one of its ends belongs to a piece
|
||||
// outside the strip, while the wire joining two terminals of this very
|
||||
// strip never leaves it -- and never has a target to name.
|
||||
static Conductor *outgoingConductor(const QSharedPointer<RealTerminal> &real_t)
|
||||
{
|
||||
TerminalStrip *strip = real_t ? real_t->parentStrip() : nullptr;
|
||||
if (!strip) return nullptr;
|
||||
|
||||
QSet<QUuid> own;
|
||||
for (const QSharedPointer<PhysicalTerminal> &physical
|
||||
: strip->physicalTerminal())
|
||||
{
|
||||
if (!physical) continue;
|
||||
for (const QSharedPointer<RealTerminal> &real : physical->realTerminals())
|
||||
if (real && real->element())
|
||||
own.insert(real->element()->uuid());
|
||||
}
|
||||
|
||||
for (Conductor *conductor : conductorsOf(real_t))
|
||||
{
|
||||
if (!conductor) continue;
|
||||
Element *ends[2] = {
|
||||
conductor->terminal1 ? conductor->terminal1->parentElement() : nullptr,
|
||||
conductor->terminal2 ? conductor->terminal2->parentElement() : nullptr };
|
||||
for (Element *end : ends)
|
||||
if (end && !own.contains(end->uuid()))
|
||||
return conductor;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The cable the create dialog hands over: owned by the project, four
|
||||
// cores, one core wired to the terminal's conductor (or to @p on).
|
||||
static Cable *wireCable(QETProject &project,
|
||||
@@ -264,6 +308,224 @@ private slots:
|
||||
QCOMPARE(real_t->cableWire(), QStringLiteral("bl, bl"));
|
||||
QVERIFY(real_t->cableIsAutomatic());
|
||||
}
|
||||
|
||||
// The Target column names where the cable lands, past this strip: the
|
||||
// three fields the strip drawing writes in the box under the cable,
|
||||
// joined in one line. Worked out from a cable it is read only, there
|
||||
// is nothing to name without one, and the cell empties again once the
|
||||
// cable goes.
|
||||
void targetColumnNamesWhereTheCableLands()
|
||||
{
|
||||
const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
|
||||
QETProject project(fixture);
|
||||
QCOMPARE(project.state(), QETProject::Ok);
|
||||
|
||||
const auto real_t = wiredTerminal(project);
|
||||
QVERIFY(!real_t.isNull());
|
||||
Conductor *outgoing = outgoingConductor(real_t);
|
||||
QVERIFY2(outgoing, "the fixture terminal has a wire leaving the strip");
|
||||
|
||||
Element *target = (outgoing->terminal1
|
||||
&& outgoing->terminal1->parentElement() == real_t->element())
|
||||
? (outgoing->terminal2 ? outgoing->terminal2->parentElement() : nullptr)
|
||||
: (outgoing->terminal1 ? outgoing->terminal1->parentElement() : nullptr);
|
||||
QVERIFY(target);
|
||||
|
||||
//The piece the cable lands on carries an Installation, a Location
|
||||
//and a Label, the way an element of a real drawing does
|
||||
ElementData named = target->elementData();
|
||||
named.m_informations.addValue(QETInformation::ELMT_PLANT,
|
||||
QStringLiteral("Plant 7"));
|
||||
named.m_informations.addValue(QETInformation::ELMT_LOCATION,
|
||||
QStringLiteral("Cabinet 7"));
|
||||
named.m_informations.addValue(QETInformation::ELMT_LABEL,
|
||||
QStringLiteral("-S7"));
|
||||
target->setElementData(named);
|
||||
|
||||
//No cable yet : nothing to name, so the cell is there to be
|
||||
//filled in by hand -- the very rule of the Cable cell
|
||||
TerminalStripModel model_before(project.terminalStrip().first());
|
||||
const QModelIndex before_cell = model_before.index(
|
||||
0, TerminalStripModel::CableTarget);
|
||||
QVERIFY(model_before.data(before_cell).toString().isEmpty());
|
||||
QVERIFY(model_before.flags(before_cell) & Qt::ItemIsEditable);
|
||||
|
||||
Cable *cable = wireCable(project, real_t, 1, QStringLiteral("15W1"),
|
||||
outgoing);
|
||||
|
||||
//Row zero is the terminal the cable is wired to
|
||||
TerminalStripModel model(project.terminalStrip().first());
|
||||
QCOMPARE(model.data(model.index(0, TerminalStripModel::Cable))
|
||||
.toString(), QStringLiteral("15W1"));
|
||||
|
||||
//The three fields, in the order the box draws them
|
||||
const QModelIndex target_cell = model.index(0,
|
||||
TerminalStripModel::CableTarget);
|
||||
QCOMPARE(model.data(target_cell).toString(),
|
||||
QStringLiteral("Plant 7 / Cabinet 7 / -S7"));
|
||||
QVERIFY(!(model.flags(target_cell) & Qt::ItemIsEditable));
|
||||
QCOMPARE(model.headerData(TerminalStripModel::CableTarget,
|
||||
Qt::Horizontal).toString(),
|
||||
QStringLiteral("Target"));
|
||||
|
||||
//The cable taken away : the cell is empty again, nothing stale
|
||||
//behind, and it takes an edit once more
|
||||
QVERIFY(cable);
|
||||
cable->removeCore(1);
|
||||
TerminalStripModel reloaded(project.terminalStrip().first());
|
||||
const QModelIndex reloaded_cell = reloaded.index(
|
||||
0, TerminalStripModel::CableTarget);
|
||||
QVERIFY(reloaded.data(reloaded_cell).toString().isEmpty());
|
||||
QVERIFY(reloaded.flags(reloaded_cell) & Qt::ItemIsEditable);
|
||||
}
|
||||
|
||||
// A target the drawing cannot work out is typed in by hand, exactly
|
||||
// like a cable designation: the cell takes the edit, Apply stores the
|
||||
// text in the element, a fresh model shows it again. A cable landing
|
||||
// on a named piece then gives the read only target of the drawing and
|
||||
// the text typed in by hand waits, untouched, until that cable goes.
|
||||
void targetTypedByHandIsStoredAndKept()
|
||||
{
|
||||
const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
|
||||
QETProject project(fixture);
|
||||
QCOMPARE(project.state(), QETProject::Ok);
|
||||
|
||||
const auto real_t = wiredTerminal(project);
|
||||
QVERIFY(!real_t.isNull());
|
||||
Element *element = real_t->element();
|
||||
QVERIFY(element);
|
||||
Conductor *outgoing = outgoingConductor(real_t);
|
||||
QVERIFY2(outgoing, "the fixture terminal has a wire leaving the strip");
|
||||
|
||||
//The editor takes a target typed in by hand : no cable is wired,
|
||||
//so there is nothing the drawing could name and the cell is open
|
||||
TerminalStripEditor editor(&project);
|
||||
editor.setCurrentStrip(project.terminalStrip().first());
|
||||
QAbstractItemView *table = editor.findChild<QAbstractItemView *>(
|
||||
QStringLiteral("m_table_widget"));
|
||||
QVERIFY2(table && table->model(), "the editor has its table");
|
||||
QAbstractItemModel *model = table->model();
|
||||
const QModelIndex cell = model->index(0, TerminalStripModel::CableTarget);
|
||||
QVERIFY(model->data(cell).toString().isEmpty());
|
||||
QVERIFY(model->flags(cell) & Qt::ItemIsEditable);
|
||||
|
||||
const QString typed{QStringLiteral("Boiler room / Cabinet 3 / -K3")};
|
||||
QVERIFY(model->setData(cell, typed, Qt::EditRole));
|
||||
QCOMPARE(model->data(cell, Qt::EditRole).toString(), typed);
|
||||
QCOMPARE(model->data(cell).toString(), typed);
|
||||
|
||||
//Apply writes it in the element, and nowhere else
|
||||
editor.apply();
|
||||
QCOMPARE(element->elementData().m_informations
|
||||
.value(RealTerminal::cableTargetInfoKey()).toString(), typed);
|
||||
//Three fields, written the way the column shows them: the box
|
||||
//draws three lines, without the slashes
|
||||
QCOMPARE(real_t->cableTarget(),
|
||||
(QVector<QString>{QStringLiteral("Boiler room"),
|
||||
QStringLiteral("Cabinet 3"),
|
||||
QStringLiteral("-K3")}));
|
||||
QVERIFY(!real_t->cableTargetIsAutomatic());
|
||||
|
||||
//A fresh model shows the text and still lets it be edited
|
||||
TerminalStripModel model_after(project.terminalStrip().first());
|
||||
const QModelIndex after_cell = model_after.index(
|
||||
0, TerminalStripModel::CableTarget);
|
||||
QCOMPARE(model_after.data(after_cell).toString(), typed);
|
||||
QVERIFY(model_after.flags(after_cell) & Qt::ItemIsEditable);
|
||||
|
||||
//The piece the cable lands on is named now : once the cable is
|
||||
//wired the drawing gives the target of its own, and that one is
|
||||
//read only while the text typed in by hand stays in the element
|
||||
Element *target = (outgoing->terminal1
|
||||
&& outgoing->terminal1->parentElement() == real_t->element())
|
||||
? (outgoing->terminal2 ? outgoing->terminal2->parentElement() : nullptr)
|
||||
: (outgoing->terminal1 ? outgoing->terminal1->parentElement() : nullptr);
|
||||
QVERIFY(target);
|
||||
ElementData named = target->elementData();
|
||||
named.m_informations.addValue(QETInformation::ELMT_PLANT,
|
||||
QStringLiteral("Plant 9"));
|
||||
named.m_informations.addValue(QETInformation::ELMT_LOCATION,
|
||||
QStringLiteral("Cabinet 9"));
|
||||
named.m_informations.addValue(QETInformation::ELMT_LABEL,
|
||||
QStringLiteral("-S9"));
|
||||
target->setElementData(named);
|
||||
|
||||
Cable *cable = wireCable(project, real_t, 1, QStringLiteral("15W1"),
|
||||
outgoing);
|
||||
QVERIFY(cable);
|
||||
QVERIFY(real_t->cableTargetIsAutomatic());
|
||||
QCOMPARE(real_t->cableTarget(),
|
||||
(QVector<QString>{QStringLiteral("Plant 9"),
|
||||
QStringLiteral("Cabinet 9"),
|
||||
QStringLiteral("-S9")}));
|
||||
QCOMPARE(element->elementData().m_informations
|
||||
.value(RealTerminal::cableTargetInfoKey()).toString(), typed);
|
||||
|
||||
TerminalStripModel model_cable(project.terminalStrip().first());
|
||||
const QModelIndex cable_cell = model_cable.index(
|
||||
0, TerminalStripModel::CableTarget);
|
||||
QCOMPARE(model_cable.data(cable_cell).toString(),
|
||||
QStringLiteral("Plant 9 / Cabinet 9 / -S9"));
|
||||
QVERIFY(!(model_cable.flags(cable_cell) & Qt::ItemIsEditable));
|
||||
//And the automatic target was never written in the element
|
||||
QCOMPARE(element->elementData().m_informations
|
||||
.value(RealTerminal::cableTargetInfoKey()).toString(), typed);
|
||||
|
||||
//The cable taken away : the text typed in by hand is back, cell
|
||||
//and all, no stale Plant 9 anywhere
|
||||
cable->removeCore(1);
|
||||
QVERIFY(!real_t->cableTargetIsAutomatic());
|
||||
QCOMPARE(real_t->cableTarget(),
|
||||
(QVector<QString>{QStringLiteral("Boiler room"),
|
||||
QStringLiteral("Cabinet 3"),
|
||||
QStringLiteral("-K3")}));
|
||||
TerminalStripModel model_back(project.terminalStrip().first());
|
||||
const QModelIndex back_cell = model_back.index(
|
||||
0, TerminalStripModel::CableTarget);
|
||||
QCOMPARE(model_back.data(back_cell).toString(), typed);
|
||||
QVERIFY(model_back.flags(back_cell) & Qt::ItemIsEditable);
|
||||
}
|
||||
|
||||
// A text typed in by hand is written the way the fields are shown in
|
||||
// the column, "Installation / Location / Label": the box under the
|
||||
// cable draws one line per field, without the slashes, exactly like a
|
||||
// target worked out from the project.
|
||||
void typedTargetGivesOneLinePerField()
|
||||
{
|
||||
const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
|
||||
QETProject project(fixture);
|
||||
QCOMPARE(project.state(), QETProject::Ok);
|
||||
|
||||
const auto real_t = wiredTerminal(project);
|
||||
QVERIFY(!real_t.isNull());
|
||||
Element *element = real_t->element();
|
||||
QVERIFY(element);
|
||||
|
||||
//One field only: one single line in the box
|
||||
ElementData typed = element->elementData();
|
||||
typed.m_informations.addValue(RealTerminal::cableTargetInfoKey(),
|
||||
QStringLiteral("Boiler room"));
|
||||
element->setElementData(typed);
|
||||
QCOMPARE(real_t->cableTarget(),
|
||||
QVector<QString>{QStringLiteral("Boiler room")});
|
||||
|
||||
//Three fields: three lines, and no slash anywhere in them
|
||||
typed = element->elementData();
|
||||
typed.m_informations.addValue(RealTerminal::cableTargetInfoKey(),
|
||||
QStringLiteral("Plant 9 / Cabinet 9 / -S9"));
|
||||
element->setElementData(typed);
|
||||
QCOMPARE(real_t->cableTarget(),
|
||||
(QVector<QString>{QStringLiteral("Plant 9"),
|
||||
QStringLiteral("Cabinet 9"),
|
||||
QStringLiteral("-S9")}));
|
||||
//A typed text is never a target of the drawing
|
||||
QVERIFY(!real_t->cableTargetIsAutomatic());
|
||||
|
||||
//The column shows the text back the way it was written
|
||||
TerminalStripModel model(project.terminalStrip().first());
|
||||
QCOMPARE(model.data(model.index(0, TerminalStripModel::CableTarget))
|
||||
.toString(), QStringLiteral("Plant 9 / Cabinet 9 / -S9"));
|
||||
}
|
||||
};
|
||||
|
||||
QET_APP_TEST_MAIN(tst_terminalcableauto)
|
||||
|
||||
Reference in New Issue
Block a user