257 lines
10 KiB
Python
257 lines
10 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
|
|
|
from PySide6.QtCore import QEvent, QObject
|
|
from PySide6.QtWidgets import (
|
|
QApplication,
|
|
QFrame,
|
|
QHBoxLayout,
|
|
QLabel,
|
|
QLineEdit,
|
|
QPushButton,
|
|
QScrollArea,
|
|
QTableWidget,
|
|
QVBoxLayout,
|
|
QWidget,
|
|
)
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
if str(PROJECT_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(PROJECT_ROOT))
|
|
|
|
from step_editor.widgets import NoWheelComboBox
|
|
from step_editor.window_state import WindowStateMixin
|
|
|
|
|
|
class _StatusBar:
|
|
def showMessage(self, _text: str) -> None:
|
|
pass
|
|
|
|
|
|
class _PropertyCardProbe(QWidget, WindowStateMixin):
|
|
def __init__(self) -> None:
|
|
super().__init__()
|
|
self.model = object()
|
|
self.operation_in_progress = False
|
|
self.scan_in_progress = False
|
|
self.load_in_progress = False
|
|
self.property_editor_updating = False
|
|
self.property_table_expanded = False
|
|
self.property_table_collapsed_rows = 4
|
|
self.property_editor_selected_row = None
|
|
self.property_command_active_key = ""
|
|
self.property_command_buttons = {}
|
|
self.property_editor_specs = []
|
|
self.selected_kind = "face"
|
|
self.selected_part_id = None
|
|
self.selected_solid_id = None
|
|
self.selected_face_id = 0
|
|
self.selected_edge_id = None
|
|
self.current_info_values = {"area": 100.0}
|
|
self.property_table = QTableWidget(0, 5)
|
|
self.property_card_scroll = QScrollArea()
|
|
self.property_card_container = QWidget()
|
|
self.property_card_layout = QVBoxLayout(self.property_card_container)
|
|
self.property_card_scroll.setWidget(self.property_card_container)
|
|
self.property_command_summary_label = QLabel()
|
|
self.property_command_bar = QFrame()
|
|
self.property_command_layout = QHBoxLayout(self.property_command_bar)
|
|
self.apply_property_button = QPushButton()
|
|
|
|
def _selected_action_info(self) -> dict[str, object]:
|
|
return {
|
|
"area": 100.0,
|
|
"surface": "plane",
|
|
"push_pull_status": "ready",
|
|
"first_level_boundary_edge_count": 4,
|
|
"first_level_boundary_vertex_count": 4,
|
|
"first_level_adjacent_face_count": 4,
|
|
}
|
|
|
|
def _set_control_state(self, widget, enabled: bool, _enabled_tip: str, _disabled_tip: str) -> None:
|
|
widget.setEnabled(enabled)
|
|
|
|
def statusBar(self) -> _StatusBar:
|
|
return _StatusBar()
|
|
|
|
|
|
class _TopLevelPropertyLabelProbe(QObject):
|
|
def __init__(self) -> None:
|
|
super().__init__()
|
|
self.shown_labels: list[str] = []
|
|
|
|
def eventFilter(self, watched, event):
|
|
if (
|
|
event.type() == QEvent.Type.Show
|
|
and isinstance(watched, QLabel)
|
|
and watched.isWindow()
|
|
and watched.objectName().startswith("propertyCard")
|
|
):
|
|
self.shown_labels.append(f"{type(watched).__name__}:{watched.objectName()}:{watched.text()}")
|
|
return False
|
|
|
|
|
|
def _assert(condition: bool, message: str) -> None:
|
|
if not condition:
|
|
raise AssertionError(message)
|
|
|
|
|
|
def main() -> int:
|
|
app = QApplication.instance() or QApplication([])
|
|
top_level_label_probe = _TopLevelPropertyLabelProbe()
|
|
app.installEventFilter(top_level_label_probe)
|
|
probe = _PropertyCardProbe()
|
|
probe.show()
|
|
QApplication.processEvents()
|
|
probe._refresh_property_editor()
|
|
QApplication.processEvents()
|
|
_assert(
|
|
not top_level_label_probe.shown_labels,
|
|
f"property card labels were shown as transient top-level windows: {top_level_label_probe.shown_labels}",
|
|
)
|
|
|
|
actionable_labels = [str(spec.get("label", "")) for _row, spec in probe._actionable_property_rows()]
|
|
_assert("面积" in actionable_labels, "modifiable feature list did not expose the editable area row")
|
|
_assert(not probe.property_command_buttons, "legacy command buttons should not be shown in the modifiable-feature panel")
|
|
_assert(not probe.property_command_bar.isVisible(), "legacy command bar should be hidden")
|
|
_assert("可修改项" in probe.property_command_summary_label.text(), "modifiable-feature summary is missing")
|
|
|
|
rows = getattr(probe, "property_card_rows", {})
|
|
_assert(rows, "property card rows were not built")
|
|
_assert(
|
|
not any(isinstance(widgets.get("target_editor"), QLineEdit) for widgets in rows.values()),
|
|
"modifiable feature rows should be compact until the user expands one",
|
|
)
|
|
_assert(
|
|
all(str(widgets.get("status_label").text()) == "可修改" for widgets in rows.values()),
|
|
"compact modifiable rows should end with the editable status label",
|
|
)
|
|
_assert(
|
|
all(not str(widgets.get("current_value").toolTip()) for widgets in rows.values() if widgets.get("current_value") is not None),
|
|
"compact modifiable rows should not show click-triggered tooltips",
|
|
)
|
|
|
|
target_row = probe._actionable_property_rows()[0][0]
|
|
probe._select_property_card_row(target_row)
|
|
rows = getattr(probe, "property_card_rows", {})
|
|
editable_rows = [row for row, widgets in rows.items() if isinstance(widgets.get("action_button"), QPushButton)]
|
|
target_rows = [row for row, widgets in rows.items() if isinstance(widgets.get("target_editor"), QLineEdit)]
|
|
scope_rows = [row for row, widgets in rows.items() if isinstance(widgets.get("scope_combo"), NoWheelComboBox)]
|
|
|
|
_assert(editable_rows, "editable property card button is missing")
|
|
_assert(target_rows, "property card target editor is missing")
|
|
_assert(scope_rows, "property card modeling-intent combo is missing")
|
|
|
|
probe._toggle_property_card_row(target_row)
|
|
QApplication.processEvents()
|
|
rows = getattr(probe, "property_card_rows", {})
|
|
_assert(probe.property_editor_selected_row is None, "clicking an expanded row should collapse it")
|
|
_assert(
|
|
not any(isinstance(widgets.get("target_editor"), QLineEdit) for widgets in rows.values()),
|
|
"collapsed modifiable rows should return to compact display",
|
|
)
|
|
_assert(
|
|
not any(editor.isVisible() for editor in probe.property_card_container.findChildren(QLineEdit)),
|
|
"collapsed modifiable rows should not leave stale target editors visible",
|
|
)
|
|
_assert(
|
|
not any(
|
|
label.isVisible() and "建模意图:" in label.text()
|
|
for label in probe.property_card_container.findChildren(QLabel)
|
|
),
|
|
"collapsed modifiable rows should not leave stale expanded hints visible",
|
|
)
|
|
|
|
probe._select_property_card_row(target_row)
|
|
rows = getattr(probe, "property_card_rows", {})
|
|
target_rows = [row for row, widgets in rows.items() if isinstance(widgets.get("target_editor"), QLineEdit)]
|
|
_assert(target_rows, "target editor is missing after re-expanding the row")
|
|
|
|
rows[target_rows[0]]["target_editor"].setText("144")
|
|
probe._update_property_apply_state()
|
|
changed = probe._changed_property_rows()
|
|
button = rows[target_rows[0]]["action_button"]
|
|
_assert(changed, "card target edit was not detected")
|
|
_assert(bool(button.property("changed")), "card button did not enter changed state")
|
|
_assert(button.isEnabled(), "card button should be enabled for a valid changed target")
|
|
|
|
probe.toggle_property_table_expanded()
|
|
_assert(probe.property_table_expanded, "property card expand toggle failed")
|
|
_assert(len(probe.property_card_rows) > len(rows), "expanded property card list did not reveal more rows")
|
|
expanded_editor = probe.property_card_rows[target_rows[0]].get("target_editor")
|
|
_assert(isinstance(expanded_editor, QLineEdit), "expanded target editor is missing")
|
|
_assert(expanded_editor.text().strip() == "144", "target value was not preserved after card rebuild")
|
|
|
|
long_context = "已按“相邻特征”沿共享边拓扑探测当前特征及 3 个局部关联特征;关联尺寸可在同一参数表中直接修改。"
|
|
probe.property_editor_specs = [
|
|
{
|
|
"key": "feature_context_note",
|
|
"label": "关联探测",
|
|
"current_text": long_context,
|
|
"current_raw": long_context,
|
|
"target_text": "",
|
|
"editable": False,
|
|
"enabled": False,
|
|
"status_text": "说明",
|
|
"span_value_columns": True,
|
|
"pin_top": True,
|
|
},
|
|
{
|
|
"key": "associated_face_center",
|
|
"label": "相邻平面 Face 1580 · 中心",
|
|
"current_text": "(-118.585, -23.3, -269.561)",
|
|
"current_raw": "(-118.585, -23.3, -269.561)",
|
|
"target_text": "(-118.585, -23.3, -269.561)",
|
|
"editable": True,
|
|
"enabled": True,
|
|
"action": "move_face_center",
|
|
"scope_text": "局部重建",
|
|
"status_text": "可修改",
|
|
},
|
|
]
|
|
probe.property_table_expanded = True
|
|
probe.property_editor_selected_row = None
|
|
probe._rebuild_property_cards()
|
|
QApplication.processEvents()
|
|
context_value = next(
|
|
(
|
|
label
|
|
for label in probe.property_card_rows[0]["card"].findChildren(QLabel)
|
|
if label.objectName() == "propertyCardValue"
|
|
),
|
|
None,
|
|
)
|
|
_assert(isinstance(context_value, QLabel), "long associated detection note is missing")
|
|
_assert(context_value.wordWrap(), "long associated detection note should wrap in diagnostics view")
|
|
_assert("关联尺寸可在同一参数表中直接修改" in context_value.text(), "associated detection note lost its trailing text")
|
|
associated_widgets = probe.property_card_rows[1]
|
|
associated_card = associated_widgets["card"]
|
|
associated_title = next(
|
|
(
|
|
label
|
|
for label in associated_card.findChildren(QLabel)
|
|
if label.objectName() == "propertyCardTitle"
|
|
),
|
|
None,
|
|
)
|
|
_assert(isinstance(associated_title, QLabel), "long associated row title is missing")
|
|
_assert(associated_title.wordWrap(), "long associated row title should use a two-line compact layout")
|
|
_assert(associated_card.height() > 24, "long associated row should be taller than a one-line compact row")
|
|
associated_value = associated_widgets.get("current_value")
|
|
_assert(isinstance(associated_value, QLabel), "long associated row value is missing")
|
|
_assert("(-118.585" in associated_value.text(), "long associated row value was hidden by the title")
|
|
|
|
print("property card editor UI ok")
|
|
if QApplication.instance() is app:
|
|
app.quit()
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|