Skip to content

Add 'Copy as SysML' context menu to all diagram tabs - #6

Merged
Malcolmnixon merged 3 commits into
mainfrom
feature/copy-as-sysml
Jul 20, 2026
Merged

Add 'Copy as SysML' context menu to all diagram tabs#6
Malcolmnixon merged 3 commits into
mainfrom
feature/copy-as-sysml

Conversation

@Malcolmnixon

Copy link
Copy Markdown
Member

This pull request introduces a new "Copy as SysML" context menu action for all diagram tabs in the SysML2Workbench, allowing users to right-click any open diagram tab and copy its underlying SysML view definition to the OS clipboard. This feature is implemented with Avalonia's real ContextMenu and TopLevel.Clipboard APIs and is available for both predefined and custom view tabs. The implementation includes robust eligibility checks and error handling, ensures a single snippet-generation code path, and is fully covered by requirements and verification documentation. Additionally, new APIs and overloads are introduced to support the reconstruction and export of view definitions.

The most important changes are:

User-Facing Feature: Diagram Tab "Copy as SysML" Context Menu

  • All diagram tabs now support a right-click context menu with a "Copy as SysML" option, using Avalonia's ContextMenu and TopLevel.Clipboard APIs to copy the diagram's SysML view definition to the clipboard. The option is disabled if no concrete definition can be derived for the tab (e.g., unscoped predefined view or unrendered custom preview). [1]], [2]], [3]], [4]])

App Shell & View Model Enhancements

View Definition and Catalog Support

  • ViewDefinitionModel introduces an overload AddExposeTarget(ExposeTargetSelection) for direct, deduplicated addition of fully-specified expose targets, supporting arbitrary recursion kinds and bracket filters. ([docs/design/sysml2-workbench/view-builder-subsystem/view-definition-model.mdR58-R74])
  • ViewCatalogPresenter adds BuildViewDefinition, reconstructing a predefined view's concrete definition (view kind, expose members, filter, display name) from the workspace for snippet export. [1]], [2]])

Requirements and Verification

  • New requirements and test coverage are added for the context menu export feature, the shell's snippet export logic, direct expose target selection, and view definition reconstruction. [1]], [2]], [3]], [4]])
  • Verification docs now include end-to-end and unit test coverage for context menu export, eligibility checks, and error handling. [1]], [2]], [3]])

Documentation Updates

  • User guide and design docs are updated to describe the new context menu, its availability, eligibility rules, and technical integration details across the UI, app shell, and view builder/catalog subsystems. [1]], [2]], [3]], [4]], [5]], [6]], [7]], [8]])

These changes provide a unified, discoverable, and robust way for users to export SysML snippets from any diagram tab, while ensuring maintainability and testability of the new functionality.

Malcolm Nixon and others added 3 commits July 19, 2026 23:01
Every rendered diagram tab (General, Interconnection, State Transition,
Action Flow, Sequence, Grid predefined views, and custom-view-builder
preview tabs) now exposes a single shared right-click context menu item,
"Copy as SysML", that copies the whole diagram's SysML `view { ... }`
definition (view kind, expose targets, and filter expression) to the OS
clipboard. All six diagram kinds and the custom preview funnel through the
one shared DiagramDocumentView/DiagramDocumentViewModel pair, so the
context menu, its enable/disable logic, and the click handler are added in
exactly one place rather than duplicated per diagram kind.

Predefined-view tabs previously had no concrete, reusable view definition
to export - only display metadata (ViewDescriptor). ViewCatalogPresenter
gains BuildViewDefinition(workspace, viewId), which reconstructs a real
ViewDefinitionModel (kind, every expose member with its own recursion kind
and optional bracket filter, filter expression, display name) from the
loaded workspace's SysmlViewNode, using ResolvedExposeMembers rather than
the raw ExposeMembers so qualified names are fully resolved against the
workspace rather than left as raw as-written text. It returns null for an
unknown view id, an unsupported render-target kind, or a view with zero
expose members (a valid but unscoped "expose everything" view with no
finite expose list to serialize). ViewDefinitionModel gains a matching
AddExposeTarget(ExposeTargetSelection) overload so an arbitrary real expose
member can be reconstructed in one call, deduplicated by the exact
(qualified name, recursion kind) pair, rather than needing the multi-call
add-then-retarget-then-filter sequence the existing string overload would
otherwise require.

