Improve terminal_strip

This commit is contained in:
Laurent Trinques
2026-10-09 09:18:40 +02:00
parent bdeef6d306
commit e89c69719a
16 changed files with 729 additions and 32 deletions
@@ -39,12 +39,16 @@ namespace TerminalStripDrawer
{
public:
DemoRealTerminal(const QString &label, const QString &xref, const QUuid &bridge,
ElementData::TerminalType type = ElementData::TTGeneric, bool led = false) :
ElementData::TerminalType type = ElementData::TTGeneric, bool led = false,
const QString &cable = QString(), const QString &wire = QString(), bool shield = false) :
m_label { label },
m_xref{ xref },
m_bridge { bridge },
m_type { type },
m_led { led }
m_led { led },
m_cable { cable },
m_wire { wire },
m_shield { shield }
{}
QString label() const override {
@@ -71,11 +75,25 @@ namespace TerminalStripDrawer
return m_led;
}
QString cable() const override {
return m_cable;
}
QString cableWire() const override {
return m_wire;
}
bool isShield() const override {
return m_shield;
}
private:
QString m_label, m_xref;
QUuid m_bridge;
ElementData::TerminalType m_type;
bool m_led;
QString m_cable, m_wire;
bool m_shield;
};
class DemoPhysicalTerminal : public AbstractPhysicalTerminalInterface
@@ -122,19 +140,19 @@ namespace TerminalStripDrawer
real_terminals_vector << QSharedPointer<AbstractRealTerminalInterface> {
new DemoRealTerminal( QStringLiteral("24vdc"),
QStringLiteral("1_A1"),
lvl_1, ElementData::TTFuse, false)};
lvl_1, ElementData::TTFuse, false, QStringLiteral("9W2"), QStringLiteral("1"), false)};
real_terminals_vector << QSharedPointer<AbstractRealTerminalInterface> {
new DemoRealTerminal( QStringLiteral("0vdc"),
QStringLiteral("1_A2"),
lvl_2, ElementData::TTSectional, false)};
lvl_2, ElementData::TTSectional, false, QStringLiteral("9W2"), QStringLiteral("2"), false)};
real_terminals_vector << QSharedPointer<AbstractRealTerminalInterface> {
new DemoRealTerminal( QStringLiteral("signal"),
QStringLiteral("1_A3"),
lvl_3, ElementData::TTDiode, false)};
lvl_3, ElementData::TTDiode, false, QStringLiteral("9W2"), QStringLiteral("3"), false)};
real_terminals_vector << QSharedPointer<AbstractRealTerminalInterface> {
new DemoRealTerminal( QStringLiteral("teach"),
QStringLiteral("1_A4"),
lvl_4, ElementData::TTGround, false)};
lvl_4, ElementData::TTGround, false, QStringLiteral("9W2"), QStringLiteral(""), true)};
m_physical_terminal << QSharedPointer<AbstractPhysicalTerminalInterface> {
new DemoPhysicalTerminal {real_terminals_vector}};
@@ -89,6 +89,14 @@ class TerminalStripLayoutPattern
//Length of the connection drawn above and under each terminal,
//in the middle of the terminal. 0 disable the connections.
qreal m_connection_length{10};
//Cable drawn under the terminals which have a cable (hose).
//Length of the wires between the terminals and the cable
//0 disable the drawing of the cables.
qreal m_cable_wire_length{40};
//Length of the cable
qreal m_cable_length{60};
//Length of the wires after the cable
qreal m_cable_end_length{40};
qreal m_bridge_point_d{5};
QVector<qreal> m_bridge_point_y_offset{50,70,90,110};
@@ -18,6 +18,7 @@
#include "terminalstripdrawer.h"
#include <QPainter>
#include <QFontMetricsF>
#include <QHash>
#include <algorithm>
@@ -168,13 +169,15 @@ void drawTypeSymbol(QPainter *painter, const QRectF &box, ElementData::TerminalT
/**
* @brief drawConnections
* Draw a connection above and a connection under @a terminal_rect, in the middle
* of the rect. A connection is a short line ended by a little circle.
* Draw a connection above and, if @a draw_bottom is true, a connection under
* @a terminal_rect, in the middle of the rect.
* A connection is a short line ended by a little circle.
* @param painter
* @param terminal_rect
* @param length : the total length of a connection, circle included
* @param draw_bottom : false if the cable is drawn under the terminal
*/
void drawConnections(QPainter *painter, const QRectF &terminal_rect, qreal length)
void drawConnections(QPainter *painter, const QRectF &terminal_rect, qreal length, bool draw_bottom)
{
const qreal radius{qMin<qreal>(length / 4, 2)};
const qreal x{terminal_rect.width() / 2};
@@ -184,8 +187,163 @@ void drawConnections(QPainter *painter, const QRectF &terminal_rect, qreal lengt
painter->drawLine(QPointF{x, top}, QPointF{x, top - length + radius * 2});
painter->drawEllipse(QPointF{x, top - length + radius}, radius, radius);
painter->drawLine(QPointF{x, bottom}, QPointF{x, bottom + length - radius * 2});
painter->drawEllipse(QPointF{x, bottom + length - radius}, radius, radius);
if (draw_bottom)
{
painter->drawLine(QPointF{x, bottom}, QPointF{x, bottom + length - radius * 2});
painter->drawEllipse(QPointF{x, bottom + length - radius}, radius, radius);
}
}
/**
* @brief The CableCell struct
* What is needed to draw the cable under a terminal.
*/
struct CableCell
{
qreal x{0}; ///< x of the middle of the terminal, in the strip coordinates
qreal bottom{0}; ///< y of the bottom of the terminal
QString cable; ///< name of the cable (hose)
QString wire; ///< color / number of the wire
bool shield{false}; ///< true if the terminal is the shield of the cable
};
/**
* @brief drawCables
* Draw the cables under the terminals. Consecutive terminals who have the same cable name
* share the same cable: the wires go down from the terminals, join in the cable,
* and leave the cable with the same wire marks. The shield is linked to a dashed ellipse
* drawn around the cable.
* @param painter : the pen and the font must be set
* @param cells : one cell per terminal, in the drawing order
* @param pattern
*/
void drawCables(QPainter *painter, const QVector<CableCell> &cells, const TerminalStripLayoutPattern &pattern)
{
const qreal wire_length{pattern.m_cable_wire_length};
if (wire_length <= 0 || cells.isEmpty()) {
return;
}
const qreal cable_length{qMax<qreal>(0, pattern.m_cable_length)};
const qreal end_length{qMax<qreal>(0, pattern.m_cable_end_length)};
const qreal radius{2};
const QFontMetricsF font_metrics{painter->font()};
const qreal text_height{font_metrics.height()};
//Draw a mark (small oblique line) on a wire and the number of the wire next to it.
//The text is written from the bottom to the top, at the left of the wire.
const auto draw_wire_mark = [&](qreal x, qreal mark_y, const QString &text, bool text_above)
{
painter->drawLine(QPointF{x - 3, mark_y + 3}, QPointF{x + 3, mark_y - 3});
if (text.isEmpty()) {
return;
}
const qreal text_width{font_metrics.horizontalAdvance(text)};
painter->save();
painter->translate(x - 1, text_above ? mark_y - 4 : mark_y + 4 + text_width);
painter->rotate(270);
painter->drawText(QRectF{0, -text_height, text_width + 2, text_height},
Qt::AlignLeft | Qt::AlignVCenter,
text);
painter->restore();
};
auto first{0};
while (first < cells.size())
{
if (cells.at(first).cable.isEmpty()) {
++first;
continue;
}
//Find the last terminal of the cable
auto last{first};
while (last + 1 < cells.size() &&
cells.at(last + 1).cable == cells.at(first).cable) {
++last;
}
QVector<CableCell> wires, shields;
qreal max_bottom{cells.at(first).bottom};
for (auto i = first ; i <= last ; ++i)
{
max_bottom = qMax(max_bottom, cells.at(i).bottom);
if (cells.at(i).shield) {
shields << cells.at(i);
} else {
wires << cells.at(i);
}
}
//A cable with only a shield is drawn like a cable with only one wire
if (wires.isEmpty()) {
wires = shields;
shields.clear();
}
const qreal min_x{wires.first().x};
const qreal max_x{wires.last().x};
const qreal cable_x{(min_x + max_x) / 2};
const qreal bar_1_y{max_bottom + wire_length};
const qreal bar_2_y{bar_1_y + cable_length};
const qreal end_y{bar_2_y + end_length};
//Wires between the terminals and the cable
for (const auto &wire : std::as_const(wires))
{
painter->drawLine(QPointF{wire.x, wire.bottom}, QPointF{wire.x, bar_1_y});
draw_wire_mark(wire.x, qMax(wire.bottom + 4, bar_1_y - 10), wire.wire, true);
}
painter->drawLine(QPointF{min_x, bar_1_y}, QPointF{max_x, bar_1_y});
//The cable
painter->drawLine(QPointF{cable_x, bar_1_y}, QPointF{cable_x, bar_2_y});
//Wires after the cable
painter->drawLine(QPointF{min_x, bar_2_y}, QPointF{max_x, bar_2_y});
for (const auto &wire : std::as_const(wires))
{
painter->drawLine(QPointF{wire.x, bar_2_y}, QPointF{wire.x, end_y});
draw_wire_mark(wire.x, qMin(bar_2_y + 10, end_y), wire.wire, false);
painter->drawEllipse(QPointF{wire.x, end_y + radius}, radius, radius);
}
//The shield, linked to an ellipse around the cable
const qreal ellipse_ry{6};
const qreal ellipse_rx{qMax<qreal>((max_x - min_x) / 2 + 4, 12)};
const qreal ellipse_y{shields.isEmpty() ? bar_2_y : qMax(bar_1_y + ellipse_ry, bar_2_y - 12)};
if (!shields.isEmpty())
{
for (const auto &shield : std::as_const(shields))
{
painter->drawLine(QPointF{shield.x, shield.bottom}, QPointF{shield.x, ellipse_y});
const qreal edge_x{shield.x > cable_x ? cable_x + ellipse_rx : cable_x - ellipse_rx};
painter->drawLine(QPointF{shield.x, ellipse_y}, QPointF{edge_x, ellipse_y});
}
painter->save();
auto dashed_pen{painter->pen()};
dashed_pen.setStyle(Qt::DashLine);
painter->setPen(dashed_pen);
painter->drawEllipse(QPointF{cable_x, ellipse_y}, ellipse_rx, ellipse_ry);
painter->restore();
}
//Name of the cable, at the left of the cable, above the ellipse
const qreal name_width{font_metrics.horizontalAdvance(cells.at(first).cable)};
const qreal name_top{bar_1_y};
const qreal name_bottom{shields.isEmpty() ? bar_2_y : ellipse_y - ellipse_ry};
painter->save();
painter->translate(cable_x - 2, (name_top + name_bottom) / 2 + name_width / 2);
painter->rotate(270);
painter->drawText(QRectF{0, -text_height, name_width + 2, text_height},
Qt::AlignLeft | Qt::AlignVCenter,
cells.at(first).cable);
painter->restore();
first = last + 1;
}
}
} //End anonymous namespace
@@ -271,6 +429,7 @@ void TerminalStripDrawer::paint(QPainter *painter)
QRectF xref_rect;
QHash<QUuid, QVector<QPointF>> bridges_anchor_points;
QVector<CableCell> cable_cells;
m_hovered_xref = hoverTerminal{};
int physical_index = 0;
@@ -291,6 +450,19 @@ void TerminalStripDrawer::paint(QPainter *painter)
}
terminal_rect = m_pattern->m_terminal_rect[index_];
//Cable (hose) of this terminal
CableCell cable_cell;
if (real_terminal_vector[i])
{
cable_cell.x = x_offset + terminal_rect.width()/2;
cable_cell.bottom = terminal_rect.y() + terminal_rect.height();
cable_cell.cable = real_terminal_vector[i]->cable();
cable_cell.wire = real_terminal_vector[i]->cableWire();
cable_cell.shield = real_terminal_vector[i]->isShield();
}
const bool have_cable{m_pattern->m_cable_wire_length > 0 && !cable_cell.cable.isEmpty()};
cable_cells.append(cable_cell);
//Draw terminal rect
painter->drawRect(terminal_rect);
@@ -306,7 +478,8 @@ void TerminalStripDrawer::paint(QPainter *painter)
//Draw the connections, above and under the terminal
if (m_pattern->m_connection_length > 0) {
drawConnections(painter, terminal_rect, m_pattern->m_connection_length);
//The cable replace the connection under the terminal
drawConnections(painter, terminal_rect, m_pattern->m_connection_length, !have_cable);
}
//Draw a stronger line if the current terminal have level
//and the current level is the first
@@ -442,6 +615,17 @@ void TerminalStripDrawer::paint(QPainter *painter)
painter->drawPolyline(QPolygonF(points_));
painter->restore();
}
//Draw the cables
painter->save();
auto cable_pen{painter->pen()};
cable_pen.setColor(Qt::black);
cable_pen.setWidth(1);
painter->setPen(cable_pen);
painter->setFont(m_pattern->font());
painter->setBrush(Qt::NoBrush);
drawCables(painter, cable_cells, *m_pattern);
painter->restore();
}
}
@@ -449,16 +633,52 @@ QRectF TerminalStripDrawer::boundingRect() const
{
QRectF rect_{0, 0, width(), height()};
//The connections are drawn above and under the terminals
if (m_pattern && m_pattern->m_connection_length > 0)
if (m_pattern)
{
const auto length_{m_pattern->m_connection_length};
qreal top_{0};
for (const auto &terminal_rect : std::as_const(m_pattern->m_terminal_rect)) {
top_ = std::min(top_, terminal_rect.top() - length_);
qreal extra_bottom{0};
//The connections are drawn above and under the terminals
if (m_pattern->m_connection_length > 0)
{
const auto length_{m_pattern->m_connection_length};
qreal top_{0};
for (const auto &terminal_rect : std::as_const(m_pattern->m_terminal_rect)) {
top_ = std::min(top_, terminal_rect.top() - length_);
}
rect_.setTop(top_);
extra_bottom = length_;
}
rect_.setBottom(rect_.bottom() + length_);
rect_.setTop(top_);
//The cables are drawn under the terminals
if (m_strip && m_pattern->m_cable_wire_length > 0)
{
bool have_cable{false};
for (const auto &physical_t : m_strip->physicalTerminal())
{
for (const auto &real_t : physical_t->realTerminals())
{
if (real_t && !real_t->cable().isEmpty()) {
have_cable = true;
break;
}
}
if (have_cable) {
break;
}
}
if (have_cable)
{
//4 is the diameter of the circle at the end of the wires
extra_bottom = std::max(extra_bottom,
m_pattern->m_cable_wire_length
+ std::max<qreal>(0, m_pattern->m_cable_length)
+ std::max<qreal>(0, m_pattern->m_cable_end_length)
+ 4);
}
}
rect_.setBottom(rect_.bottom() + extra_bottom);
}
return rect_;
@@ -61,6 +61,10 @@ namespace TerminalStripDrawer
//They are not pure virtual, so an implementation can ignore them.
virtual ElementData::TerminalType type() const { return ElementData::TTGeneric; }
virtual bool isLed() const { return false; }
//Cable (hose) connected to the terminal, drawn under the strip.
virtual QString cable() const { return QString(); }
virtual QString cableWire() const { return QString(); }
virtual bool isShield() const { return false; }
};
class AbstractPhysicalTerminalInterface
@@ -138,6 +138,21 @@ namespace TerminalStripDrawer
return m_real ? m_real->isLed() : false;
}
QString TrueRealTerminal::cable() const
{
return m_real ? m_real->cable() : QString();
}
QString TrueRealTerminal::cableWire() const
{
return m_real ? m_real->cableWire() : QString();
}
bool TrueRealTerminal::isShield() const
{
return m_real ? m_real->isShield() : false;
}
TrueBridge::TrueBridge(QSharedPointer<TerminalStripBridge> bridge) :
m_bridge { bridge }
{}
@@ -61,6 +61,9 @@ namespace TerminalStripDrawer
QString xref() const override;
ElementData::TerminalType type() const override;
bool isLed() const override;
QString cable() const override;
QString cableWire() const override;
bool isShield() const override;
private:
QSharedPointer<RealTerminal> m_real;
+22 -2
View File
@@ -157,20 +157,40 @@ QString RealTerminal::Xref() const
/**
* @brief RealTerminal::cable
* @return
* @return The name of the cable (hose) connected to this terminal.
* The value is stored in the informations of the element.
*/
QString RealTerminal::cable() const {
if (m_element) {
return m_element->elementData().m_informations.value(cableInfoKey()).toString();
}
return QString();
}
/**
* @brief RealTerminal::cableWire
* @return
* @return The color / number of the wire of the cable, connected to this terminal.
*/
QString RealTerminal::cableWire() const {
if (m_element) {
return m_element->elementData().m_informations.value(cableWireInfoKey()).toString();
}
return QString();
}
/**
* @brief RealTerminal::isShield
* @return true if this terminal is the shield of the cable
* and not one of its wires.
*/
bool RealTerminal::isShield() const {
if (m_element) {
return QET::infoFlagIsTrue(
m_element->elementData().m_informations.value(shieldInfoKey()).toString());
}
return false;
}
/**
* @brief RealTerminal::conductor
* @return
+7
View File
@@ -65,6 +65,13 @@ class RealTerminal
QString Xref() const;
QString cable() const;
QString cableWire() const;
bool isShield() const;
//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"); }
static QString shieldInfoKey() { return QStringLiteral("terminal_shield"); }
QString conductor() const;
ElementData::TerminalType type() const;
@@ -36,6 +36,7 @@ struct modelRealTerminalData
mrtd.cable_wire = real_t->cableWire();
mrtd.conductor_ = real_t->conductor();
mrtd.led_ = real_t->isLed();
mrtd.shield_ = real_t->isShield();
mrtd.type_ = real_t->type();
mrtd.function_ = real_t->function();
mrtd.element_ = real_t->element();
@@ -53,6 +54,7 @@ struct modelRealTerminalData
QString cable_wire;
QString conductor_;
bool led_ = false;
bool shield_ = false;
bool bridged_ = false;
ElementData::TerminalType type_ = ElementData::TerminalType::TTGeneric;
@@ -32,6 +32,13 @@
#include "../physicalterminal.h"
#include "../terminalstripbridge.h"
#include <QApplication>
#include <QClipboard>
#include <QKeyEvent>
#include <algorithm>
#include <limits>
/**
* @brief TerminalStripEditor::TerminalStripEditor
* @param project : Project to manage the terminal strip
@@ -46,6 +53,9 @@ TerminalStripEditor::TerminalStripEditor(QETProject *project, QWidget *parent) :
ui->m_table_widget->setItemDelegate(new TerminalStripModelDelegate{this});
//Copy, paste and delete of the cells with the keyboard
ui->m_table_widget->installEventFilter(this);
//Setup the bridge color
ui->m_bridge_color_cb->setColors(TerminalStripBridge::bridgeColor().toList());
@@ -198,6 +208,15 @@ void TerminalStripEditor::apply()
current_data.setTerminalFunction(data_.function_);
current_data.setTerminalLED(data_.led_);
current_data.m_informations.addValue(QStringLiteral("label"), data_.label_);
//The cable data are only stored when they are used
const auto set_info = [&current_data](const QString &key, const QString &value) {
if (!value.isEmpty() || current_data.m_informations.contains(key)) {
current_data.m_informations.addValue(key, value);
}
};
set_info(RealTerminal::cableInfoKey(), data_.cable_);
set_info(RealTerminal::cableWireInfoKey(), data_.cable_wire);
set_info(RealTerminal::shieldInfoKey(), data_.shield_ ? QStringLiteral("true") : QString());
if (element->elementData() != current_data)
m_project->undoStack()->push(new ChangeElementDataCommand(element, current_data));
@@ -265,6 +284,8 @@ void TerminalStripEditor::selectionChanged()
ui->m_type_cb ->setDisabled(true);
ui->m_function_cb ->setDisabled(true);
ui->m_led_cb ->setDisabled(true);
ui->m_cable_le ->setDisabled(true);
ui->m_cable_apply_pb ->setDisabled(true);
ui->m_bridge_terminals_pb ->setDisabled(true);
ui->m_unbridge_terminals_pb->setDisabled(true);
@@ -280,10 +301,14 @@ void TerminalStripEditor::selectionChanged()
ui->m_type_cb ->setDisabled(true);
ui->m_function_cb ->setDisabled(true);
ui->m_led_cb ->setDisabled(true);
ui->m_cable_le ->setDisabled(true);
ui->m_cable_apply_pb->setDisabled(true);
} else {
ui->m_type_cb ->setEnabled(true);
ui->m_function_cb ->setEnabled(true);
ui->m_led_cb ->setEnabled(true);
ui->m_cable_le ->setEnabled(true);
ui->m_cable_apply_pb->setEnabled(true);
}
const auto model_physical_terminal_vector = m_model->modelPhysicalTerminalDataForIndex(index_list);
@@ -601,6 +626,222 @@ void TerminalStripEditor::on_m_led_cb_activated(int index)
}
}
namespace {
/**
* @return true if the cell at @a index contain a free text
* (label, cable or wire of the cable), so a text can be pasted in it.
*/
bool cellAcceptText(const QModelIndex &index)
{
const auto column_ = TerminalStripModel::columnTypeForIndex(index);
return column_ == TerminalStripModel::Label
|| column_ == TerminalStripModel::Cable
|| column_ == TerminalStripModel::CableWire;
}
}
/**
* @brief TerminalStripEditor::eventFilter
* Manage the shortcuts copy, paste and delete in the table
* @param watched
* @param event
* @return
*/
bool TerminalStripEditor::eventFilter(QObject *watched, QEvent *event)
{
if (watched == ui->m_table_widget &&
event->type() == QEvent::KeyPress &&
m_model)
{
const auto key_event = static_cast<QKeyEvent *>(event);
if (key_event->matches(QKeySequence::Copy)) {
copySelectionToClipboard();
return true;
}
if (key_event->matches(QKeySequence::Paste)) {
pasteFromClipboard();
return true;
}
if (key_event->matches(QKeySequence::Delete)) {
clearSelectedTexts();
return true;
}
}
return QWidget::eventFilter(watched, event);
}
/**
* @brief TerminalStripEditor::copySelectionToClipboard
* Copy the selected cells to the clipboard, as a text where the columns
* are separated by a tabulation and the rows by a new line
* (the format used by the spreadsheets).
*/
void TerminalStripEditor::copySelectionToClipboard()
{
if (!m_model || !ui->m_table_widget->selectionModel()) {
return;
}
const auto selection = ui->m_table_widget->selectionModel()->selectedIndexes();
if (selection.isEmpty()) {
return;
}
int top{std::numeric_limits<int>::max()}, left{std::numeric_limits<int>::max()}, bottom{-1}, right{-1};
QHash<qint64, QString> texts;
for (const auto &index : selection)
{
top = std::min(top, index.row());
left = std::min(left, index.column());
bottom = std::max(bottom, index.row());
right = std::max(right, index.column());
texts.insert((qint64(index.row()) << 32) | qint64(index.column()),
index.data(Qt::DisplayRole).toString());
}
QStringList lines;
for (auto row = top ; row <= bottom ; ++row)
{
QStringList cells;
for (auto column = left ; column <= right ; ++column) {
cells << texts.value((qint64(row) << 32) | qint64(column));
}
lines << cells.join(QLatin1Char('\t'));
}
QApplication::clipboard()->setText(lines.join(QLatin1Char('\n')));
}
/**
* @brief TerminalStripEditor::pasteFromClipboard
* Paste the text of the clipboard in the table.
* - If the text is only one value and several cells are selected,
* the value is set to every selected cell.
* - Otherwise the text is read like a table (tabulation between the columns
* and new line between the rows) and written from the top left selected cell.
* Only the label, cable and cable wire cells are modified.
*/
void TerminalStripEditor::pasteFromClipboard()
{
if (!m_model || !ui->m_table_widget->selectionModel()) {
return;
}
auto text = QApplication::clipboard()->text();
if (text.isEmpty()) {
return;
}
text.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
text.replace(QLatin1Char('\r'), QLatin1Char('\n'));
auto lines = text.split(QLatin1Char('\n'));
//A spreadsheet end the last row with a new line
if (lines.size() > 1 && lines.last().isEmpty()) {
lines.removeLast();
}
const auto selection = ui->m_table_widget->selectionModel()->selectedIndexes();
//One value, several cells : set the value to all of them
if (lines.size() == 1 &&
!lines.first().contains(QLatin1Char('\t')) &&
selection.size() > 1)
{
for (const auto &index : selection)
{
if (cellAcceptText(index)) {
m_model->setData(index, lines.first(), Qt::EditRole);
}
}
return;
}
//Else write the text like a table, from the top left selected cell
int first_row{-1}, first_column{-1};
if (selection.isEmpty())
{
const auto current_ = ui->m_table_widget->currentIndex();
if (!current_.isValid()) {
return;
}
first_row = current_.row();
first_column = current_.column();
}
else
{
first_row = std::numeric_limits<int>::max();
first_column = std::numeric_limits<int>::max();
for (const auto &index : selection) {
first_row = std::min(first_row, index.row());
first_column = std::min(first_column, index.column());
}
}
for (auto i = 0 ; i < lines.size() ; ++i)
{
const auto row = first_row + i;
if (row >= m_model->rowCount()) {
break;
}
const auto cells = lines.at(i).split(QLatin1Char('\t'));
for (auto j = 0 ; j < cells.size() ; ++j)
{
const auto column = first_column + j;
if (column >= m_model->columnCount()) {
break;
}
const auto index = m_model->index(row, column);
if (cellAcceptText(index)) {
m_model->setData(index, cells.at(j), Qt::EditRole);
}
}
}
}
/**
* @brief TerminalStripEditor::clearSelectedTexts
* Erase the text of the selected cells who accept a text.
*/
void TerminalStripEditor::clearSelectedTexts()
{
if (!m_model || !ui->m_table_widget->selectionModel()) {
return;
}
const auto selection = ui->m_table_widget->selectionModel()->selectedIndexes();
for (const auto &index : selection)
{
if (cellAcceptText(index)) {
m_model->setData(index, QString(), Qt::EditRole);
}
}
}
/**
* @brief TerminalStripEditor::on_m_cable_apply_pb_clicked
* Set the cable name written in the line edit
* to every selected terminal.
*/
void TerminalStripEditor::on_m_cable_apply_pb_clicked()
{
if (m_model)
{
const auto index_list = ui->m_table_widget->selectionModel()->selectedIndexes();
const auto cable_name = ui->m_cable_le->text();
for (auto model_index : index_list)
{
const auto cable_index = m_model->index(model_index.row(), TerminalStripModel::Cable, model_index.parent());
if (cable_index.isValid()) {
m_model->setData(cable_index, cable_name, Qt::EditRole);
}
}
}
}
/**
* @brief TerminalStripEditor::on_m_bridge_terminals_pb_clicked
*/
@@ -46,7 +46,13 @@ class TerminalStripEditor : public QWidget
void reload();
void apply();
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
private:
void copySelectionToClipboard();
void pasteFromClipboard();
void clearSelectedTexts();
void clear();
void spanMultiLevelTerminals();
void selectionChanged();
@@ -62,6 +68,7 @@ class TerminalStripEditor : public QWidget
void on_m_type_cb_activated(int index);
void on_m_function_cb_activated(int index);
void on_m_led_cb_activated(int index);
void on_m_cable_apply_pb_clicked();
void on_m_bridge_terminals_pb_clicked();
void on_m_unbridge_terminals_pb_clicked();
void on_m_bridge_color_cb_activated(const QColor &col);
@@ -67,7 +67,7 @@
</property>
</widget>
</item>
<item row="12" column="1" colspan="2">
<item row="14" column="1" colspan="2">
<widget class="KColorCombo" name="m_bridge_color_cb"/>
</item>
<item row="5" column="0">
@@ -90,7 +90,7 @@
</property>
</widget>
</item>
<item row="12" column="0">
<item row="14" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Bridge color :</string>
@@ -139,14 +139,41 @@
</property>
</widget>
</item>
<item row="9" column="0" colspan="3">
<item row="9" column="0">
<widget class="QLabel" name="label_cable">
<property name="text">
<string>Cable :</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="9" column="1" colspan="2">
<widget class="QLineEdit" name="m_cable_le">
<property name="toolTip">
<string>Name of the cable of the selected terminals</string>
</property>
</widget>
</item>
<item row="10" column="1" colspan="2">
<widget class="QPushButton" name="m_cable_apply_pb">
<property name="toolTip">
<string>Set the cable name to all the selected terminals</string>
</property>
<property name="text">
<string>Apply the cable to the selection</string>
</property>
</widget>
</item>
<item row="11" column="0" colspan="3">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="13" column="0">
<item row="15" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -233,14 +260,14 @@
</property>
</widget>
</item>
<item row="10" column="1" colspan="2">
<item row="12" column="1" colspan="2">
<widget class="QPushButton" name="m_bridge_terminals_pb">
<property name="text">
<string>Bridging the terminals</string>
</property>
</widget>
</item>
<item row="11" column="1" colspan="2">
<item row="13" column="1" colspan="2">
<widget class="QPushButton" name="m_unbridge_terminals_pb">
<property name="text">
<string>Unbridge the terminals</string>
@@ -155,6 +155,9 @@ void TerminalStripLayoutEditor::valueEdited()
m_layout.data()->m_type_symbol_y = ui->m_type_symbol_y_sb->value();
m_layout.data()->m_type_symbol_height = ui->m_type_symbol_height_sb->value();
m_layout.data()->m_connection_length = ui->m_connection_length_sb->value();
m_layout.data()->m_cable_wire_length = ui->m_cable_wire_length_sb->value();
m_layout.data()->m_cable_length = ui->m_cable_length_sb->value();
m_layout.data()->m_cable_end_length = ui->m_cable_end_length_sb->value();
updateUi();
m_preview_strip_item.update();
@@ -264,6 +267,9 @@ void TerminalStripLayoutEditor::updateUi()
ui->m_type_symbol_y_sb->setValue(data->m_type_symbol_y);
ui->m_type_symbol_height_sb->setValue(data->m_type_symbol_height);
ui->m_connection_length_sb->setValue(data->m_connection_length);
ui->m_cable_wire_length_sb->setValue(data->m_cable_wire_length);
ui->m_cable_length_sb->setValue(data->m_cable_length);
ui->m_cable_end_length_sb->setValue(data->m_cable_end_length);
m_ui_updating = false;
updatePreview();
@@ -503,6 +503,43 @@
</property>
</widget>
</item>
<item row="10" column="2">
<widget class="QLabel" name="label_cable">
<property name="text">
<string>Cable: wires / cable / end</string>
</property>
</widget>
</item>
<item row="10" column="3">
<widget class="QSpinBox" name="m_cable_wire_length_sb">
<property name="toolTip">
<string>Length of the wires between the terminals and the cable. 0 disable the drawing of the cables.</string>
</property>
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
<item row="10" column="4">
<widget class="QSpinBox" name="m_cable_length_sb">
<property name="toolTip">
<string>Length of the cable.</string>
</property>
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
<item row="10" column="5">
<widget class="QSpinBox" name="m_cable_end_length_sb">
<property name="toolTip">
<string>Length of the wires after the cable.</string>
</property>
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -1186,6 +1223,54 @@
</hint>
</hints>
</connection>
<connection>
<sender>m_cable_wire_length_sb</sender>
<signal>valueChanged(int)</signal>
<receiver>TerminalStripLayoutEditor</receiver>
<slot>valueEdited()</slot>
<hints>
<hint type="sourcelabel">
<x>700</x>
<y>460</y>
</hint>
<hint type="destinationlabel">
<x>480</x>
<y>311</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_cable_length_sb</sender>
<signal>valueChanged(int)</signal>
<receiver>TerminalStripLayoutEditor</receiver>
<slot>valueEdited()</slot>
<hints>
<hint type="sourcelabel">
<x>700</x>
<y>460</y>
</hint>
<hint type="destinationlabel">
<x>480</x>
<y>311</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_cable_end_length_sb</sender>
<signal>valueChanged(int)</signal>
<receiver>TerminalStripLayoutEditor</receiver>
<slot>valueEdited()</slot>
<hints>
<hint type="sourcelabel">
<x>700</x>
<y>460</y>
</hint>
<hint type="destinationlabel">
<x>480</x>
<y>311</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>valueEdited()</slot>
@@ -46,10 +46,11 @@ 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 COLUMN_COUNT = 14;
const int COLUMN_COUNT = 15;
static QVector<bool> UNMODIFIED_CELL_VECTOR{false, false, false, false, false, false, false, false, false, false, false, false, false, false};
static QVector<bool> UNMODIFIED_CELL_VECTOR{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false};
/**
* @brief TerminalStripModel::levelForColumn
@@ -93,6 +94,7 @@ TerminalStripModel::Column TerminalStripModel::columnTypeForIndex(const QModelIn
case 11 : return Type;
case 12 : return Function;
case 13 : return Led;
case 14 : return Shield;
default : return Invalid;
}
}
@@ -177,6 +179,8 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const
{
switch (index.column()) {
case LABEL_CELL : return mrtd.label_;
case CABLE_CELL : return mrtd.cable_;
case CABLE_WIRE_CELL : return mrtd.cable_wire;
default: return QVariant();
}
@@ -186,6 +190,11 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const
{
return mrtd.led_ ? Qt::Checked : Qt::Unchecked;
}
else if (role == Qt::CheckStateRole &&
index.column() == SHIELD_CELL)
{
return mrtd.shield_ ? Qt::Checked : Qt::Unchecked;
}
else if (role == Qt::BackgroundRole && index.column() < COLUMN_COUNT )
{
if (m_modified_cell.contains(mrtd.element_) &&
@@ -248,6 +257,28 @@ bool TerminalStripModel::setData(const QModelIndex &index, const QVariant &value
modified_ = true;
modified_cell = LABEL_CELL;
}
else if (column_ == CABLE_CELL &&
role == Qt::EditRole &&
mrtd.cable_ != value.toString())
{
mrtd.cable_ = value.toString();
modified_ = true;
modified_cell = CABLE_CELL;
}
else if (column_ == CABLE_WIRE_CELL &&
role == Qt::EditRole &&
mrtd.cable_wire != value.toString())
{
mrtd.cable_wire = value.toString();
modified_ = true;
modified_cell = CABLE_WIRE_CELL;
}
else if (column_ == SHIELD_CELL)
{
mrtd.shield_ = value.toBool();
modified_ = true;
modified_cell = SHIELD_CELL;
}
//Set the modification to the terminal data
if (modified_)
@@ -294,6 +325,7 @@ QVariant TerminalStripModel::headerData(int section, Qt::Orientation orientation
case TYPE_CELL: return tr("Type");
case FUNCTION_CELL : return tr("Function");
case LED_CELL: return tr("led");
case SHIELD_CELL: return tr("Shield");
default : return QVariant();
}
}
@@ -307,9 +339,10 @@ Qt::ItemFlags TerminalStripModel::flags(const QModelIndex &index) const
Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
auto c = index.column();
if (c == LABEL_CELL || c == TYPE_CELL || c == FUNCTION_CELL)
if (c == LABEL_CELL || c == TYPE_CELL || c == FUNCTION_CELL
|| c == CABLE_CELL || c == CABLE_WIRE_CELL)
flags = flags | Qt::ItemIsEditable;
if (c == LED_CELL) {
if (c == LED_CELL || c == SHIELD_CELL) {
flags = flags | Qt::ItemIsUserCheckable;
}
return flags;
@@ -61,6 +61,7 @@ class TerminalStripModel : public QAbstractTableModel
Type = 11,
Function = 12,
Led = 13,
Shield = 14,
Invalid = 99
};