mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-22 22:34:13 +02:00
Tell the fields of a target apart by line breaks only
A target typed in by hand was split into its fields on " / ", which broke as soon as a field itself contained a slash: an installation named "ASP/01" gave the box two lines with half a name in each, and nothing to tell a separator apart from the name. Only a line break now breaks the text into fields (RealTerminal::cableTarget()), and the Target cell shows the fields the very same way, one line each (modelRealTerminalData::targetText()), so the cell and the box under the cable always read the same text. The Target cell is edited line by line to go with that: it takes a multi line editor where Return writes a new line, Ctrl+Return hands the cell back to the table and Escape throws the text away (TerminalStripModelDelegate), and the rows of the table are as tall as the lines their cell shows, so the fields below the first one are never cut off -- a cell without a target keeps the row it has always had. The text copied to the clipboard keeps one line per row, the fields of such a cell joined with " / " again, or a spreadsheet would take them for several rows. tst_terminalcableauto reads the three fields of a target of the drawing back one line each, checks a "/" typed inside a field stays part of it -- one line holding it, slashes and all -- checks the editor of the cell is the multi line one, hands its text back untouched, gives the cell back on Ctrl+Return while Return keeps writing a new line, and checks the rows grow with the lines the cell holds and shrink back afterwards. tst_cabletarget paints a strip whose cable ends on a field containing a slash: the box is no deeper than with one plain field.
This commit is contained in:
@@ -413,8 +413,10 @@ bool RealTerminal::isShield() const {
|
||||
* 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.
|
||||
* written one line per field, Installation, Location and Label (BMK),
|
||||
* the way the cell shows them: only a line break breaks it into fields.
|
||||
* A "/" written inside a field (a name like "ASP/01") is part of that
|
||||
* field and never breaks anything.
|
||||
* @return the lines to write in the box under the cable
|
||||
*/
|
||||
QVector<QString> RealTerminal::cableTarget() const
|
||||
@@ -430,13 +432,15 @@ QVector<QString> RealTerminal::cableTarget() const
|
||||
.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
|
||||
//One line by field, and only a line break breaks the text
|
||||
//into fields : a "/" written inside a field stays where it is
|
||||
QString text_{typed_};
|
||||
text_.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
|
||||
text_.replace(QLatin1Char('\r'), QLatin1Char('\n'));
|
||||
|
||||
QVector<QString> lines_;
|
||||
for (const QString &field_
|
||||
: typed_.split(QStringLiteral(" / "), Qt::SkipEmptyParts)) {
|
||||
: text_.split(QLatin1Char('\n'), Qt::SkipEmptyParts)) {
|
||||
lines_ << field_;
|
||||
}
|
||||
return lines_;
|
||||
|
||||
@@ -27,10 +27,12 @@
|
||||
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
|
||||
///lands on, one line by field : what the strip draws in the box
|
||||
///under its cable (RealTerminal::cableTarget) and what the Target
|
||||
///cell shows, both read line by line. A "/" written inside a field
|
||||
///is part of that field, never a separator.
|
||||
///A target typed in by hand is kept as it was written, 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_)
|
||||
{
|
||||
@@ -41,7 +43,7 @@ struct modelRealTerminalData
|
||||
fields_ << field_;
|
||||
}
|
||||
}
|
||||
return fields_.join(QStringLiteral(" / "));
|
||||
return fields_.join(QLatin1Char('\n'));
|
||||
}
|
||||
|
||||
static modelRealTerminalData data(const QSharedPointer<RealTerminal> &real_t)
|
||||
|
||||
@@ -253,6 +253,14 @@ void TerminalStripEditor::setCurrentStrip(TerminalStrip *strip_)
|
||||
//the width of its own text, never a cut off Installation
|
||||
ui->m_table_widget->horizontalHeader()->setSectionResizeMode(
|
||||
TerminalStripModel::CableTarget, QHeaderView::ResizeToContents);
|
||||
//That column holds one line by field: its rows must be tall
|
||||
//enough for as many lines as a cell shows, while a cell of
|
||||
//one line keeps the height the rows have always had
|
||||
auto v_header_ = ui->m_table_widget->verticalHeader();
|
||||
v_header_->setMinimumSectionSize(qMax(
|
||||
v_header_->defaultSectionSize(),
|
||||
ui->m_table_widget->rowHeight(0)));
|
||||
v_header_->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
m_model->buildBridgePixmap(setUpBridgeCellWidth());
|
||||
connect(ui->m_table_widget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &TerminalStripEditor::selectionChanged);
|
||||
}
|
||||
@@ -880,8 +888,15 @@ void TerminalStripEditor::copySelectionToClipboard()
|
||||
for (auto row = top ; row <= bottom ; ++row)
|
||||
{
|
||||
QStringList cells;
|
||||
for (auto column = left ; column <= right ; ++column) {
|
||||
cells << texts.value((qint64(row) << 32) | qint64(column));
|
||||
for (auto column = left ; column <= right ; ++column)
|
||||
{
|
||||
//A cell may hold several lines (the Target cell holds one
|
||||
//line by field): the text of the clipboard keeps one line by
|
||||
//row, the fields of that cell are joined back the way a
|
||||
//spreadsheet reads them
|
||||
QString cell_{texts.value((qint64(row) << 32) | qint64(column))};
|
||||
cell_.replace(QLatin1Char('\n'), QStringLiteral(" / "));
|
||||
cells << cell_;
|
||||
}
|
||||
lines << cells.join(QLatin1Char('\t'));
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
#include <QSpinBox>
|
||||
#include <QPainter>
|
||||
#include <QApplication>
|
||||
#include <QKeyEvent>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QFrame>
|
||||
|
||||
/**
|
||||
* Some const int who describe what a column contain
|
||||
@@ -517,8 +520,9 @@ QVariant TerminalStripModel::headerData(int section, Qt::Orientation orientation
|
||||
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");
|
||||
//Same three fields as the box drawn under the cable, one line
|
||||
//by field: only a line break separates them
|
||||
return tr("Installation, Location and Label (BMK) of the piece the cable lands on, past this strip, one line per field");
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
@@ -1128,10 +1132,59 @@ QWidget *TerminalStripModelDelegate::createEditor(QWidget *parent, const QStyleO
|
||||
|
||||
return qcb;
|
||||
}
|
||||
if (index.column() == CABLE_TARGET_CELL) {
|
||||
//The Target cell holds one line by field, so it takes a multi
|
||||
//line editor : Return writes a new line (the cell gives its
|
||||
//text back when the focus goes somewhere else), Ctrl+Return
|
||||
//hands it over at once, Escape throws the text away
|
||||
auto te = new QPlainTextEdit(parent);
|
||||
te->setObjectName(QStringLiteral("terminal_cable_target"));
|
||||
te->setFrameStyle(QFrame::NoFrame);
|
||||
te->setTabChangesFocus(true);
|
||||
te->setToolTip(tr("One line per field: Installation, Location, Label (BMK).\n"
|
||||
"Ctrl+Return gives the cell back, Escape throws the text away."));
|
||||
te->installEventFilter(const_cast<TerminalStripModelDelegate *>(this));
|
||||
|
||||
return te;
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::createEditor(parent, option, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalStripModelDelegate::eventFilter
|
||||
* The filter taken on by the Target cell editor: only the key which is
|
||||
* handled here is the one giving the text back to the table. The filter
|
||||
* of the base class is left aside for that cell on purpose, it is written
|
||||
* for one line editors and would take Return away from the text.
|
||||
* @param object the editor of the cell
|
||||
* @param event the event sent to it
|
||||
* @return true when the event is taken by this delegate
|
||||
*/
|
||||
bool TerminalStripModelDelegate::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
if (object && object->objectName() == QLatin1String("terminal_cable_target"))
|
||||
{
|
||||
if (event && event->type() == QEvent::KeyPress)
|
||||
{
|
||||
const auto key_event = static_cast<QKeyEvent *>(event);
|
||||
if ((key_event->key() == Qt::Key_Return ||
|
||||
key_event->key() == Qt::Key_Enter) &&
|
||||
key_event->modifiers().testFlag(Qt::ControlModifier))
|
||||
{
|
||||
auto editor_ = qobject_cast<QWidget *>(object);
|
||||
emit commitData(editor_);
|
||||
emit closeEditor(editor_, QAbstractItemDelegate::NoHint);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::eventFilter(object, event);
|
||||
}
|
||||
|
||||
void TerminalStripModelDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
|
||||
{
|
||||
if (index.isValid() &&
|
||||
@@ -1214,6 +1267,17 @@ void TerminalStripModelDelegate::setEditorData(QWidget *editor, const QModelInde
|
||||
return;
|
||||
}
|
||||
|
||||
if (index.isValid() &&
|
||||
editor->objectName() == QLatin1String("terminal_cable_target"))
|
||||
{
|
||||
if (auto te = dynamic_cast<QPlainTextEdit *>(editor)) {
|
||||
//The cell shows one line by field: the editor gets them
|
||||
//back exactly as they are, nothing joined, nothing split
|
||||
te->setPlainText(index.data(Qt::EditRole).toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QStyledItemDelegate::setEditorData(editor, index);
|
||||
}
|
||||
|
||||
@@ -1254,6 +1318,14 @@ void TerminalStripModelDelegate::setModelData(QWidget *editor, QAbstractItemMode
|
||||
model->setData(index, qcb->currentData(), Qt::EditRole);
|
||||
}
|
||||
}
|
||||
else if (editor->objectName() == QLatin1String("terminal_cable_target"))
|
||||
{
|
||||
if (auto te = dynamic_cast<QPlainTextEdit *>(editor)) {
|
||||
//The lines are handed over as they were written, so a
|
||||
//" / " inside a field is part of it and never a separator
|
||||
model->setData(index, te->toPlainText(), Qt::EditRole);
|
||||
}
|
||||
}
|
||||
else {
|
||||
QStyledItemDelegate::setModelData(editor, model, index);
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@ class TerminalStripModelDelegate : public QStyledItemDelegate
|
||||
QWidget *editor,
|
||||
QAbstractItemModel *model,
|
||||
const QModelIndex &index) const override;
|
||||
bool eventFilter(QObject *object, QEvent *event) override;
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
|
||||
|
||||
@@ -51,9 +51,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. 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. Two cables of one strip end
|
||||
target typed in by hand is written one line per field, Installation,
|
||||
Location, Label, the way the column shows them, and only a line
|
||||
break breaks it into fields: a "/" written inside a field is part of
|
||||
it, the box draws one line holding it. Two cables of one strip end
|
||||
close to each other, and their boxes are wider than the room between
|
||||
them: the box standing in the way of the other is set lower, its
|
||||
stub drawn longer, and the strip reserves the room for it too.
|
||||
@@ -529,12 +530,14 @@ void tst_cabletarget::realisticStyleDrawsTheCable()
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
A target typed in by hand is written one line per field, and only a
|
||||
line break breaks it into fields: the box under the cable draws one
|
||||
line per field, with no separator 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. A "/" written inside a field, an
|
||||
installation named "Betrieb 1/2", keeps its line: the box is no
|
||||
deeper than with one plain field.
|
||||
*/
|
||||
void tst_cabletarget::typedTargetIsDrawnInItsOwnLines()
|
||||
{
|
||||
@@ -604,9 +607,9 @@ void tst_cabletarget::typedTargetIsDrawnInItsOwnLines()
|
||||
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"));
|
||||
//drawing -- the fields are written one under the other, the cell
|
||||
//holding them only tells them apart by their line breaks
|
||||
type_in(QStringLiteral("Boiler room\nCabinet 3\n-K3"));
|
||||
QCOMPARE(a_->cableTarget(), (QVector<QString>{QStringLiteral("Boiler room"),
|
||||
QStringLiteral("Cabinet 3"),
|
||||
QStringLiteral("-K3")}));
|
||||
@@ -614,6 +617,16 @@ void tst_cabletarget::typedTargetIsDrawnInItsOwnLines()
|
||||
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");
|
||||
|
||||
//A slash written inside a field is part of it: the text gives
|
||||
//one single line, the box is back to the depth of one field and
|
||||
//holds the slash where it was typed
|
||||
type_in(QStringLiteral("Betrieb 1/2 / Keller"));
|
||||
QCOMPARE(a_->cableTarget(),
|
||||
QVector<QString>{QStringLiteral("Betrieb 1/2 / Keller")});
|
||||
const qreal one_slashed_field{lowest_row(render())};
|
||||
QVERIFY2(qAbs(one_slashed_field - one_line) < metrics.height() / 2,
|
||||
"a slash inside a field must not split it into lines");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -688,7 +701,7 @@ void tst_cabletarget::boxesOfTwoCablesAreSetApart()
|
||||
second_data_.m_informations.addValue(RealTerminal::cableInfoKey(),
|
||||
QStringLiteral("X98"));
|
||||
second_data_.m_informations.addValue(RealTerminal::cableTargetInfoKey(),
|
||||
QStringLiteral("Plant 9 / Cabinet 9 / -S9"));
|
||||
QStringLiteral("Plant 9\nCabinet 9\n-S9"));
|
||||
second_->setElementData(second_data_);
|
||||
QCOMPARE(b_->cableTarget(),
|
||||
(QVector<QString>{QStringLiteral("Plant 9"),
|
||||
|
||||
@@ -30,6 +30,12 @@
|
||||
#include "qetproject.h"
|
||||
|
||||
#include <QAbstractItemView>
|
||||
#include <QCoreApplication>
|
||||
#include <QKeyEvent>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QSignalSpy>
|
||||
#include <QTableView>
|
||||
#include <QTextCursor>
|
||||
|
||||
/**
|
||||
The Cable and Color / wire number columns of the terminal strip editor
|
||||
@@ -45,10 +51,11 @@
|
||||
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.
|
||||
cable works a target out again. A text typed in is written one line
|
||||
per field, Installation, Location, Label, the way the column shows
|
||||
them: only a line break breaks it into fields, so a "/" written
|
||||
inside a field (a name like "ASP/01") is part of that field and the
|
||||
box draws one line containing it.
|
||||
|
||||
fixtures/every_feature.qet has the strip X1 whose two terminals are
|
||||
wired to conductors on the folio, and no cable at all.
|
||||
@@ -358,11 +365,11 @@ private slots:
|
||||
QCOMPARE(model.data(model.index(0, TerminalStripModel::Cable))
|
||||
.toString(), QStringLiteral("15W1"));
|
||||
|
||||
//The three fields, in the order the box draws them
|
||||
//The three fields, one on its own line as 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"));
|
||||
QStringLiteral("Plant 7\nCabinet 7\n-S7"));
|
||||
QVERIFY(!(model.flags(target_cell) & Qt::ItemIsEditable));
|
||||
QCOMPARE(model.headerData(TerminalStripModel::CableTarget,
|
||||
Qt::Horizontal).toString(),
|
||||
@@ -409,7 +416,7 @@ private slots:
|
||||
QVERIFY(model->data(cell).toString().isEmpty());
|
||||
QVERIFY(model->flags(cell) & Qt::ItemIsEditable);
|
||||
|
||||
const QString typed{QStringLiteral("Boiler room / Cabinet 3 / -K3")};
|
||||
const QString typed{QStringLiteral("Boiler room\nCabinet 3\n-K3")};
|
||||
QVERIFY(model->setData(cell, typed, Qt::EditRole));
|
||||
QCOMPARE(model->data(cell, Qt::EditRole).toString(), typed);
|
||||
QCOMPARE(model->data(cell).toString(), typed);
|
||||
@@ -418,8 +425,8 @@ private slots:
|
||||
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
|
||||
//Three lines, each field on its own: the box draws them one under
|
||||
//the other, without any separator
|
||||
QCOMPARE(real_t->cableTarget(),
|
||||
(QVector<QString>{QStringLiteral("Boiler room"),
|
||||
QStringLiteral("Cabinet 3"),
|
||||
@@ -465,7 +472,7 @@ private slots:
|
||||
const QModelIndex cable_cell = model_cable.index(
|
||||
0, TerminalStripModel::CableTarget);
|
||||
QCOMPARE(model_cable.data(cable_cell).toString(),
|
||||
QStringLiteral("Plant 9 / Cabinet 9 / -S9"));
|
||||
QStringLiteral("Plant 9\nCabinet 9\n-S9"));
|
||||
QVERIFY(!(model_cable.flags(cable_cell) & Qt::ItemIsEditable));
|
||||
//And the automatic target was never written in the element
|
||||
QCOMPARE(element->elementData().m_informations
|
||||
@@ -486,10 +493,11 @@ private slots:
|
||||
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.
|
||||
// A text typed in by hand is written one line per field, and only a
|
||||
// line break breaks it into fields: the box under the cable draws
|
||||
// one line per field, exactly like a target worked out from the
|
||||
// project, while a "/" written inside a field is part of it and
|
||||
// gives one single line holding it.
|
||||
void typedTargetGivesOneLinePerField()
|
||||
{
|
||||
const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
|
||||
@@ -509,10 +517,11 @@ private slots:
|
||||
QCOMPARE(real_t->cableTarget(),
|
||||
QVector<QString>{QStringLiteral("Boiler room")});
|
||||
|
||||
//Three fields: three lines, and no slash anywhere in them
|
||||
//Three fields, written one per line: three lines, and no
|
||||
//separator anywhere in them
|
||||
typed = element->elementData();
|
||||
typed.m_informations.addValue(RealTerminal::cableTargetInfoKey(),
|
||||
QStringLiteral("Plant 9 / Cabinet 9 / -S9"));
|
||||
QStringLiteral("Plant 9\nCabinet 9\n-S9"));
|
||||
element->setElementData(typed);
|
||||
QCOMPARE(real_t->cableTarget(),
|
||||
(QVector<QString>{QStringLiteral("Plant 9"),
|
||||
@@ -524,7 +533,187 @@ private slots:
|
||||
//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"));
|
||||
.toString(), QStringLiteral("Plant 9\nCabinet 9\n-S9"));
|
||||
|
||||
//A slash inside a field, and one typed between two words of a
|
||||
//field kept in one line: both stay part of the field, the cell
|
||||
//shows them untouched and the box holds one single line each
|
||||
typed = element->elementData();
|
||||
typed.m_informations.addValue(RealTerminal::cableTargetInfoKey(),
|
||||
QStringLiteral("Betrieb 1/2"));
|
||||
element->setElementData(typed);
|
||||
QCOMPARE(real_t->cableTarget(),
|
||||
QVector<QString>{QStringLiteral("Betrieb 1/2")});
|
||||
|
||||
typed = element->elementData();
|
||||
typed.m_informations.addValue(RealTerminal::cableTargetInfoKey(),
|
||||
QStringLiteral("Betrieb 1/2 / Keller"));
|
||||
element->setElementData(typed);
|
||||
QCOMPARE(real_t->cableTarget(),
|
||||
QVector<QString>{QStringLiteral("Betrieb 1/2 / Keller")});
|
||||
TerminalStripModel slashed(project.terminalStrip().first());
|
||||
QCOMPARE(slashed.data(slashed.index(0, TerminalStripModel::CableTarget))
|
||||
.toString(), QStringLiteral("Betrieb 1/2 / Keller"));
|
||||
|
||||
//The line breaks written by hand are the fields again, whatever
|
||||
//the fields themselves contain
|
||||
typed = element->elementData();
|
||||
typed.m_informations.addValue(RealTerminal::cableTargetInfoKey(),
|
||||
QStringLiteral("Betrieb 1/2\nKeller\n-K4"));
|
||||
element->setElementData(typed);
|
||||
QCOMPARE(real_t->cableTarget(),
|
||||
(QVector<QString>{QStringLiteral("Betrieb 1/2"),
|
||||
QStringLiteral("Keller"),
|
||||
QStringLiteral("-K4")}));
|
||||
}
|
||||
|
||||
// The Target cell is edited line by line: its editor holds one line
|
||||
// per field and hands the text back exactly as the cell holds it.
|
||||
// Return writes a new line (the cell is multi line), Ctrl+Return
|
||||
// gives the cell back without waiting for the focus to go somewhere
|
||||
// else, and the row of the table is as tall as the lines the cell
|
||||
// shows, so none of them is cut off.
|
||||
void targetCellIsEditedLineByLine()
|
||||
{
|
||||
const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
|
||||
QETProject project(fixture);
|
||||
QCOMPARE(project.state(), QETProject::Ok);
|
||||
|
||||
TerminalStripEditor editor(&project);
|
||||
editor.setCurrentStrip(project.terminalStrip().first());
|
||||
QTableView *table = editor.findChild<QTableView *>(
|
||||
QStringLiteral("m_table_widget"));
|
||||
QVERIFY2(table && table->model(), "the editor has its table");
|
||||
QAbstractItemModel *model = table->model();
|
||||
QVERIFY(model->rowCount() > 1);
|
||||
const QModelIndex cell = model->index(0, TerminalStripModel::CableTarget);
|
||||
QVERIFY(model->flags(cell) & Qt::ItemIsEditable);
|
||||
|
||||
const QString typed{QStringLiteral("Betrieb 1/2\nKeller\n-K4")};
|
||||
QVERIFY(model->setData(cell, typed, Qt::EditRole));
|
||||
QCOMPARE(model->data(cell).toString(), typed);
|
||||
|
||||
//The editor of the table is the one taking a cell of several
|
||||
//lines, and one of its own does the very same thing for the
|
||||
//keys, without a view in between
|
||||
QVERIFY(qobject_cast<TerminalStripModelDelegate *>(
|
||||
table->itemDelegate()));
|
||||
TerminalStripModelDelegate delegate;
|
||||
|
||||
QStyleOptionViewItem option;
|
||||
option.rect = QRect(0, 0, qMax(
|
||||
50, table->columnWidth(TerminalStripModel::CableTarget)), 400);
|
||||
option.font = table->font();
|
||||
option.fontMetrics = QFontMetrics(option.font);
|
||||
|
||||
QWidget *cell_editor = delegate.createEditor(table, option, cell);
|
||||
QVERIFY(cell_editor);
|
||||
auto *text_edit = qobject_cast<QPlainTextEdit *>(cell_editor);
|
||||
QVERIFY2(text_edit, "the Target cell takes a multi line editor");
|
||||
QCOMPARE(text_edit->objectName(),
|
||||
QStringLiteral("terminal_cable_target"));
|
||||
|
||||
//The editor gives the lines back exactly as the cell holds
|
||||
//them: nothing joined, nothing split again
|
||||
delegate.setEditorData(cell_editor, cell);
|
||||
QCOMPARE(text_edit->toPlainText(), typed);
|
||||
delegate.setModelData(cell_editor, model, cell);
|
||||
QCOMPARE(model->data(cell).toString(), typed);
|
||||
|
||||
//Return writes a new line in the cell, and hands nothing over
|
||||
//yet: Ctrl+Return is the key giving the cell back
|
||||
QSignalSpy committed(&delegate, &TerminalStripModelDelegate::commitData);
|
||||
QSignalSpy closed(&delegate, &TerminalStripModelDelegate::closeEditor);
|
||||
text_edit->moveCursor(QTextCursor::End);
|
||||
|
||||
QKeyEvent return_key{QEvent::KeyPress, Qt::Key_Return,
|
||||
Qt::NoModifier};
|
||||
QCoreApplication::sendEvent(cell_editor, &return_key);
|
||||
QCOMPARE(text_edit->toPlainText(), typed + QLatin1Char('\n'));
|
||||
QCOMPARE(committed.count(), 0);
|
||||
QCOMPARE(closed.count(), 0);
|
||||
|
||||
QKeyEvent ctrl_return_key{QEvent::KeyPress, Qt::Key_Return,
|
||||
Qt::ControlModifier};
|
||||
QCoreApplication::sendEvent(cell_editor, &ctrl_return_key);
|
||||
QCOMPARE(committed.count(), 1);
|
||||
QCOMPARE(closed.count(), 1);
|
||||
delete cell_editor;
|
||||
}
|
||||
|
||||
// The row of the table follows the lines its Target cell holds: the
|
||||
// cell is never cut off, however many lines it takes, the row grows
|
||||
// to hold them all and shrinks back afterwards, while the rows
|
||||
// around keep the height they have always had.
|
||||
void targetRowGrowsWithTheLinesOfItsCell()
|
||||
{
|
||||
const QString fixture = QFINDTESTDATA("fixtures/every_feature.qet");
|
||||
QETProject project(fixture);
|
||||
QCOMPARE(project.state(), QETProject::Ok);
|
||||
|
||||
TerminalStripEditor editor(&project);
|
||||
editor.setCurrentStrip(project.terminalStrip().first());
|
||||
QTableView *table = editor.findChild<QTableView *>(
|
||||
QStringLiteral("m_table_widget"));
|
||||
QVERIFY2(table && table->model(), "the editor has its table");
|
||||
QAbstractItemModel *model = table->model();
|
||||
QVERIFY(model->rowCount() > 1);
|
||||
const QModelIndex cell = model->index(0, TerminalStripModel::CableTarget);
|
||||
QVERIFY(model->flags(cell) & Qt::ItemIsEditable);
|
||||
QVERIFY2(model->data(cell).toString().isEmpty(),
|
||||
"no target to start with, the row is the usual one");
|
||||
|
||||
const QModelIndex other_cell = model->index(
|
||||
1, TerminalStripModel::CableTarget);
|
||||
const int base_row = table->rowHeight(cell.row());
|
||||
const int base_other_row = table->rowHeight(other_cell.row());
|
||||
QVERIFY(base_row > 0);
|
||||
|
||||
//Three lines in the cell: the row holds them all, at the
|
||||
//font of the table -- the row was already taller than that
|
||||
//for what else the terminal draws, so it may stay as it is
|
||||
const QString typed{QStringLiteral("Betrieb 1/2\nKeller\n-K4")};
|
||||
QVERIFY(model->setData(cell, typed, Qt::EditRole));
|
||||
QCOMPARE(model->data(cell).toString(), typed);
|
||||
|
||||
const auto heightOfLines = [table](int lines_) {
|
||||
return lines_ * table->fontMetrics().height();
|
||||
};
|
||||
const int three_line_row = table->rowHeight(cell.row());
|
||||
QVERIFY2(three_line_row >= qMax(base_row, heightOfLines(3)),
|
||||
"the row must be as tall as both the lines the cell "
|
||||
"shows and what it held before, or something is cut off");
|
||||
QVERIFY2(table->rowHeight(other_cell.row()) >= base_other_row,
|
||||
"the rows around are not pushed down");
|
||||
|
||||
//From here on the rows have been worked out once: what the
|
||||
//other rows hold is the height they keep
|
||||
const int other_row = table->rowHeight(other_cell.row());
|
||||
|
||||
//Many more lines than anything else in the row: the row grows
|
||||
//to hold them, and the rows around stay where they are
|
||||
const QString many{QStringLiteral(
|
||||
"Plant 6\nCabinet 6\n-K6\nZone 6\nLevel 6\nEnd 6")};
|
||||
QVERIFY(model->setData(cell, many, Qt::EditRole));
|
||||
const int six_line_row = table->rowHeight(cell.row());
|
||||
QVERIFY2(six_line_row >= heightOfLines(6),
|
||||
"the row must be as tall as the lines the cell shows, "
|
||||
"or the fields below the first one are cut off");
|
||||
QVERIFY2(six_line_row > qMax(base_row, three_line_row),
|
||||
"a cell which took six lines must take a taller row "
|
||||
"than the one it had before");
|
||||
QVERIFY2(table->rowHeight(other_cell.row()) == other_row,
|
||||
"the rows around keep their own height");
|
||||
|
||||
//Back to one single line: the row follows again
|
||||
QVERIFY(model->setData(cell, QStringLiteral("Keller"), Qt::EditRole));
|
||||
QVERIFY2(table->rowHeight(cell.row()) < six_line_row,
|
||||
"the row follows the cell back to a single line");
|
||||
QVERIFY2(table->rowHeight(cell.row())
|
||||
<= base_row + table->fontMetrics().height(),
|
||||
"the row is back to the height it had before");
|
||||
QVERIFY2(table->rowHeight(cell.row()) >= table->fontMetrics().height(),
|
||||
"the single line left is still shown");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user