WorkbenchTab now carries an optional SourceDefinition (the concrete
ViewDefinitionModel a tab was rendered from, populated by SelectPredefinedView
via BuildViewDefinition or carried through from PreviewCustomView).
MainWindowShell.CanExportTabAsSysml/ExportTabAsSysmlSnippet expose whether a
tab is exportable and generate its snippet text via the existing
SysmlSnippetGenerator - the same generator the custom view builder's own
export button already used - so there remains exactly one snippet-generation
code path. The no-derivable-definition edge case (unknown tab, or a
predefined view with no expose members) is handled gracefully: the context
menu item is disabled and the reason is logged at Info level via the
existing RollingFileLogger, never thrown.

The actual clipboard write goes through a new IClipboardService seam
(AvaloniaClipboardService wraps TopLevel.GetTopLevel(anchor)?.Clipboard,
resolved lazily per call rather than cached at construction), mirroring the
existing IUiDispatcher seam pattern, so DiagramDocumentViewModel.CopyAsSysmlAsync
can be unit tested with a fake clipboard instead of a live UI.
DiagramDocumentView's code-behind constructs the real clipboard service once
it has a view model and assigns it to the view model's ClipboardService
property.

Companion updates: reqstream requirements and test-name traceability for
MainWindowShell, ViewCatalogPresenter, ViewDefinitionModel, and the OTS
Avalonia unit; design docs for the same units plus the "Diagram Document
Tabs" section of docs/design/ots/dock.md, which documents the new context
menu, its enable/disable behavior, and the SourceDefinition data flow; and
matching verification-doc scenario narratives for every new test. New
tests: ViewDefinitionModelTests (AddExposeTarget selection overload, add and
null-argument cases), ViewCatalogPresenterTests (BuildViewDefinition kind/
expose/filter resolution, unknown view id, zero-expose-members cases),
MainWindowShellTests (CanExportTabAsSysml/ExportTabAsSysmlSnippet across
predefined, custom-preview, unknown, and unscoped-view cases),
DiagramDocumentViewModelTests (CopyAsSysmlAsync with a fake clipboard
service across exportable, non-exportable, and no-clipboard-assigned
cases), and one new OTS headless Avalonia end-to-end test,
DiagramContextMenu_CopyAsSysml_CopiesSnippetToClipboard, which drives the
real context menu and menu item through the actual visual tree and reads
the result back from the headless platform's real TopLevel.Clipboard.

Full dotnet build (0 warnings/errors), dotnet test (153 + 19 passing),
dotnet sysml2tools lint, dotnet reqstream --lint, and a local reproduction
of CI's dotnet reqstream --enforce (clean aside from the three pre-existing,
unrelated per-OS platform requirements that are only satisfiable on their
respective CI runner) all pass. fix.ps1 and lint.ps1 both run clean.
The right-click 'Copy as SysML' context menu (added in 62a94d5) applies
to every open diagram tab - all predefined view kinds and custom-view
previews - via the shared DiagramDocumentView, not just the Custom View
Builder panel's own button. The user guide only documented the panel
button, leaving the broader context-menu capability undiscoverable.

Add a paragraph at the end of 'Browsing Predefined Views' describing the
per-tab context menu and its disabled state when no concrete view
definition can be derived, and a one-line cross-reference at the end of
step 7 in 'Building a Custom View' pointing readers to it.
Border.ContextMenu consumes the right-button pointer release before the
diagram's own PointerReleased handler runs, so panning (started for any
button) was never stopped, leaving the diagram permanently dragging on
subsequent mouse moves. Pan gestures now only start on the left button;
right-click is reserved exclusively for the context menu. A
PointerCaptureLost handler also resets the panning flag defensively.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Malcolmnixon
Malcolmnixon merged commit 443877a into main Jul 20, 2026
6 checks passed
@Malcolmnixon
Malcolmnixon deleted the feature/copy-as-sysml branch July 20, 2026 03:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant