Extract attach-bsdl into core; add it to the wx GUI.

Second editing op into the wx frontend. Extract the logic (parse the .bsd,
apply it to the part, record bsdl_path) into core/app/edit.hpp::attach_bsdl
(Part*, path) -> {ok, error, entity, bound, unbound, ports_total}, failing
without mutation when the file can't be parsed.

The TUI `attach-bsdl` command now renders that result (output unchanged); the
wx GUI gains an Edit ▸ Attach BSDL… menu reusing PickPart() + a .bsd file
dialog. Prune the now-dead bsdl_model include from commands.cpp.

tests/test_edit.cpp: parse failure leaves the part untouched; null part. The
success path is covered by a batch run (entity + bound/total ports). 381 core
assertions green; tui + wx build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 21:18:46 +02:00
parent 7e88f82446
commit b999446151
6 changed files with 91 additions and 11 deletions

View File

@@ -33,6 +33,7 @@ enum {
ID_SAVE,
ID_EXPORT,
ID_SET_CONNECTOR_TYPE,
ID_ATTACH_BSDL,
ID_VERIFY,
ID_QUIT,
ID_ABOUT,
@@ -57,6 +58,7 @@ EssimFrame::EssimFrame(WxFrontend &fe)
auto *edit = new wxMenu;
edit->Append(ID_SET_CONNECTOR_TYPE, "Set &connector type…\tCtrl-T");
edit->Append(ID_ATTACH_BSDL, "Attach &BSDL…\tCtrl-B");
auto *sysm = new wxMenu;
sysm->Append(ID_VERIFY, "&Verify\tCtrl-K");
@@ -100,6 +102,7 @@ EssimFrame::EssimFrame(WxFrontend &fe)
Bind(wxEVT_MENU, &EssimFrame::OnSave, this, ID_SAVE);
Bind(wxEVT_MENU, &EssimFrame::OnExport, this, ID_EXPORT);
Bind(wxEVT_MENU, &EssimFrame::OnSetConnectorType, this, ID_SET_CONNECTOR_TYPE);
Bind(wxEVT_MENU, &EssimFrame::OnAttachBsdl, this, ID_ATTACH_BSDL);
Bind(wxEVT_MENU, &EssimFrame::OnVerify, this, ID_VERIFY);
Bind(wxEVT_MENU, &EssimFrame::OnQuit, this, ID_QUIT);
Bind(wxEVT_MENU, &EssimFrame::OnAbout, this, ID_ABOUT);
@@ -309,6 +312,30 @@ void EssimFrame::OnSetConnectorType(wxCommandEvent &) {
RebuildModelView();
}
void EssimFrame::OnAttachBsdl(wxCommandEvent &) {
Part *p = PickPart();
if (!p) return;
wxFileDialog dlg(this, "Attach a BSDL model", "", "",
"BSDL files (*.bsd)|*.bsd|All files (*.*)|*.*",
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (dlg.ShowModal() != wxID_OK) return;
app::AttachBsdlResult r = app::attach_bsdl(p, dlg.GetPath().utf8_string());
if (!r.ok) {
Log("attach-bsdl: " + wx(r.error));
wxMessageBox(wx(r.error), "Attach BSDL failed", wxOK | wxICON_ERROR, this);
return;
}
wxString who = (p->prnt ? wx(p->prnt->name) + "/" : wxString()) + wx(p->name);
wxString tail = r.unbound ? wxString::Format(", %d unbound", r.unbound)
: wxString();
Log(wxString::Format("%s: attached BSDL '%s' — %d/%d ports bound%s",
who, wx(r.entity), r.bound, r.ports_total, tail));
RebuildModelView();
}
void EssimFrame::OnVerify(wxCommandEvent &) {
app::VerifyReport r = app::verify(fe_.system());