Project View ↔ NewRawScan Integration
Overview
The Project View is updated reactively when new raw scans are loaded into the
project model. This interaction is mediated through an event-driven architecture
centered on the RawScanAppendEvent.
The flow is:
Backend loads raw scans
Model emits
RawScanAppendEventPresenter listens and transforms the event
View updates the Project Tree
This decouples data ingestion from UI concerns.
Architecture
The interaction spans three layers:
Model: Owns raw scan data and emits events
Presenter: Subscribes to events and updates the view
View (Project Tree): Displays scans hierarchically
Data Flow
Loading raw scans triggers the following sequence:
FileMenuPresenter
↓
TaviProjectModel.load_raw_scan_from_folder
↓
RawScanLoadController.load_folder
↓
(returns List[RawScan])
↓
TaviProjectModel
- stores scans in TaviData
- emits RawScanAppendEvent per scan
↓
EventBroker
↓
LoadRawScanPresenter.update_treeview_data
↓
ProjectView.add_raw_scan
↓
TreeViewWidget.add_raw_scan
Model Responsibilities
The TaviProjectModel is responsible for:
Persisting scans in
TaviData.raw_scansEmitting a
RawScanAppendEventper scan
Each event contains:
uuid: Unique identifierfriendly_name: Display namefriendly_path: Logical grouping path
Implementation detail:
Events are emitted after scans are stored
One event is emitted per scan (not batched)
Event Definition
RawScanAppendEvent is a typed model event:
class RawScanAppendEvent(Event):
uuid: UUID
friendly_name: str
friendly_path: str
This event is the sole contract between backend data loading and UI updates.
Presenter Responsibilities
The LoadRawScanPresenter:
Registers with the
EventBrokerforRawScanAppendEventMaintains a local
inventoryof loaded scansTranslates events into view updates
On event:
self._view.add_raw_scan(event.uuid,
event.friendly_name,
event.friendly_path)
The presenter does no transformation beyond forwarding metadata.
View Responsibilities (Project Tree)
The Project View is implemented via TreeViewWidget and is responsible for:
Maintaining hierarchical structure via
path_mapTracking nodes via
uuid_mapRendering scan entries under a
/Rawroot
Adding a Scan
All raw scans are inserted under a fixed root:
/Raw/<friendly_path>/<friendly_name>
The method:
add_raw_scan(uuid, name, path)
normalizes input by:
Stripping leading
/frompathPrefixing with
/Raw
Tree Construction
Tree nodes are created incrementally:
Each path segment becomes a node if not already present
Leaf nodes represent scans
Duplicate names are allowed (UUID enforces uniqueness)
Key constraints:
Duplicate UUID insertion raises an error
Path structure is cached in
path_mapfor O(1) lookup
Example
Given:
friendly_name = "scan1"friendly_path = "/experiment/runA"
The resulting tree:
/Raw
└── experiment
└── runA
└── scan1
Key Design Decisions
Event-driven UI updates
The UI does not poll or directly query the model. Instead:
The model pushes updates via events
The presenter reacts asynchronously
This ensures:
Loose coupling
Easier extensibility (e.g., progress events, deletion events)
Per-scan event emission
Each scan generates its own event rather than batching.
Pros:
Simpler UI updates
Incremental rendering possible
Cons:
Higher event volume for large loads
Strict UUID ownership
The view enforces uniqueness via uuid_map:
Prevents duplicate insertion bugs
Enables future direct lookup (e.g., selection sync)
Summary
The Project View does not directly depend on the loading mechanism. Instead, it
subscribes to RawScanAppendEvent and incrementally builds a hierarchical
representation of scans under the /Raw namespace.
This pattern cleanly separates:
Data ingestion (controller + model)
Event propagation (event broker)
Presentation logic (presenter)
Rendering (view)