Skip to content

Refactor SimulationController to callback-based lifecycle API and move EDT UI updates into Frame#488

Merged
bedaHovorka merged 5 commits intocopilot/goal-7-simulation-speed-controlfrom
copilot/decide-thread-safety-strategy
May 6, 2026
Merged

Refactor SimulationController to callback-based lifecycle API and move EDT UI updates into Frame#488
bedaHovorka merged 5 commits intocopilot/goal-7-simulation-speed-controlfrom
copilot/decide-thread-safety-strategy

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 6, 2026

SimulationController previously mutated Swing UI state directly, relying on Frame as an implicit EDT boundary. This change applies the requested option 5: controller lifecycle is now UI-agnostic, and Frame owns EDT-marshalled UI projection.

  • Controller boundary: lifecycle logic decoupled from Swing

    • Replaced direct ControlPanel / ToolBar / StatusBar dependencies with callbacks:
      • onStateChanged(SimulationStatus)
      • onSpeedChanged(Double)
      • onCompleted()
    • Added controller-level SimulationStatus enum (RUNNING, STOPPED) for explicit state signaling.
    • Preserved existing lifecycle semantics (sync runner start, monitor-thread completion path, stale-monitor guard).
  • Frame integration: EDT-safe UI projection

    • Frame now wires controller callbacks to UI updates (ControlPanel, ToolBar, StatusBar).
    • Added a local EDT dispatch helper in Frame so callback-driven UI work is always marshalled to EDT.
    • Keeps controller reusable/testable while preserving current UI behavior.
  • Test adaptation: callback-wired headless verification

    • Updated SimulationControllerTest to construct controller via callback wiring helper instead of passing Swing components directly into the controller.
    • Tests continue asserting stop button/status/toolbar/speed-indicator behavior through callback-driven UI projection.
SimulationController(
	onStateChanged = { state -> runOnEdt { /* map RUNNING/STOPPED to UI */ } },
	onSpeedChanged = { speed -> runOnEdt { statusBar.updateSpeedIndicator(speed) } },
	onCompleted = { /* completion hook */ }
)

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • download.jetbrains.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Xmx2g -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title [WIP] Decide thread-safety strategy for SimulationController Refactor SimulationController to callback-based lifecycle API and move EDT UI updates into Frame May 6, 2026
Copilot AI requested a review from bedaHovorka May 6, 2026 04:32
@bedaHovorka bedaHovorka marked this pull request as ready for review May 6, 2026 04:53

This comment was marked as resolved.

@bedaHovorka
Copy link
Copy Markdown
Owner

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 6, 2026

@copilot apply changes based on the comments in this thread

Applied the requested fixes in commit 4b63ed5.

  • Frame now clears simulationControlPanel.runner on STOPPED callback, so natural completion detaches the finished runner.
  • SimulationController.start() now emits an initial onSpeedChanged(newRunner.speedMultiplier) after listener wiring, so preselected speed is reflected immediately.
  • Added test preselectedSpeedPropagatesOnStart in SimulationControllerTest to verify initial speed projection.

Screenshot: N/A — no visual layout/UI rendering change; this is lifecycle wiring/state synchronization behavior.

Copilot AI requested a review from bedaHovorka May 6, 2026 05:15
- StatusBar.propertyChange: dispatch label update via invokeLater when
  called from non-EDT thread (EDT violation now always reachable since
  StatusBar stays visible during simulation)
- SimulationControlPanel: add onSpeedChanged callback wired to
  SimulationController.setSpeed() so desiredSpeed stays in sync; speed
  selected via slider/preset is now honoured after stop+start
- Frame.setContext: close previous SimulationContext after new wiring to
  prevent Koin scope leak on repeated Simulation > Start... invocations
- SimulationControllerTest: replace Thread.sleep(100) with flushEDT(times=3)
  to eliminate timing-dependent flakiness in stale-monitor test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 6, 2026

@bedaHovorka bedaHovorka merged commit 87786bf into copilot/goal-7-simulation-speed-control May 6, 2026
10 checks passed
@bedaHovorka bedaHovorka deleted the copilot/decide-thread-safety-strategy branch May 6, 2026 06:37
Copilot AI added a commit that referenced this pull request May 6, 2026
…e EDT UI updates into Frame (#488)

* refactor: decouple SimulationController from Swing components

Agent-Logs-Url: https://github.com/bedaHovorka/interlockSim/sessions/01419796-a691-46e1-ae10-8c1373a9ee18

Co-authored-by: bedaHovorka <5263405+bedaHovorka@users.noreply.github.com>

* test: adapt SimulationController tests to callback-based UI wiring

Agent-Logs-Url: https://github.com/bedaHovorka/interlockSim/sessions/01419796-a691-46e1-ae10-8c1373a9ee18

Co-authored-by: bedaHovorka <5263405+bedaHovorka@users.noreply.github.com>

* fix: handle stopped runner detachment and initial speed callback

Agent-Logs-Url: https://github.com/bedaHovorka/interlockSim/sessions/e88ff78a-7a85-4ecd-9542-da0b8e356164

Co-authored-by: bedaHovorka <5263405+bedaHovorka@users.noreply.github.com>

* fix: resolve four Important issues from code review

- StatusBar.propertyChange: dispatch label update via invokeLater when
  called from non-EDT thread (EDT violation now always reachable since
  StatusBar stays visible during simulation)
- SimulationControlPanel: add onSpeedChanged callback wired to
  SimulationController.setSpeed() so desiredSpeed stays in sync; speed
  selected via slider/preset is now honoured after stop+start
- Frame.setContext: close previous SimulationContext after new wiring to
  prevent Koin scope leak on repeated Simulation > Start... invocations
- SimulationControllerTest: replace Thread.sleep(100) with flushEDT(times=3)
  to eliminate timing-dependent flakiness in stale-monitor test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: bedaHovorka <5263405+bedaHovorka@users.noreply.github.com>
Co-authored-by: Bedrich Hovorka <bedrich.hovorka@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

Decide thread-safety strategy for SimulationController (EDT enforcement)

3 participants