Document Designer workflows and qualify the real library example

This commit is contained in:
2026-11-13 23:04:20 +01:00
parent e865d7b4df
commit 83b9e4013d
13 changed files with 960 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
# Neitzel FX Designer developer guide
Neitzel FX Designer edits ordinary FXML while understanding NeitzelLib Models, bindings and reusable Components. The standalone application and the IntelliJ editor share the same Scene Builder Kit UI. This guide describes the current implementation; the older work-package documents record implementation history and test evidence.
Start with the [Person desk quick start](quick-start.md). It uses the real `fx-example` module in NeitzelLib, rather than a separate imitation. The module shows direct and computed bindings, converters, nested/repeated Components, a Table, selection, messages and dependency injection. The optional Designer profile adds sample previews and generated metadata without putting the Designer in the application's runtime dependencies.
| I want to… | Read |
| --- | --- |
| Run the example and open it in the Designer | [Quick start](quick-start.md) |
| Start a JavaFX project and connect it to the Designer | [Projects and configuration](projects.md) |
| Understand sample Models, build snapshots and previews | [Preview and build workflow](previews.md) |
| Edit layouts, Components, bindings and collections | [Authoring reference](authoring.md) |
| Generate metadata, Java ViewModels or a starter View | [Generation](generation.md) |
| Install/use the IntelliJ editor | [IntelliJ setup](intellij.md) |
| Understand the modules or diagnose a failure | [Architecture and troubleshooting](architecture.md) |
## What is available now
- Source, Design and Split views over the same authoritative FXML document.
- Editable target-rendered Component/Repeat/Table placeholders, sizing and Component/Row navigation.
- Direct, Computed, Repeat and Table/Column inspectors, compatible-target discovery and validation.
- Reference-aware identifier rename, subtree copy/paste and deletion with one host Undo/Redo command per operation.
- Shared Problems and source highlighting; native IntelliJ Problems and supported Alt+Enter fixes.
- Independent interactive preview with fresh sample Models and explicit outdated-build/draft handling.
- Opt-in generated Model metadata, generated Java ViewModel subclasses/registries and reviewed creation of a new editable FXML View.
- A native macOS app/ZIP containing its own Java runtime and Kit, plus an IntelliJ plugin for the tested IDE build.
The tested host baseline is macOS arm64, Java 25 and JavaFX/Kit 26. The reference application uses Java 21 and JavaFX 21.0.7. IntelliJ is qualified against build **263.7307.200**. These are tested combinations, not a claim that arbitrary JavaFX, JDK, IDE or OS versions work.
The current artifacts are development snapshots: NeitzelLib `1.0-SNAPSHOT` and Designer tooling `0.1.0-SNAPSHOT`. They must be built/installed locally or obtained from an explicitly provided development build. There is no published stable runtime minimum, public Maven repository or signed/notarized release implied by these instructions.
## Scope and conventions
A **Model** is an ordinary application object. A **ViewModel** is the NeitzelLib object exposing its Attributes as observable properties. A **View** is an FXML document. A **Component** is an application node/controller with its own matching `ClassName.fxml`. A **Row Component** is the reusable row implementation selected by a NeitzelLib Table. A Designer **context** chooses a Maven application and its build/target runtimes. A preview **example** chooses a fresh Model graph and services for one View resource.
Application classes execute only in target JVMs. They do not enter the standalone or IntelliJ host classloader. Discovery uses metadata and signatures; preview executes the application and therefore requires trusted project code. Separate processes are a runtime-isolation boundary, not a security sandbox.
Configuration files and explicit command-line selection are the supported setup workflow. A graphical project/context wizard is not required. Production IntelliJ–standalone ownership handoff, broader native structural editing, signed installation/update, and other platform combinations remain follow-up work. Both hosts can already edit independently; do not infer a coordinated transfer protocol from that fact.
The [documentation validation record](documentation-validation.md) maps this guide to reference-example checks and states what was not rerun.
+71
View File
@@ -0,0 +1,71 @@
# Architecture, development and troubleshooting
The host owns editing; the target owns application execution. This separation lets a JavaFX 26 editor design applications using the qualified JavaFX 21 runtime without importing their classes or native toolkit into the host.
```mermaid
flowchart TD
IDE[IntelliJ Documents and commands] --> HOST[Host service contracts]
APP[Standalone documents and windows] --> HOST
HOST <--> UI[Shared Kit 26 UI and lexical projection]
UI --> CORE[Shared workflow and validation]
CORE --> BUILD[Isolated Maven build and capture]
BUILD --> STORE[Immutable snapshot and leases]
CORE --> WORKER[Authenticated target JVM]
STORE --> WORKER
WORKER --> LIB[NeitzelLib ViewLoader and injection]
LIB --> MODEL[Fresh sample Model and ViewModel graph]
LIB --> VIEW[Real FXML Components and bindings]
WORKER --> PIXELS[Images and sizing metadata]
PIXELS --> UI
WORKER --> PREVIEW[Independent interactive preview window]
```
## Dependency boundaries
| Module | Responsibility |
| --- | --- |
| `designer-contracts` | Configuration, metadata and wire values; no Kit/IDE/application dependency |
| `designer-core` | Build/snapshot orchestration, lexical edits, workflow and host service interfaces |
| `designer-kit-ui` | Shared Kit UI, source projection, binding panels and diagnostics |
| `designer-standalone` | Local document/window implementation and launcher |
| `designer-intellij` | Native IDE Documents, commands, navigation, Problems and toolkit gate |
| `designer-preview-api` | Small Java 21 sample provider/session contract, optionally test-scoped in applications |
| `designer-target-tools` | Java 21 worker, runtime adapter, discovery and rendering |
| `designer-maven-plugin` | Captures Maven's effective application runtime for immutable snapshots |
| `designer-model-processor` | Optional Java 21 compile-time Model metadata and ViewModel generation |
The application depends on NeitzelLib FX/core/injection and its own JavaFX runtime, not the host. Preview providers depend on the small API; annotation processing depends on the processor. The target tool JARs are supplied by the host. The shared UI uses a narrow patched Kit source with recorded provenance; see [third-party notices](../../THIRD-PARTY-NOTICES.md). The Kit patch retains its BSD-3-Clause notice. The original Designer code currently has no assigned license, as the notices state; a public repository alone does not establish reuse permission. Retain the applicable third-party licenses and notices when redistributing those components. See [module boundaries](../module-host-boundaries.md) for extension points.
## Trust and lifecycle
Transport uses authenticated loopback sessions, random tokens delivered through an owner pipe, bounded messages and correlated build/document/request identities. Application stdout/stderr are logs, not protocol framing. Worker ownership is explicit: cancellation, editor close and owner death trigger bounded shutdown. Draft overlays use private copies and cannot mutate published snapshots. Process isolation does not restrict application file/network access.
Adding a host should implement the host service interfaces and reuse core/Kit; avoid putting host APIs into shared contracts. Supporting another runtime requires a target adapter and compatibility evidence, not loading the runtime in Kit. New binding authoring should use lexical edits tied to authoritative revisions, shared target validation and host command history. Protocol/schema versions are validated explicitly; never accept unsupported data by guessing.
## Development checks
`./mvnw -B -ntp verify` validates shared modules. The [README qualification commands](../../README.md#validate-the-foundation) additionally check exact local runtime artifacts, bytecode/linkage boundaries, native standalone workflows, target fixtures, lifecycle and IntelliJ packaging. Registered IDE tests are separate. Packaging creates a macOS app image/ZIP with a bundled runtime; it is not a graphical installer, signed public release or cross-platform qualification. Follow [distribution qualification](../standalone-distribution.md).
A fresh NeitzelLib rebuild may change JAR hashes without changing source. Use the normal development launch route while developing. Requalifying the recorded runtime requires regression XML inspection, source/class/artifact comparison, relevant adapter/host tests and deliberately updated provenance together. The [runtime record](../runtime/neitzellib-baseline.md) is explicit; a checksum mismatch must not be bypassed. The current snapshot coordinates identify local artifacts, not a published corrected release.
The [real fx-example qualification](quick-start.md#verify-this-reference-integration-automatically) tests actual application resources in a copied reactor and packaged host. Existing synthetic classpath/module-path fixtures remain useful for failure cases and native IDE regression; neither replaces testing application-specific services and behavior.
## Troubleshooting
| Symptom | Check and action |
| --- | --- |
| Configuration rejected | Schema version, unknown keys, explicit context, reactor-relative module and local full-JDK mappings |
| Build fails resolving Designer snapshot | Build/install Designer tools locally first; no public snapshot repository is assumed |
| Runtime hash gate fails after library install | Distinguish developer build from recorded qualification; follow deliberate requalification, do not rewrite hashes automatically |
| Source works, designer unavailable in IntelliJ | Exact qualified SDK, `embed.scene.builder=false`, restart, no preloaded incompatible Glass |
| Blank/stale Component image | Successful Build and Refresh, matching sample descriptor, Model PI, captured resource mapping and target logs |
| New preview refused after Java/POM change | Build again, or explicitly select last successful build with its outdated state |
| Child View has no sample | Add a descriptor matching that resource and a compatible fresh provider; rebuild |
| Preview fails loading a class/property | Verify the original application first, correct FXML/imports/JPMS access, inspect target logs; no broad opens are injected |
| Converter warning | Declare/test capabilities when supported; an unverified warning is distinct from a known incompatible binding |
| Metadata stale or duplicate | Clean build after processor/Model changes; ensure one owning source compilation emits it |
| Edit or fix rejected as stale | Refresh current source/diagnostics and repeat the intended action; no old ranges are applied |
| Unsupported enum/object projection | Keep runtime initialization in application code where appropriate, or edit Source; target execution support does not imply host property-editor support |
| Preview hangs or worker dies | Review readiness timeouts and nonblocking `ready()`, target logs and native crash files; use small fresh sample services |
Implementation pages linked throughout this manual retain dated historical results. Their earlier “next” sections describe those slices, not an override of this current guide. Remaining product boundaries include graphical setup, production handoff, broader platform/IDE qualification, signed release distribution, arbitrary FXML object editors and complete native accessibility qualification.
+41
View File
@@ -0,0 +1,41 @@
# Edit Views and bindings
Both hosts use the same Kit hierarchy, canvas, inspector and Bindings panels. **Source**, **Design** and **Split** share one authoritative host document. Supported actions produce lexical replacements rather than serializing the whole FXML tree. Comments, processing instructions, quote style and unrelated declarations remain intact. Each accepted operation is one host Undo/Redo command; invalid FXML may still be saved for later repair.
## Canvas and Component properties
Select an object in the hierarchy or canvas, edit supported scalar/layout properties, or drag/resize it. Standard controls remain ordinary Kit objects; application Components use target-rendered placeholders. Explicit width/height and supported attached layout constraints are editable, including nested/anonymous Components and `fx:root` bodies. A corner resize changes both dimensions in one transaction.
Unsupported structural proposals are rejected instead of rewriting unknown XML. Use the shared Structure panel for the supported operations below and Source for everything else. Application-specific property editors, arbitrary custom object values and generic FXML language coverage are not implied by successful pixel rendering. In particular, importing an application enum solely for `<Role fx:constant="..."/>` can be misclassified by the host projection. The reference Desk populates its ChoiceBox in Controller initialization instead; ordinary NeitzelLib/FXMLLoader applications can still use enum constants.
## Discovery and authoring
Build first, declare the Model with `<?neitzel-model ...?>`, then open **Bindings**. Discovery shows Model Attributes and nested paths, selected ViewModel, target types, collection elements and compatible Component/Row types. Direction-aware checks compare what will be read and written; a plausible name is not sufficient compatibility evidence.
| Panel | Typical workflow | Reference example |
| --- | --- | --- |
| Direct bindings | Choose target control/property, Model path, `view`/`model`/`both`, optional Converter; create, update or remove | `nameField.text` ↔ `name`; age through `AgeConverter` |
| Computed bindings | Select target control/property and a public zero-argument Controller method; create, update or remove | `greetingLabel.text` from `DeskController.greeting()` |
| Repeat | Select a Pane, collection Attribute and compatible Component; edit/remove the declaration | `visits` rendered as `VisitForm` instances |
| Table / Columns | Select Table, collection Attribute and Row; author ordered Columns and inspect Row alignment | `visitTable` with `VisitRow` cells |
| Structure | Rename identifiers, copy/paste or delete a subtree with associated references | Duplicate a nested layout section without identifier collisions |
| Problems | Inspect diagnostics, navigate to source and apply an explicitly selected supported fix | Correct an invalid DirectBinding direction |
| Generate View | Review metadata-based form choices before creating new FXML | New form for Person; see [generation](generation.md) |
All three DirectBinding directions initialize the control from the Model. After initialization, `view` updates the View from the Model; `model` updates the Model from the View; `both` requests both directions. ObservableList-valued Attributes use shared list identity: list mutation does not follow these scalar direction/Converter semantics. Runtime and target compatibility remain authoritative, including conversions and generic types. Creating a declaration does not create the named Java class or method.
Converters are discovered from compiled classes without constructing them. Explicit capabilities permit direction-aware suggestions; an unannotated Converter can remain valid runtime code but produce an unverified warning. Configure and test its behavior in the application. The [Converter contract](../converter-validation.md) documents the optional capability annotation and validation details.
Computed suggestions come from the actual Controller (the Component itself for its fx:root View). Methods must be public, take no arguments and return a compatible value. Use `#method`; there are no Model path, direction, observed-path or Converter fields. Discovery does not execute methods or prove their runtime refresh behavior. The editor does not implement arbitrary expression languages. Repeat discovery requires a supported collection and compatible element Model. Repeat and Table select a direct collection Attribute/property on the current ViewModel, not DirectBinding-style dotted traversal. Table discovery additionally compares ordered Columns with the declared Row's cells. Missing or ambiguous generic/Row information is reported rather than guessed. **Open Row Component** is the explicit action for editing its FXML separately.
## Reference-safe structure changes
Renaming `fx:id` also updates supported binding targets and ordinary `$id`, simple `${id.property}`, `fx:reference` and `fx:copy` references. Copy assigns fresh descendant identifiers and carries associated bindings; paste validates them in the destination Model/Controller context. Delete removes the selected subtree and bindings targeting its descendants. These actions never refactor Java Controller fields, Model paths or separately stored Component definitions.
Paste targets supported standard Pane children (VBox, HBox, Pane, AnchorPane, StackPane, FlowPane, TilePane, GridPane). The clipboard is shared between editors in the same host process, not the OS or separate host processes. Complex expressions, scripts, includes, ambiguous imports, cross-View relative resources, document-root copy/delete and unsupported child properties require Source review. Native Kit reparent/delete/clipboard proposals are not a substitute for these shared actions. See [exact structural limits](../reference-safe-structure.md).
## Diagnostics and quick fixes
Problems are scoped to open designer documents and current build/draft evidence. Selecting a problem navigates to the affected FXML location. Source underlines follow the same ranges. IntelliJ also exposes Problems entries, native XML annotations and **Alt+Enter** actions. This is not a whole-project background inspection or precise Java-source navigation service.
Errors block new previews; warnings remain visible and permit preview. Stale diagnostic actions are withdrawn after edits or build changes. Available fixes are deliberately narrow: explicit DirectBinding direction choices, removing a later duplicate Direct/Computed target, and removal of eligible simple invalid Direct/Computed/Repeat declarations. Tables, unknown/nested payloads, warnings and declarations with `fx:id` do not get speculative deletion fixes. No action is auto-selected. Fixes preserve unrelated source and use normal Undo/Redo; see [supported fixes](../source-highlighting-fixes.md).
@@ -0,0 +1,50 @@
# Documentation and reference-example validation
This record covers the current-guide/reference-example documentation slice on 2026-11-13. It does not replace the earlier complete Designer host qualification or turn skipped human checks into passes.
## Coverage reviewed
| Developer task | Current guide | Executable reference / evidence |
| --- | --- | --- |
| Start the application, then connect the editor | [Quick start](quick-start.md) | NeitzelLib `fx-example`, existing nine application regression tests |
| Configure contexts, JDKs, Maven and sample services | [Projects](projects.md) | Checked-in library context, optional `designer-preview` profile, local settings helper |
| Understand host/target/runtime dependencies | [Architecture](architecture.md) | Module boundary checks and exact local artifact manifest remain unchanged |
| Use snapshots, draft overlays and separate previews | [Previews](previews.md) | Actual packaged host Build and Refresh, target Component pixels and fresh per-View samples |
| Edit bindings, structures, diagnostics and fixes | [Authoring](authoring.md) | Existing shared/registered-host qualification; actual example metadata and no-error binding discovery |
| Generate metadata, Java ViewModels and FXML | [Generation](generation.md) | Actual example generates Person/Address/Note metadata; existing generated-VM/FXML suites cover those features separately |
| Install and use the plugin | [IntelliJ](intellij.md) | Exact SDK/toolkit guard and build scripts reviewed against source; no new SDK/platform qualification claimed |
| Follow licensing and development boundaries | [Architecture](architecture.md) | Third-party notices, unlicensed original Designer code and local development snapshots distinguished |
The library documentation separately explains MVVM, dependency injection and every runtime binding type. The Designer guide links to those concepts rather than claiming the editor creates application semantics. Reviewed corrections include Controller-based Computed methods (no direction/path/Converter), initial DirectBinding population in every direction, shared ObservableList behavior, direct Repeat/Table collection Attributes, the non-generic runtime ViewModel base and exact descriptor keys.
## Repeatable checks
With JDK 21 in the NeitzelLib checkout:
```sh
mvn -B -ntp -pl fx-example -am -Pdesigner-preview -Dmaven.test.failure.ignore=false verify
mvn -B -ntp -pl fx-example -am -Dmaven.test.failure.ignore=false clean verify
```
The parent POM hardcodes failure-ignore; inspect all Surefire XML, not just the exit status. The profile run passed **127 tests** (core 1, injection 10, fx 105, fx-example 11). The subsequent clean ordinary build passed **125 tests** (the same runtime tests and fx-example 9), with zero failures, errors or skips in both runs. The clean ordinary output contained neither preview provider classes nor generated Designer metadata. No rebuilt library runtime artifacts were installed by these checks.
With an already qualified app image, JDK 25 and target JDK 21, run `scripts/check-library-example.py` using the [quick-start command](quick-start.md#verify-this-reference-integration-automatically). It copies the real library checkout and app, injects an external test agent only into the disposable host, and verifies:
- Build and Refresh of the real selected reactor and target pixels for `homeForm`;
- generated Person metadata with no binding errors;
- source editing, exact Undo/Redo and save through host documents;
- Address Component source navigation and duplicate-window prevention;
- per-document sample discovery and interactive loading for Desk, AddressForm, VisitForm, VisitRow and NoteForm;
- worker exit after host disposal and no new native crash report.
The test deliberately supplies known parent and child drafts together, as the production host does. An earlier test attempt omitted the saved parent's overlay when launching a child and correctly received `Build is outdated`; the test was corrected without weakening the product's current-build gate.
The documentation reviewer independently compiled and ran the library's new-project JavaFX quick start and injection-only recipe. The generated-registry snippets also compiled and ran, verifying selected generated defaults, stored-property identity and UI write-back.
The local settings helper was checked for creation and refusal to overwrite existing settings. Python syntax, guide relative links, JSON snippets and formatted Java sources were checked. `scripts/check-neitzellib-artifact.py` still passed all seven pinned artifact hashes for source `90e08b7`; no baseline hashes changed.
Local disposable evidence is printed by each invocation. The first complete actual-example pass was under `/private/var/folders/0b/lyx5t31j6ns1mf4pw7sxksj40000gn/T/designer-library-example-xh0b17ty`; library logs were `/tmp/fx-example-designer-profile.log` and `/tmp/fx-example-normal-final.log`. A final rerun after test-script formatting also passed under `/private/var/folders/0b/lyx5t31j6ns1mf4pw7sxksj40000gn/T/designer-library-example-pe02j042` (`/tmp/designer-fx-example-final.log`). These paths are evidence locations on the test workstation, not required project inputs or published artifacts.
## Qualification limits
The actual `fx-example` integration uses classpath mode and the packaged standalone macOS host. Named-module and IntelliJ behavior remains covered by the pre-existing dedicated fixtures/host suites; this documentation slice does not claim that the actual nonmodular fx-example was converted to JPMS or independently rerun in IntelliJ. No manual testing, VoiceOver review, new OS/SDK validation, signed installer or public artifact publication was performed.
+44
View File
@@ -0,0 +1,44 @@
# Metadata, Java ViewModels and new FXML forms
These are three separate operations: describe existing Java Models at compile time, optionally generate Java ViewModel classes, and interactively review a new editable FXML form. The Person desk enables the first, keeps its hand-written ViewModel, and provides examples for the third.
## Compile-time Model descriptions
Add `de.neitzel.fxdesigner:designer-model-processor:0.1.0-SNAPSHOT` to Maven compiler `annotationProcessorPaths`, preserving existing processors such as Lombok. Enable annotation processing and select Models with:
```xml
<compilerArgs>
<arg>-Adesigner.models=com.example.Person,com.example.Address</arg>
</compilerArgs>
```
The processor emits deterministic resources under `META-INF/neitzel-fx-designer/models/`. It describes eligible public read/write JavaBean Attributes, inherited properties and collection element types without constructing Models. Only types owned by the source compilation are emitted. Discovery prefers these descriptions and verifies them against compiled signatures; absent metadata uses compiled-signature fallback. Malformed, duplicate or stale metadata is an error, not silently ignored. Custom BeanInfo semantics and unsupported generics are not guessed.
Build and Refresh clean-builds the selected inputs. Outside the Designer, clean after removing/renaming properties or changing processor selections so obsolete generated files cannot survive. Generated metadata is not a runtime dependency or an alternative Model instance. [Full processor setup and format](../generated-model-metadata.md).
## Optional Java ViewModels and registry
Add the following compiler options when generated Java classes are desired:
```xml
<arg>-Adesigner.viewModels=true</arg>
<arg>-Adesigner.viewModelModels=com.example.Person,com.example.Address</arg>
<arg>-Adesigner.generatedPackage=com.example.generated</arg>
<arg>-Adesigner.viewModelDefaults=com.example.Person=com.example.CustomPersonViewModel</arg>
```
`viewModelModels` is an optional subset of `designer.models`; omission selects all. `viewModelDefaults` is optional. Generated classes in `target/generated-sources/annotations` expose typed stored properties and accessors, with nested ViewModels and observable collection values following NeitzelLib's existing identity/write-back rules. Do not edit generated Java. Put custom behavior in an ordinary subclass of the generated base and select it as the default. A pre-existing subclass of plain non-generic `ViewModel` cannot simply be registered as a generated-base subclass.
The generated registry supplies defaults without constructing registry objects. Classpath builds emit service metadata. Named modules need an explicit `provides de.neitzel.fx.view.ViewModelRegistry with ...GeneratedViewModelRegistry;` and appropriate generated-package exports/opens. A compatible explicit `@ViewModelClass` takes precedence before first creation; conflicts and incompatible defaults fail rather than splitting Model identity.
Use separate generated packages for participating modules. Unsupported generic Model declarations, reserved API collisions, unsafe narrowing and unresolved nested mappings are compile errors. Cross-module nested generation and arbitrary custom BeanInfo mappings are outside the qualified slice. Selection remains checked-in Maven configuration; there is no graphical Java-generation setup screen. See the [registry and JPMS reference](../generated-viewmodels.md) and matching NeitzelLib runtime guide.
## Review and create FXML
1. Build successfully, then choose **Bindings → Generate View**. Enter the qualified Model and optionally an existing Controller; **Load Model fields**.
2. Include fields, order them, edit labels, controls, directions and Converters. **Discover field choices** supplies compatible Components/Rows and Table information. Omitted fields need no valid configuration.
3. For nested Models choose an existing Component. For Model collections choose Repeat or Table and an existing Component/Row; Table Columns use ordered `attribute | header | optional width` lines. Open the selected source independently if it needs editing.
4. Enter a new sibling `.fxml` filename and **Review generated View**. Inspect both proposed layout and exact XML. Errors block creation; warnings remain visible.
5. **Create reviewed View** writes exactly the approved text without overwriting an existing file and opens it in the host. Subsequent edits have normal Undo/Redo. Rebuild to include the new resource; add a preview descriptor if it should run interactively.
Any relevant document, build or choice change invalidates review. File creation is not itself a text Undo command. Generation produces an independent editable document, not a managed file that later regeneration overwrites. The supported controls are TextField, Label, CheckBox, ListView, Component, Repeat and Table. Scalar defaults form a two-column GridPane; complex sections span it. A blank Controller uses the runtime's declarative fallback. The generator does not create Controllers, handlers, Components, Computed declarations or sample providers, and does not support arbitrary output directories. [Detailed creation contract](../reviewed-view-generation.md).
+45
View File
@@ -0,0 +1,45 @@
# Use the IntelliJ host
The plugin embeds the same JavaFX 26 / Scene Builder Kit 26 UI as the standalone app. IntelliJ owns Documents, saves, commands and Undo/Redo; application Models and Components remain in separate target JVMs. The currently qualified SDK is **263.7307.200 on macOS**. The runtime gate checks this exact SDK, even though plugin metadata accepts the broader 263 build family.
## Build and install locally
First build/install the shared Designer Maven modules using JDK 25 as shown in the [quick start](quick-start.md). Set `IDEA_HOME` to the IntelliJ application's `Contents` directory, then from the Designer checkout:
```sh
export JAVA_HOME=/absolute/path/to/jdk-25
export IDEA_HOME=/Applications/YourQualifiedIDE.app/Contents
./designer-intellij/gradlew -p designer-intellij --no-daemon \
-PideaHome="$IDEA_HOME" test buildPlugin verifyPluginProjectConfiguration
```
The ZIP is under `designer-intellij/build/distributions/`. Install that local ZIP through IntelliJ's plugin installation from disk, then restart. This is a development plugin; no Marketplace publication or compatibility with other IDE builds is claimed.
Before opening the designer, use IntelliJ's Registry action to disable **`embed.scene.builder`**, then restart again if necessary. Keep JavaFX/FXML language support enabled. The Designer refuses initialization if bundled embedding remains enabled, another provider remains active or incompatible Glass native libraries are already loaded. Changing the registry setting while running revokes the Designer; restart into the correct state. Do not try to load two JavaFX native toolkits in one IDE process.
## Configure the project
Use the same checked-in context and ignored `.neitzel-fx-designer/host.properties` / runtime settings as the standalone development host. The [reference helper](quick-start.md#4-create-local-runtime-and-launch-settings) configures the actual NeitzelLib checkout. Paths identify the built worker JARs; they do not select the IDE's toolkit. Build/target JDK roles remain independent of the IDE's own JVM.
Open an FXML resource and choose the **Neitzel Designer** editor. The ordinary IntelliJ XML editor stays available. Inside the shared designer, Source/Design/Split refer to its own presentation modes of that same native Document. Select **Build and Refresh** to activate a successful application snapshot; an ordinary IDE build does not perform that operation.
Use normal IntelliJ Save and Undo/Redo, the shared actions, or the Edit menu. Supported designer changes are one native command. Problems and source annotations refer to the current FXML; Alt+Enter offers the same bounded fixes as the shared panel. Opening a Component selects its existing tab or creates one, leaving the parent open. Multiple project/editor lifetimes remain separately owned, and closing one editor disposes its workers without closing other previews.
## Qualification and current boundaries
For a disposable fixture IDE that does not modify normal IDE settings:
```sh
python3 scripts/run-fixture-host.py intellij \
--java-home "$JAVA_HOME" --target-java-home /absolute/path/to/jdk-21 \
--idea-home "$IDEA_HOME"
```
After preparing the recorded qualification prerequisites, automated registered-editor checks are:
```sh
python3 scripts/check-ide-host.py --java-home "$JAVA_HOME" \
--target-java-home /absolute/path/to/jdk-21 --idea-home "$IDEA_HOME"
```
Add `--mode modulepath --repeat 3` for the repeated named-module reliability gate. These checks require a real macOS desktop session. The [reliability record](../ide-host-reliability.md) describes startup validation and native persistence fixes. Previous manually skipped scenarios remain skipped; successful automation is not a claim of human VoiceOver qualification. A production coordinated standalone handoff is not part of this plugin slice. Use independently owned documents carefully rather than assuming the earlier prototype's transfer buttons are shipped features.
+31
View File
@@ -0,0 +1,31 @@
# Builds, canvas rendering and interactive previews
**Build and Refresh** is the activation boundary between your working project and executable preview code. Ordinary IntelliJ compilation or running Maven elsewhere does not activate a new Designer snapshot.
## Snapshot lifecycle
The Designer captures the selected Maven reactor closure, copies inputs into a private build, runs the configured build and publishes immutable outputs only after success. It captures dependency identities and generated metadata together. Leases keep snapshots available while workers use them. Mutable project `target` directories are never the preview runtime.
Java/POM/configuration drafts must be saved through the explicit build workflow before compilation. FXML drafts can instead be supplied as private resource overlays for preview. Approval refers to exact revisions, so an edit after approval is not silently saved. Cancel stops the pending work. A failed or outdated build does not silently execute old classes: choose **Preview last successful** explicitly and retain its outdated indication until a successful new build.
## Editable canvas
The shared Kit draws ordinary host controls and host-owned Component placeholders. A target worker loads the real parent View with a fresh sample Model graph, measures Components, and returns pixels and sizing information. The host does not construct application Components. Target minimum/preferred sizes and explicit FXML layout settings inform the projection.
Dragging/resizing remains responsive using the previous image while a newer size is rendering. Responses are accepted only for the current document revision, requested size and session. Nested and anonymous Components, repeated Components and Row source navigation use the shared workflow; individual runtime children of a Repeat are not separate source declarations. Edit their Component definition through **Open Component** or **Open Row Component**.
The canvas is a design surface, not the running application. Use interactive preview to click application controls and exercise Model write-back.
## Interactive preview
**Interactive preview** starts a separate target JVM with its own Model/context and the current View plus known open Component drafts. It does not share the canvas Model. **Restart** creates fresh sample state; **Stop preview** closes only the owned preview. Closing its editor closes its preview while other editors remain open.
Typing later FXML drafts does not destroy interactive state immediately: the preview remains open and indicates earlier drafts. Saving an affected document restarts the preview with fresh sample state. Explicit restart also captures current drafts and clears that indication. Build changes require the normal successful-snapshot selection. Invalid bindings block new previews while leaving source editing/saving available.
An application can execute arbitrary Java in a preview. Process isolation protects host class loading; it is not an operating-system sandbox. Use deliberately harmless sample services and avoid real credentials or irreversible actions. Dispose timers, listeners and services in the sample session. Owner pipes and bounded shutdown terminate workers if the host closes or disappears; a forced kill cannot execute application cleanup guarantees.
## Navigation and limits
Opening a Component selects an existing editor for the same canonical source instead of duplicating it. The parent stays open and its layout is unchanged. Standalone uses separate windows; IntelliJ uses editor tabs. Only resolvable project resources are editable; a compiled dependency's packaged resource is not an editable project source.
The current protocol bounds drafts (128 files, 1 MiB each), frame payloads and aggregate images. Resources must map unambiguously into the captured runtime. Signed JAR overlay mutation is rejected. Large applications may need smaller examples rather than unlimited payloads. The [target session reference](../target-runtime-sessions.md) and [build reference](../build-and-refresh.md) explain the implementation and validation evidence.
+115
View File
@@ -0,0 +1,115 @@
# Connect an application
Start with an application that builds and runs without the editor. The [Person desk quick start](quick-start.md) is the complete executable example. For a new JavaFX application, use NeitzelLib's library quick start first; add Designer integration afterward. Neither a host dependency nor the Scene Builder Kit belongs on the application's runtime path.
## Shared project configuration
Commit `neitzel-fx-designer.json` at the Maven reactor root. This example selects a test-source preview provider:
```json
{
"schemaVersion": "1.0",
"contexts": {
"person-desk": {
"applicationModule": "fx-example",
"mavenProfiles": ["designer-preview"],
"launchMode": "classpath",
"buildRuntime": "java21",
"targetRuntime": "java21",
"preview": {
"sourceSet": "test",
"provider": "de.neitzel.fx.example.preview.DeskPreviewProvider",
"defaultExample": "desk"
}
}
}
}
```
A context identifies one application module, profile set, launch mode and runtime pair. Select explicitly when the file contains multiple contexts. Paths and module selections must stay inside the reactor. Unknown properties and unsupported schema versions are errors, not ignored settings. The authoritative [configuration schema](../../designer-contracts/src/main/resources/schema/configuration-1.0.json) lists limits and required fields.
| Setting | Meaning |
| --- | --- |
| `applicationModule` | Application module relative to the reactor root |
| `mavenProfiles` | Explicit Maven profiles used for this snapshot |
| `launchMode` | `classpath` or `module-path` |
| `buildRuntime`, `targetRuntime` | Logical names resolved from local settings |
| `buildJava`, `targetJava` | Optional required Java feature versions |
| `requiredCapabilities` | Explicit worker/runtime capabilities required by the context |
| `preview.sourceSet` | `test`, or `module` with a required `preview.module` |
| `preview.provider` | Qualified provider class; general example discovery is filtered to it |
| `preview.defaultExample`, `preview.examples` | Default/sample selection constraints |
| `preview.requestTimeoutSeconds` | Request timeout, 1–300 seconds |
| `preview.readinessTimeoutSeconds` | Asynchronous readiness timeout, 1–300 seconds |
| `modulePath` | Required only for module-path mode: `entryModule`, optional `addReads` and `addOpens` |
Named-module applications need their ordinary FXMLLoader/injection reflective access as well as explicit preview access. Use the real module names from your dependencies. The Designer does not automatically add broad `--add-opens` workarounds. Consult the [qualified classpath/module-path fixtures](../preview-target-fixtures.md) and existing `designer-target-tools/src/test` examples before adapting a JPMS application.
## Local runtime settings
Keep machine paths out of the committed context. An ignored `.neitzel-fx-designer/runtimes.json` maps names independently for build and target roles:
```json
{
"schemaVersion": "1.0",
"runtimes": {
"java21": {
"build": "/absolute/path/to/jdk-21",
"target": "/absolute/path/to/jdk-21"
}
}
}
```
The [local settings schema](../../designer-contracts/src/main/resources/schema/local-settings-1.0.json) is authoritative. Both entries refer to full JDK installations. The host's bundled Java runtime is a separate role. Configure local `host.properties` with `configuration`, `context`, `settings`, `maven` and `tools`; paths resolve relative to that properties file. `tools` contains the target-tools, contracts and preview-api JARs separated by the platform path separator. The [quick-start helper](quick-start.md#4-create-local-runtime-and-launch-settings) writes these files for the reference example. There is no graphical project-setup wizard.
## Typed sample providers
Add `de.neitzel.fxdesigner:designer-preview-api:0.1.0-SNAPSHOT` with test scope, preferably in an opt-in profile. A provider implements `PreviewProvider<Model, ApplicationContext>`; its public no-argument constructor and `open(exampleId)` execute only in the target JVM, after selection. `modelType()` declares the Model contract.
The following is an illustrative fragment: `Person`, `MyApplication` and `createSamplePerson()` belong to your application. Import `PreviewProvider` and `PreviewSession` from `de.neitzel.fxdesigner.preview` and `ApplicationContext` from `de.neitzel.injection`. The complete compiling providers are in NeitzelLib’s `fx-example/src/designer/java/de/neitzel/fx/example/preview`.
```java
public final class PersonPreview implements PreviewProvider<Person, ApplicationContext> {
public Class<Person> modelType() { return Person.class; }
public PreviewSession<Person, ApplicationContext> open(String id) {
if (!id.equals("person")) throw new IllegalArgumentException(id);
Person model = createSamplePerson();
ApplicationContext context = new ApplicationContext(MyApplication.class);
return new PreviewSession<>() {
public Person model() { return model; }
public ApplicationContext context() { return context; }
public void close() { /* release resources owned by this sample */ }
};
}
}
```
Use fresh Models and services on every call. Do not reuse production singletons, real accounts or external data unintentionally. `open` must clean partial allocations if it throws. `ready()` is called after View load/CSS/layout on the FX thread; return a completion stage for asynchronous work and never block that thread. `close()` runs once on FX after normal close or load/readiness failure. Forced process death cannot guarantee cooperative cleanup.
The actual example uses `DeskPreviewProvider`, `AddressPreviewProvider` and `NotePreviewProvider`. Independent Row previews prepare their parent Controller state explicitly; a Row cannot assume that a separately edited parent View has already run. Sample setup avoids the application's message popup.
Register non-executing descriptors in `META-INF/neitzel-fx-designer/examples.properties`:
```properties
format=1
count=1
example.0.id=person
example.0.label=Person sample
example.0.modelType=com.example.Person
example.0.providerClass=com.example.PersonPreview
example.0.viewResource=com/example/Person.fxml
example.0.componentPackage=com.example
```
Descriptors are discovered without constructing providers. Per-document selection matches the FXML resource, including independent Components. Inspect the reference example's real five-entry descriptor when adding another View; a new generated FXML file needs its own descriptor before it has an interactive sample.
## Declare the View's Model
Use a processing instruction, ignored by normal FXMLLoader:
```xml
<?neitzel-model com.example.Person?>
```
This is the editor's explicit Model declaration; it does not create a Model or replace the runtime Controller/ViewModel selection. Use `xmlns:fx="http://javafx.com/fxml/1"`. Discovery reads compiled signatures or optional generated metadata, follows nested Attributes and collection element types, and selects the explicit Controller/Component ViewModel contract. Rebuild after Java/configuration changes. See [generation](generation.md) for processor setup.
+116
View File
@@ -0,0 +1,116 @@
# Quick start: the Person desk
This walkthrough uses NeitzelLib's `fx-example`, package `de.neitzel.fx.example`. Keep two separate checkouts: **NeitzelLib** contains the runtime and application; **NeitzelFXDesigner** contains the editor and project-side tools. The example runs without the Designer.
## 1. Run the JavaFX application first
Use a full JDK 21 and Maven. From the NeitzelLib checkout:
```sh
export JAVA_HOME=/absolute/path/to/jdk-21
mvn -B -ntp -pl fx-example -am -Dmaven.test.failure.ignore=false install
mvn -pl fx-example javafx:run
```
**Check test reports:** NeitzelLib’s parent POM currently hardcodes `testFailureIgnore=true`; the command-line flag alone does not override it. Inspect the nonempty `target/surefire-reports/TEST-*.xml` files in core, injection, fx and fx-example and require zero failures/errors before trusting either normal or preview-profile builds. A Maven `BUILD SUCCESS` alone is insufficient.
The first command builds/installs the required reactor modules. The second launches only the application module; do not add `-am` to `javafx:run`, because the parent and library modules have no application entry point. The `Main` launcher calls `Application.launch(DeskApp.class, args)`. `DeskApp` creates the sample Person and injection context, then loads `view/Desk.fxml` through NeitzelLib's `ViewLoader`.
Edit the name and home address, add a visit or tag, and select a visit. The same visit list feeds both the Table and repeated forms. Close the application before continuing. The library's [`fx-example` README](https://gitea.neitzel.de/konrad/NeitzelLib/src/branch/main/fx-example/README.md) explains the individual controls and binding behavior.
**Artifact identity:** a fresh Maven install can produce different JAR bytes even for the same source revision. This is a normal developer build, not proof that it matches the Designer maintainer's recorded binary baseline. Do not replace the hashes in `docs/runtime/neitzellib-baseline.json` merely to make a packaging check pass. See the source-build route and qualification distinction below.
## 2. Build the project-side tools and development host
Use JDK 25 in the Designer checkout:
```sh
export JAVA_HOME=/absolute/path/to/jdk-25
./mvnw -B -ntp install
./mvnw -B -ntp -pl designer-standalone \
org.apache.maven.plugins:maven-dependency-plugin:3.6.1:build-classpath \
-DincludeScope=runtime -Dmdep.outputFile=target/runtime-classpath.txt
```
This installs the Java 21 preview API, Model processor and Maven capture plugin, as well as building the shared host and worker tools. It does not build/install an IntelliJ plugin or publish artifacts remotely. The host requires JDK 25; the project-side tools and reference application use JDK 21.
`check-bootstrap.py` and `package-standalone.py` are **maintainer qualification** commands with an exact local runtime-artifact hash gate. After rebuilding/installing NeitzelLib, use the development launcher below unless that new runtime has been explicitly requalified and its provenance recorded. The [runtime baseline record](../runtime/neitzellib-baseline.md) explains the gate. Do not describe an unqualified source build as the recorded packaged release.
## 3. Enable the example's optional preview profile
The current NeitzelLib checkout contains:
- `neitzel-fx-designer.json`: checked-in `person-desk` context selecting `fx-example` and Maven profile `designer-preview`;
- `fx-example/src/designer/java/.../preview`: typed preview providers and their tests;
- `fx-example/src/designer/resources/META-INF/neitzel-fx-designer/examples.properties`: non-executing sample descriptors;
- the optional profile in `fx-example/pom.xml`: test-scoped preview API, profile-only test sources/resources and generated Model metadata.
From NeitzelLib with JDK 21, validate that optional profile:
```sh
mvn -B -ntp -pl fx-example -am -Pdesigner-preview \
-Dmaven.test.failure.ignore=false verify
```
The profile generates Model metadata for Person, Address and Note. It does **not** replace the hand-written `PersonViewModel` with a generated default. Without the profile, the normal application has no Designer preview dependency. Use a clean build when switching profiles if you need to prove that profile-only test output and generated metadata have been removed.
## 4. Create local runtime and launch settings
From the Designer checkout:
```sh
python3 scripts/configure-library-example.py \
--library /absolute/path/to/NeitzelLib \
--target-java-home /absolute/path/to/jdk-21
```
The helper writes ignored `.neitzel-fx-designer/runtimes.json` and `host.properties` under NeitzelLib. It uses the Designer Maven wrapper as the explicit fallback and current built worker-tool JARs. It refuses to overwrite existing settings; edit existing files explicitly. Machine paths belong here, not in the shared project configuration.
Launch the development host from the Designer checkout with JDK 25:
```sh
"$JAVA_HOME/bin/java" --enable-native-access=ALL-UNNAMED \
-cp "designer-standalone/target/classes:$(cat designer-standalone/target/runtime-classpath.txt)" \
de.neitzel.fxdesigner.standalone.Launcher \
/absolute/path/to/NeitzelLib/.neitzel-fx-designer/host.properties \
/absolute/path/to/NeitzelLib/fx-example/src/main/resources/de/neitzel/fx/example/view/Desk.fxml
```
The classpath separator above is `:` for the qualified macOS setup. It is not a Windows command.
If you have an already qualified development app bundle, use its bundled JVM instead:
```sh
"/path/to/NeitzelFXDesigner.app/Contents/MacOS/NeitzelFXDesigner" \
--configuration /absolute/path/to/NeitzelLib/neitzel-fx-designer.json \
--settings /absolute/path/to/NeitzelLib/.neitzel-fx-designer/runtimes.json \
--maven /absolute/path/to/NeitzelFXDesigner/mvnw \
/absolute/path/to/NeitzelLib/fx-example/src/main/resources/de/neitzel/fx/example/view/Desk.fxml
```
The bundle obtains worker tooling from inside the app. Its JVM does not replace the configured application JDK. See [distribution instructions](../standalone-distribution.md) for app/ZIP creation and its current release boundaries.
## 5. Build, inspect and preview
1. Select **Build and Refresh**. The Designer builds an isolated copy of the selected reactor closure and publishes a successful snapshot. The original reactor's `target` directories are not the preview runtime.
2. The Desk example is selected for `Desk.fxml`. `homeForm`, the repeated visits and Table render through the target runtime. The enum ChoiceBox's runtime values are supplied in `DeskController.initialize`; the host does not instantiate application enum constants.
3. Inspect **Bindings → Direct bindings**. The `nameField.text` binding addresses `name`; the age binding uses `AgeConverter`. Unannotated Converters can be valid runtime code while carrying an unverified capability warning.
4. Open **Interactive preview**. This creates a fresh Person graph in another target process. Editing its controls changes only the preview Model, not a persistent application record or your FXML.
5. Select the home Component and **Open Component**. `AddressForm.fxml` opens in another editor. Repeating the action selects that existing editor. Its own `address` sample is available; opening `NoteForm.fxml` offers the independent `note` sample. **Open Row Component** opens `VisitRow.fxml` with its independent `row` sample.
6. Make an FXML edit, use Undo/Redo, save and reopen. Source is authoritative; the original imports, comments and unrelated formatting remain intact for supported edits.
Examples are filtered by the opened View. The parent selector does not list all five descriptors indiscriminately. Desk has `desk`; AddressForm has `address`; VisitForm has `visit`; VisitRow has `row`; NoteForm has `note`.
## Verify this reference integration automatically
After building the tools and obtaining the packaged app, run:
```sh
python3 scripts/check-library-example.py \
--library /absolute/path/to/NeitzelLib \
--app /path/to/NeitzelFXDesigner.app \
--java-home /absolute/path/to/jdk-25 \
--target-java-home /absolute/path/to/jdk-21
```
The script copies the actual NeitzelLib checkout into a temporary directory. It builds that reactor through the real Designer, checks generated Model discovery, canvas pixels, source history/save, Component navigation and all five View-specific interactive samples. The external test agent is not shipped with the app or sample. It does not install rebuilt NeitzelLib JARs into your local Maven repository.