| 717 | } |
| 718 | |
| 719 | nlohmann::json QmitkMxNMultiWidget::SerializeLayout() const |
| 720 | { |
| 721 | // Validate layout shape: top-level layout must contain exactly one QSplitter |
| 722 | // (the canonical post-load shape). |
| 723 | auto* topLayout = this->layout(); |
| 724 | if (nullptr == topLayout || topLayout->count() == 0) |
| 725 | { |
| 726 | mitkThrow() << "SerializeLayout: editor has no top-level layout to serialize."; |
| 727 | } |
| 728 | auto* item = topLayout->itemAt(0); |
| 729 | auto* widget = (item == nullptr) ? nullptr : item->widget(); |
| 730 | auto* rootSplitter = dynamic_cast<QSplitter*>(widget); |
| 731 | if (nullptr == rootSplitter) |
| 732 | { |
| 733 | mitkThrow() << "SerializeLayout: top-level widget is not a QSplitter."; |
| 734 | } |
| 735 | |
| 736 | // Pre-walk: collect engine-internal sync-group indices encountered in the |
| 737 | // cell tree, then look up each one's bare name in the engine's group-name |
| 738 | // registry ('m_GroupNameByIndex'). The registry is populated by every |
| 739 | // 'AddSynchronizationGroup' call, so every group in the cell tree must |
| 740 | // have an entry. A missing entry here would indicate engine-state |
| 741 | // corruption and is surfaced as a throw rather than papered over. |
| 742 | std::map<GroupSyncIndexType, std::string> groupNames; |
| 743 | std::function<void(const QSplitter*)> walk = [&](const QSplitter* split) |
| 744 | { |
| 745 | for (int i = 0; i < split->count(); ++i) |
| 746 | { |
| 747 | auto* child = split->widget(i); |
| 748 | if (auto* sub = dynamic_cast<QSplitter*>(child)) |
| 749 | { |
| 750 | walk(sub); |
| 751 | } |
| 752 | else if (auto* cell = dynamic_cast<QmitkRenderWindowWidget*>(child)) |
| 753 | { |
| 754 | const auto idx = cell->GetUtilityWidget()->GetSyncGroup(); |
| 755 | if (groupNames.find(idx) == groupNames.end()) |
| 756 | { |
| 757 | const auto recorded = m_GroupNameByIndex.find(idx); |
| 758 | if (recorded == m_GroupNameByIndex.end()) |
| 759 | { |
| 760 | mitkThrow() << "SerializeLayout: cell sync group " << idx |
| 761 | << " has no entry in the group-name registry; " |
| 762 | << "engine state is corrupt."; |
| 763 | } |
| 764 | groupNames[idx] = recorded->second; |
| 765 | } |
| 766 | } |
| 767 | } |
| 768 | }; |
| 769 | walk(rootSplitter); |
| 770 | |
| 771 | // Emit the strict-mode 'groups' dict for every group referenced by a cell. |
| 772 | nlohmann::json groupsJson = nlohmann::json::object(); |
| 773 | for (const auto& [idx, name] : groupNames) |
| 774 | { |
| 775 | bool selectAll = true; |
| 776 | if (auto* connector = this->GetSyncGroupConnector(idx)) |