Add View > Show to hide texts, shapes, pictures by kind (bugtracker #301)

A submenu under View (Affichage > Afficher) with one tick per kind:
symbol texts, wire texts, free texts, shapes, pictures, tables and
cross-references. Unticking one hides it on every folio of every open
project; the status bar says how many kinds are hidden. Session only,
not saved in the project.

Each item is tagged with its kind by its constructor (ShownKinds::tag),
so an item created while its kind is hidden starts hidden whatever
created it. A tag rather than type(): the cross-reference under a
contact's label is a plain QGraphicsTextItem.

Items that already hide themselves (wire text switched off, one text per
potential, a cross-reference snapped elsewhere) now go through
ShownKinds::setVisible(): the kind state can only veto a show, and
apply() re-shows only what it hid itself (hidden_key), never what an
item hid. Conductor::updateTextVisibility() replaces the same visibility
rule pasted in diagrampropertiesdialog.cpp and qetscriptapi.cpp.

Hidden items are not selectable (Qt), so Select All, copy and delete
skip them. Print, PDF and image export render the scene and leave them
out; the DXF export walks items itself and skips them through
ShownKinds::isHidden(). CrossRefItem::linkedChanged() keeps following
its slaves while hidden only by kind, so its label is right when shown.

Known limitation: QGraphicsScene::itemsBoundingRect() still counts hidden
items, so Zoom to fit and borderless image export keep their space.

Verified: tst_shownkinds (12 cases, two mutation checks) and ctest 55/55;
GUI hide/show of symbol texts, wire texts (incl. one text per potential),
free texts, shapes and cross-references returns pixel-identical folios;
with nothing hidden, --export-dxf of the 24 examples is byte-identical to
master (133 files) and --export-pdf renders identically (133 pages).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
This commit is contained in:
ispyisail
2026-10-03 19:44:12 +13:00
parent 6144da0f91
commit 649f06b3b8
21 changed files with 530 additions and 24 deletions
+8
View File
@@ -139,6 +139,14 @@ add_test(NAME tst_itemgroups COMMAND tst_itemgroups)
target_include_directories(tst_itemgroups PRIVATE ${QET_DIR}/sources)
target_link_libraries(tst_itemgroups PRIVATE Qt::Test Qt::Widgets Qt::Xml)
# shownkinds.cpp keeps View > Show (bugtracker #301) apart from the item
# classes, so it is tested here on a plain scene of rectangles.
add_executable(tst_shownkinds tst_shownkinds.cpp ${QET_DIR}/sources/shownkinds.cpp)
add_test(NAME tst_shownkinds COMMAND tst_shownkinds)
set_tests_properties(tst_shownkinds PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
target_include_directories(tst_shownkinds PRIVATE ${QET_DIR}/sources)
target_link_libraries(tst_shownkinds PRIVATE Qt::Test Qt::Widgets)
# textanchor.h is header-only: the point of a text chosen by its alignment,
# shown as Position X/Y in the text properties (#1155).
add_executable(tst_textanchor tst_textanchor.cpp)
+188
View File
@@ -0,0 +1,188 @@
#include <QtTest>
#include <QGraphicsRectItem>
#include <QGraphicsScene>
#include "shownkinds.h"
class tst_shownkinds : public QObject
{
Q_OBJECT
QGraphicsScene *scene = nullptr;
QGraphicsRectItem *add(QGraphicsItem *parent = nullptr)
{
auto item = new QGraphicsRectItem(0, 0, 10, 10, parent);
item->setFlag(QGraphicsItem::ItemIsSelectable);
if (!parent) {
scene->addItem(item);
}
return item;
}
private slots:
void init()
{
scene = new QGraphicsScene;
for (int k = 0; k < ShownKinds::KindCount; ++k) {
ShownKinds::setShown(ShownKinds::Kind(k), true);
}
}
void cleanup()
{
delete scene;
scene = nullptr;
}
void hideAndShowAgain()
{
auto shape = add();
auto text = add();
ShownKinds::tag(shape, ShownKinds::Shapes);
ShownKinds::tag(text, ShownKinds::FreeTexts);
ShownKinds::setShown(ShownKinds::Shapes, false);
ShownKinds::apply(scene, ShownKinds::Shapes);
QVERIFY(!shape->isVisible());
QVERIFY(text->isVisible());
QCOMPARE(ShownKinds::hiddenCount(), 1);
ShownKinds::setShown(ShownKinds::Shapes, true);
ShownKinds::apply(scene, ShownKinds::Shapes);
QVERIFY(shape->isVisible());
QCOMPARE(ShownKinds::hiddenCount(), 0);
}
// Created while its kind is hidden: starts hidden, whatever created it.
void createdWhileHidden()
{
ShownKinds::setShown(ShownKinds::Pictures, false);
auto picture = add();
ShownKinds::tag(picture, ShownKinds::Pictures);
QVERIFY(!picture->isVisible());
}
// Untagged items (symbols, wires) are never touched.
void untaggedUntouched()
{
auto symbol = add();
auto hidden_symbol = add();
hidden_symbol->setVisible(false);
for (int k = 0; k < ShownKinds::KindCount; ++k) {
ShownKinds::setShown(ShownKinds::Kind(k), false);
ShownKinds::apply(scene, ShownKinds::Kind(k));
}
QVERIFY(symbol->isVisible());
for (int k = 0; k < ShownKinds::KindCount; ++k) {
ShownKinds::setShown(ShownKinds::Kind(k), true);
ShownKinds::apply(scene, ShownKinds::Kind(k));
}
QVERIFY(!hidden_symbol->isVisible());
}
// apply() touches only the kind it is given.
void applyOnlyThatKind()
{
auto shape = add();
ShownKinds::tag(shape, ShownKinds::Shapes);
ShownKinds::setShown(ShownKinds::Shapes, false);
ShownKinds::apply(scene, ShownKinds::Tables);
QVERIFY(shape->isVisible());
}
// An item that hid itself (a wire number switched off) stays hidden
// when its kind is hidden and shown again.
void ownHiddenStaysHidden()
{
auto number = add();
ShownKinds::tag(number, ShownKinds::WireNumbers);
ShownKinds::setVisible(number, false);
ShownKinds::setShown(ShownKinds::WireNumbers, false);
ShownKinds::apply(scene, ShownKinds::WireNumbers);
ShownKinds::setShown(ShownKinds::WireNumbers, true);
ShownKinds::apply(scene, ShownKinds::WireNumbers);
QVERIFY(!number->isVisible());
}
// An item asking to be shown while its kind is hidden stays hidden,
// and appears when the kind is shown (one text per potential moving
// to another wire, a cross-reference changing its snap).
void showVetoedThenRestored()
{
auto number = add();
ShownKinds::tag(number, ShownKinds::WireNumbers);
ShownKinds::setShown(ShownKinds::WireNumbers, false);
ShownKinds::apply(scene, ShownKinds::WireNumbers);
ShownKinds::setVisible(number, true);
QVERIFY(!number->isVisible());
ShownKinds::setShown(ShownKinds::WireNumbers, true);
ShownKinds::apply(scene, ShownKinds::WireNumbers);
QVERIFY(number->isVisible());
}
// Hidden while its kind is hidden: not shown again with the kind.
void hiddenWhileKindHidden()
{
auto number = add();
ShownKinds::tag(number, ShownKinds::WireNumbers);
ShownKinds::setShown(ShownKinds::WireNumbers, false);
ShownKinds::apply(scene, ShownKinds::WireNumbers);
ShownKinds::setVisible(number, false);
ShownKinds::setShown(ShownKinds::WireNumbers, true);
ShownKinds::apply(scene, ShownKinds::WireNumbers);
QVERIFY(!number->isVisible());
}
// A text under a hidden parent still counts as wanting to be visible.
void childOfHiddenParent()
{
auto group = add();
auto text = add(group);
ShownKinds::tag(group, ShownKinds::SymbolTexts);
ShownKinds::tag(text, ShownKinds::CrossReferences);
ShownKinds::setShown(ShownKinds::SymbolTexts, false);
ShownKinds::apply(scene, ShownKinds::SymbolTexts);
ShownKinds::setShown(ShownKinds::CrossReferences, false);
ShownKinds::apply(scene, ShownKinds::CrossReferences);
ShownKinds::setShown(ShownKinds::SymbolTexts, true);
ShownKinds::apply(scene, ShownKinds::SymbolTexts);
QVERIFY(!text->isVisible());
ShownKinds::setShown(ShownKinds::CrossReferences, true);
ShownKinds::apply(scene, ShownKinds::CrossReferences);
QVERIFY(text->isVisible());
}
// isHidden() follows the parents: a cross-reference under a symbol text.
void hiddenThroughParent()
{
auto symbol = add();
auto label = add(symbol);
auto xref = add(label);
ShownKinds::tag(label, ShownKinds::SymbolTexts);
ShownKinds::tag(xref, ShownKinds::CrossReferences);
QVERIFY(!ShownKinds::isHidden(xref));
ShownKinds::setShown(ShownKinds::SymbolTexts, false);
QVERIFY(ShownKinds::isHidden(xref));
QVERIFY(!ShownKinds::isHidden(symbol));
}
// Hidden means safe from Select All, copy and delete: Qt will not
// select it, and drops a selection it had.
void hiddenIsNotSelectable()
{
auto text = add();
ShownKinds::tag(text, ShownKinds::FreeTexts);
text->setSelected(true);
ShownKinds::setShown(ShownKinds::FreeTexts, false);
ShownKinds::apply(scene, ShownKinds::FreeTexts);
QVERIFY(!text->isSelected());
text->setSelected(true);
QVERIFY(scene->selectedItems().isEmpty());
QVERIFY(scene->items(QRectF(-5, -5, 20, 20)).isEmpty());
}
};
QTEST_MAIN(tst_shownkinds)
#include "tst_shownkinds.moc"