From cd85f23dbc62e3230437fd11c16adabb45322c4e Mon Sep 17 00:00:00 2001 From: Arthur Poiret Date: Mon, 4 May 2026 23:28:07 +0200 Subject: [PATCH 1/2] fix(#454): offload blocking database and service calls from fx thread --- .../plugin/controllers/DirectoryInfoController.java | 12 ++++-------- .../plugin/controllers/PluginInfoController.java | 6 +++--- .../plugin/controllers/PluginTableController.java | 3 ++- .../plugin/controllers/PluginsController.java | 9 ++++++--- .../com/owlplug/plugin/services/PluginService.java | 6 +++--- .../com/owlplug/plugin/ui/RecoveredPluginView.java | 3 ++- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/DirectoryInfoController.java b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/DirectoryInfoController.java index 9430cf02..5602c3d9 100644 --- a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/DirectoryInfoController.java +++ b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/DirectoryInfoController.java @@ -175,19 +175,15 @@ public void setPluginDirectory(PluginDirectory pluginDirectory) { path = path.substring(0, path.length() - 1); } + directoryPluginsTab.setText("Plugins (" + pluginDirectory.getPluginList().size() + ")"); + Optional directoryStat = fileStatRepository.findByPath(path); directoryStat.ifPresent(fileStat -> directoryMetricsTab.setText( - FileUtils.humanReadableByteCount(fileStat.getLength(), true))); - - directoryPluginsTab.setText("Plugins (" + pluginDirectory.getPluginList().size() + ")"); + FileUtils.humanReadableByteCount(fileStat.getLength(), true))); List fileStats = fileStatRepository.findByParentPathOrderByLengthDesc(path); directoryFilesTab.setText("Files (" + fileStats.size() + ")"); - - ObservableList obsStats = FXCollections.observableArrayList(); - obsStats.addAll(fileStats); - directoryFilesTableView.setItems(obsStats); - + directoryFilesTableView.setItems(FXCollections.observableArrayList(fileStats)); pieChart.setData(createStatChartBuckets(fileStats)); pieChart.layout(); diff --git a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginInfoController.java b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginInfoController.java index 83e93447..19d53fe9 100644 --- a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginInfoController.java +++ b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginInfoController.java @@ -37,6 +37,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Optional; +import java.util.concurrent.CompletableFuture; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; @@ -140,8 +141,7 @@ public void initialize() { }); enableButton.setOnAction(e -> { - pluginService.enablePlugin(plugin); - setPlugin(plugin); + CompletableFuture.runAsync(() -> pluginService.enablePlugin(plugin)); }); pluginComponentListView.setCellFactory(new PluginComponentCellFactory(this.getApplicationDefaults())); @@ -149,7 +149,7 @@ public void initialize() { nativeDiscoveryToggleButton.selectedProperty().addListener((observable, oldValue, newValue) -> { if (plugin != null && plugin.getFootprint() != null) { plugin.getFootprint().setNativeDiscoveryEnabled(newValue); - pluginService.save(plugin.getFootprint()); + CompletableFuture.runAsync(() -> pluginService.save(plugin.getFootprint())); } }); diff --git a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginTableController.java b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginTableController.java index e6d58b48..a659ae39 100644 --- a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginTableController.java +++ b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginTableController.java @@ -29,6 +29,7 @@ import com.owlplug.plugin.services.PluginService; import com.owlplug.plugin.ui.PluginStateView; import java.io.File; +import java.util.concurrent.CompletableFuture; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; @@ -230,7 +231,7 @@ private ContextMenu createPluginContextMenu(Plugin plugin) { if (plugin.isDisabled()) { MenuItem enableItem = new MenuItem("Enable plugin"); enableItem.setOnAction(e -> { - pluginService.enablePlugin(plugin); + CompletableFuture.runAsync(() -> pluginService.enablePlugin(plugin)); }); menu.getItems().add(enableItem); } else { diff --git a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginsController.java b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginsController.java index d0dbbca5..3c62c1a8 100644 --- a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginsController.java +++ b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginsController.java @@ -30,6 +30,7 @@ import com.owlplug.plugin.model.Plugin; import com.owlplug.plugin.repositories.PluginRepository; import com.owlplug.plugin.services.PluginService; +import java.util.concurrent.CompletableFuture; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.MenuItem; @@ -205,9 +206,11 @@ public void initialize() { } public void displayPlugins() { - Iterable plugins = pluginRepository.findAll(); - treeViewController.setPlugins(plugins); - tableController.setPlugins(plugins); + CompletableFuture.supplyAsync(() -> pluginRepository.findAll()) + .thenAccept(plugins -> FX.run(() -> { + treeViewController.setPlugins(plugins); + tableController.setPlugins(plugins); + })); } public void selectPluginById(long id) { diff --git a/owlplug-client/src/main/java/com/owlplug/plugin/services/PluginService.java b/owlplug-client/src/main/java/com/owlplug/plugin/services/PluginService.java index 40f1f2e3..a99ce079 100644 --- a/owlplug-client/src/main/java/com/owlplug/plugin/services/PluginService.java +++ b/owlplug-client/src/main/java/com/owlplug/plugin/services/PluginService.java @@ -168,12 +168,12 @@ public void enablePlugin(Plugin plugin) { public PluginState getPluginState(Plugin plugin) { - if (!plugin.isScanComplete()) { - return PluginState.UNSTABLE; - } if (plugin.isDisabled()) { return PluginState.DISABLED; } + if (!plugin.isScanComplete()) { + return PluginState.UNSTABLE; + } if (plugin.isNativeCompatible()) { return PluginState.ACTIVE; } diff --git a/owlplug-client/src/main/java/com/owlplug/plugin/ui/RecoveredPluginView.java b/owlplug-client/src/main/java/com/owlplug/plugin/ui/RecoveredPluginView.java index 25d5548f..ac21b740 100644 --- a/owlplug-client/src/main/java/com/owlplug/plugin/ui/RecoveredPluginView.java +++ b/owlplug-client/src/main/java/com/owlplug/plugin/ui/RecoveredPluginView.java @@ -21,6 +21,7 @@ import com.owlplug.core.components.ApplicationDefaults; import com.owlplug.plugin.model.Plugin; import com.owlplug.plugin.services.PluginService; +import java.util.concurrent.CompletableFuture; import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.image.ImageView; @@ -60,7 +61,7 @@ public RecoveredPluginView(Plugin plugin, PluginService pluginService, Applicati toggleSwitch.setSelected(plugin.getFootprint().isNativeDiscoveryEnabled()); toggleSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> { plugin.getFootprint().setNativeDiscoveryEnabled(newValue); - pluginService.save(plugin.getFootprint()); + CompletableFuture.runAsync(() -> pluginService.save(plugin.getFootprint())); }); this.getChildren().add(toggleSwitch); From 5ebb20a25c2637a1927e1191ef44be54ad1e87a3 Mon Sep 17 00:00:00 2001 From: Arthur Poiret Date: Wed, 6 May 2026 23:11:58 +0200 Subject: [PATCH 2/2] refactor: use object properties for remote mutable fields on controllers --- .../controllers/ComponentInfoController.java | 18 ++++++++++---- .../controllers/DirectoryInfoController.java | 23 ++++++++++++++---- .../controllers/NodeInfoController.java | 8 +++---- .../controllers/PluginInfoController.java | 24 +++++++++++++------ .../controllers/SymlinkInfoController.java | 21 +++++++++------- .../controllers/ProjectInfoController.java | 17 +++++++++---- .../controllers/ProjectsController.java | 2 +- 7 files changed, 79 insertions(+), 34 deletions(-) diff --git a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/ComponentInfoController.java b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/ComponentInfoController.java index d1c6a1b4..244768ac 100644 --- a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/ComponentInfoController.java +++ b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/ComponentInfoController.java @@ -26,6 +26,8 @@ import com.owlplug.plugin.ui.PluginStateView; import java.util.ArrayList; import java.util.Optional; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.fxml.FXML; import javafx.scene.control.Label; import javafx.scene.effect.ColorAdjust; @@ -70,20 +72,22 @@ public class ComponentInfoController extends BaseController { private PluginStateView pluginStateView; @FXML private Label pluginReferenceLabel; - private PluginComponent currentComponent = null; - private ArrayList knownPluginImages = new ArrayList<>(); + + private final ObjectProperty componentProperty = new SimpleObjectProperty<>(); + private final ArrayList knownPluginImages = new ArrayList<>(); /** * FXML initialize method. */ @FXML public void initialize() { + componentProperty.addListener(e -> refresh()); pluginScreenshotPane.setEffect(new ColorAdjust(0, 0, -0.6, 0)); } - public void setComponent(PluginComponent component) { - this.currentComponent = component; + public void refresh() { + PluginComponent component = componentProperty.get(); pluginFormatIcon.setImage(this.getApplicationDefaults().getPluginFormatIcon(component.getPlugin().getFormat())); pluginFormatLabel.setText(component.getPlugin().getFormat().getText() + " Plugin Component"); pluginTitleLabel.setText(component.getName()); @@ -99,7 +103,7 @@ public void setComponent(PluginComponent component) { } private void setPluginImage() { - Plugin currentPlugin = currentComponent.getPlugin(); + Plugin currentPlugin = componentProperty.get().getPlugin(); String url = currentPlugin.getScreenshotUrl(); if (url == null || url.isEmpty()) { @@ -133,4 +137,8 @@ private void setPluginImage() { } } + public ObjectProperty componentProperty() { + return componentProperty; + } + } diff --git a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/DirectoryInfoController.java b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/DirectoryInfoController.java index 5602c3d9..a82bd366 100644 --- a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/DirectoryInfoController.java +++ b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/DirectoryInfoController.java @@ -35,6 +35,8 @@ import java.io.File; import java.util.List; import java.util.Optional; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -88,15 +90,17 @@ public class DirectoryInfoController extends BaseController { private TableColumn fileSizeColumn; private PieChart pieChart; - private PluginDirectory pluginDirectory; + private final ObjectProperty pluginDirectoryProperty = new SimpleObjectProperty<>(); /** * FXML Initialize. */ public void initialize() { + pluginDirectoryProperty.addListener(e -> refresh()); + openDirectoryButton.setOnAction(e -> { - PlatformUtils.openFromDesktop(pluginDirectory.getPath()); + PlatformUtils.openFromDesktop(pluginDirectoryProperty.get().getPath()); }); pluginDirectoryListView.setCellFactory(new PluginListCellFactory(this.getApplicationDefaults())); @@ -105,6 +109,8 @@ public void initialize() { Dialog dialog = this.getDialogManager().newDialog(); DialogLayout layout = new DialogLayout(); + PluginDirectory pluginDirectory = pluginDirectoryProperty.get(); + layout.setHeading(new Label("Remove directory")); layout.setBody(new Label("Do you really want to remove " + pluginDirectory.getName() + " and all of its content ? This will permanently delete the file from your hard drive.")); @@ -160,8 +166,13 @@ protected void layoutChartChildren(double top, double left, double contentWidth, } - public void setPluginDirectory(PluginDirectory pluginDirectory) { - this.pluginDirectory = pluginDirectory; + /** + * Refresh directory info. + * Most database accesses are performed in this method and expected to be run on + * UI thread to work around a bug with charts display with concurrent updates. + */ + public void refresh() { + PluginDirectory pluginDirectory = pluginDirectoryProperty.get(); directoryPathTextField.setText(pluginDirectory.getPath()); directoryNameLabel.setText(pluginDirectory.getName()); pluginDirectoryListView.getItems().setAll(pluginDirectory.getPluginList()); @@ -210,5 +221,9 @@ private ObservableList createStatChartBuckets(List file return chartData; } + public ObjectProperty pluginDirectoryProperty() { + return pluginDirectoryProperty; + } + } diff --git a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/NodeInfoController.java b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/NodeInfoController.java index cdc28e6d..834ab71c 100644 --- a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/NodeInfoController.java +++ b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/NodeInfoController.java @@ -68,19 +68,19 @@ public void setNode(Object node) { componentInfoView.setVisible(false); if (node instanceof Plugin) { - pluginInfoController.setPlugin((Plugin) node); + pluginInfoController.pluginProperty().set((Plugin) node); pluginInfoView.setVisible(true); } if (node instanceof PluginDirectory) { - directoryInfoController.setPluginDirectory((PluginDirectory) node); + directoryInfoController.pluginDirectoryProperty().set((PluginDirectory) node); directoryInfoView.setVisible(true); } if (node instanceof Symlink) { - symlinkInfoController.setSymlink((Symlink) node); + symlinkInfoController.symlinkProperty().set((Symlink) node); symlinkInfoView.setVisible(true); } if (node instanceof PluginComponent) { - componentInfoController.setComponent((PluginComponent) node); + componentInfoController.componentProperty().set((PluginComponent) node); componentInfoView.setVisible(true); } } diff --git a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginInfoController.java b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginInfoController.java index 19d53fe9..c809a095 100644 --- a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginInfoController.java +++ b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/PluginInfoController.java @@ -38,6 +38,8 @@ import java.util.ArrayList; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; @@ -108,8 +110,8 @@ public class PluginInfoController extends BaseController { @FXML private ToggleSwitch nativeDiscoveryToggleButton; - private Plugin plugin = null; - private ArrayList knownPluginImages = new ArrayList<>(); + private final ObjectProperty pluginProperty = new SimpleObjectProperty(); + private final ArrayList knownPluginImages = new ArrayList<>(); /** * FXML initialize method. @@ -117,6 +119,7 @@ public class PluginInfoController extends BaseController { @FXML public void initialize() { + pluginProperty.addListener(e -> refresh()); pluginScreenshotPane.setEffect(new ColorAdjust(0, 0, -0.6, 0)); openDirectoryButton.setGraphic(new ImageView(this.getApplicationDefaults().directoryImage)); @@ -131,7 +134,9 @@ public void initialize() { }); + disableButton.setOnAction(e -> { + Plugin plugin = pluginProperty.get(); if (this.getPreferences().getBoolean(ApplicationDefaults.SHOW_DIALOG_DISABLE_PLUGIN_KEY, true)) { this.disableController.setPlugin(plugin); this.disableController.show(); @@ -141,12 +146,14 @@ public void initialize() { }); enableButton.setOnAction(e -> { + Plugin plugin = pluginProperty.get(); CompletableFuture.runAsync(() -> pluginService.enablePlugin(plugin)); }); pluginComponentListView.setCellFactory(new PluginComponentCellFactory(this.getApplicationDefaults())); nativeDiscoveryToggleButton.selectedProperty().addListener((observable, oldValue, newValue) -> { + Plugin plugin = pluginProperty.get(); if (plugin != null && plugin.getFootprint() != null) { plugin.getFootprint().setNativeDiscoveryEnabled(newValue); CompletableFuture.runAsync(() -> pluginService.save(plugin.getFootprint())); @@ -155,13 +162,9 @@ public void initialize() { } - public void setPlugin(Plugin plugin) { - this.plugin = plugin; - refresh(); - } - public void refresh() { + Plugin plugin = pluginProperty.get(); if (plugin == null) { return; } @@ -202,6 +205,7 @@ public void refresh() { } private void setPluginImage() { + Plugin plugin = pluginProperty.get(); String url = plugin.getScreenshotUrl(); if (url == null || url.isEmpty()) { // Fallback to footprint screenshot URL @@ -235,6 +239,7 @@ private void setPluginImage() { } private void showUninstallDialog() { + Plugin plugin = pluginProperty.get(); Dialog dialog = this.getDialogManager().newDialog(); DialogLayout layout = new DialogLayout(); @@ -263,9 +268,14 @@ private void showUninstallDialog() { dialog.setContent(layout); dialog.show(); } + @EventListener private void handle(PluginRefreshEvent event) { FX.run(this::refresh); } + public ObjectProperty pluginProperty() { + return pluginProperty; + } } + diff --git a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/SymlinkInfoController.java b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/SymlinkInfoController.java index d30205e9..7635f40c 100644 --- a/owlplug-client/src/main/java/com/owlplug/plugin/controllers/SymlinkInfoController.java +++ b/owlplug-client/src/main/java/com/owlplug/plugin/controllers/SymlinkInfoController.java @@ -28,6 +28,8 @@ import com.owlplug.plugin.tasks.SymlinkRemoveTask; import com.owlplug.plugin.ui.PluginListCellFactory; import java.util.Optional; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.Label; @@ -55,21 +57,22 @@ public class SymlinkInfoController extends BaseController { @FXML private Label targetPathLabel; - private Symlink symlink; + private final ObjectProperty symlinkProperty = new SimpleObjectProperty<>(); /** * FXML Initialize. */ public void initialize() { + symlinkProperty.addListener(e -> refresh()); openLinkButton.setGraphic(new ImageView(this.getApplicationDefaults().symlinkImage)); openLinkButton.setOnAction(e -> { - PlatformUtils.openFromDesktop(symlink.getPath()); + PlatformUtils.openFromDesktop(symlinkProperty.get().getPath()); }); openTargetButton.setGraphic(new ImageView(this.getApplicationDefaults().directoryImage)); openTargetButton.setOnAction(e -> { - PlatformUtils.openFromDesktop(symlink.getTargetPath()); + PlatformUtils.openFromDesktop(symlinkProperty.get().getTargetPath()); }); pluginDirectoryListView.setCellFactory(new PluginListCellFactory(this.getApplicationDefaults())); @@ -79,7 +82,7 @@ public void initialize() { DialogLayout layout = new DialogLayout(); layout.setHeading(new Label("Remove directory")); - layout.setBody(new Label("Do you really want to delete link " + symlink.getName() + layout.setBody(new Label("Do you really want to delete link " + symlinkProperty.get().getName() + " ? Content will NOT be removed from the target folder.")); Button cancelButton = new Button("Cancel"); @@ -91,7 +94,7 @@ public void initialize() { Button removeButton = new Button("Delete"); removeButton.setOnAction(removeEvent -> { dialog.close(); - taskFactory.create(new SymlinkRemoveTask(symlink)) + taskFactory.create(new SymlinkRemoveTask(symlinkProperty.get())) .setOnSucceeded(x -> taskFactory.createPluginScanTask().scheduleNow()).schedule(); }); removeButton.getStyleClass().add("button-danger"); @@ -102,13 +105,15 @@ public void initialize() { }); } - public void setSymlink(Symlink symlink) { - this.symlink = symlink; + public void refresh() { + Symlink symlink = symlinkProperty.get(); directoryPathLabel.setText(symlink.getPath()); pluginDirectoryListView.getItems().setAll(symlink.getPluginList()); targetPathLabel.setText(Optional.ofNullable(symlink.getTargetPath()).orElse("Unknown")); - openTargetButton.setVisible(symlink.getTargetPath() != null); } + public ObjectProperty symlinkProperty() { + return symlinkProperty; + } } diff --git a/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectInfoController.java b/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectInfoController.java index ea339f5a..5282f5b3 100644 --- a/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectInfoController.java +++ b/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectInfoController.java @@ -29,6 +29,7 @@ import com.owlplug.project.model.DawProject; import com.owlplug.project.model.LookupResult; import java.io.File; +import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; @@ -89,19 +90,21 @@ public class ProjectInfoController extends BaseController { @FXML private TableColumn pluginTableLinkColumn; - private DawProject currentProject = null; + private final ObjectProperty projectProperty = new SimpleObjectProperty<>(); @FXML public void initialize() { + projectProperty.addListener(e -> refresh()); openDirectoryButton.setOnAction(e -> { File projectFile = new File(projectPathLabel.getText()); PlatformUtils.openFromDesktop(projectFile.getParentFile()); }); projectOpenButton.setOnAction(e -> { - if (currentProject != null) { - PlatformUtils.openFromDesktop(currentProject.getPath()); + DawProject project = projectProperty.get(); + if (project != null) { + PlatformUtils.openFromDesktop(project.getPath()); // Disable to prevent opening the project several times. projectOpenButton.setDisable(true); } @@ -188,8 +191,8 @@ public void updateItem(PluginFormat item, boolean empty) { } - public void setProject(DawProject project) { - this.currentProject = project; + public void refresh() { + DawProject project = projectProperty.get(); projectInfoPane.setVisible(true); projectNameLabel.setText(project.getName()); projectAppLabel.setText(project.getApplication().getName()); @@ -206,4 +209,8 @@ public void setProject(DawProject project) { } + public ObjectProperty projectProperty() { + return projectProperty; + } + } diff --git a/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectsController.java b/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectsController.java index e5f5455c..2cb8586f 100644 --- a/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectsController.java +++ b/owlplug-client/src/main/java/com/owlplug/project/controllers/ProjectsController.java @@ -79,7 +79,7 @@ public void initialize() { projectTreeView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { if (newValue instanceof TreeItem treeItem && treeItem.getValue() instanceof DawProject project) { - projectInfoController.setProject(project); + projectInfoController.projectProperty().set(project); } });