diff --git a/gui-local/src/main/java/place/sita/labelle/gui/local/StageConfiguration.java b/gui-local/src/main/java/place/sita/labelle/gui/local/StageConfiguration.java index 2b8ac8e..1f087dc 100644 --- a/gui-local/src/main/java/place/sita/labelle/gui/local/StageConfiguration.java +++ b/gui-local/src/main/java/place/sita/labelle/gui/local/StageConfiguration.java @@ -18,6 +18,7 @@ import place.sita.modulefx.FxSceneBuilderProcessors; import place.sita.modulefx.threading.ThreadingSupportSupplier; import place.sita.labelle.gui.local.menu.Menu; +import place.sita.modulefx.vtg.VirtualTreeGroup; import java.util.*; @@ -54,10 +55,13 @@ public UnstableSceneReporter configureStage(Stage stage, StageType stageType) { FxSceneBuilderProcessors processors = new FxSceneBuilderProcessors(childrenFactory, unstableSceneReporter); UUID loadId = UUID.randomUUID(); unstableSceneReporter.markUnstable(loadId, "Loading new stage"); + + VirtualTreeGroup virtualTreeGroup = new VirtualTreeGroup(); + Menu menu = applicationContext.getBean(Menu.class); Node node; try { - node = FxControllerLoader.setupForController(menu, "/fx/mainmenu.fxml", processors); + node = FxControllerLoader.setupForController(menu, "/fx/mainmenu.fxml", processors, virtualTreeGroup); } finally { unstableSceneReporter.markStable(loadId); } diff --git a/module-fx/src/main/java/place/sita/modulefx/FxControllerLoader.java b/module-fx/src/main/java/place/sita/modulefx/FxControllerLoader.java index 6012c91..811b460 100644 --- a/module-fx/src/main/java/place/sita/modulefx/FxControllerLoader.java +++ b/module-fx/src/main/java/place/sita/modulefx/FxControllerLoader.java @@ -1,14 +1,16 @@ package place.sita.modulefx; import javafx.scene.Node; +import place.sita.modulefx.vtg.VirtualTreeGroup; public class FxControllerLoader { - public static Node setupForController(Object controller, String resource, FxSceneBuilderProcessors processors) { - return internalSetupForController(controller, null, null, resource, processors); + public static Node setupForController(Object controller, String resource, FxSceneBuilderProcessors processors, VirtualTreeGroup virtualTreeGroup) { + return internalSetupForController(controller, null, null, resource, processors, virtualTreeGroup); } - private static Node internalSetupForController(Object controller, Object parent, Node parentNode, String resource, FxSceneBuilderProcessors fxSceneBuilderProcessors) { + + private static Node internalSetupForController(Object controller, Object parent, Node parentNode, String resource, FxSceneBuilderProcessors fxSceneBuilderProcessors, VirtualTreeGroup virtualTreeGroup) { Node results = FxSceneBuilder.loadNodeForController(controller, resource); fxSceneBuilderProcessors.runAll(new FxSetupContext() { @@ -38,13 +40,18 @@ public FxSceneBuilderProcessors processors() { } @Override - public Node setupForController(Object bean, String resource, FxSetupContext context) { - return internalSetupForController(bean, controller, results, resource, context.processors()); + public Node setupForController(Object bean, String resource, FxSetupContext context, VirtualTreeGroup virtualTreeGroup) { + return internalSetupForController(bean, controller, results, resource, context.processors(), virtualTreeGroup); + } + + @Override + public Node setupForController(Object bean, String resource, FxSetupContext context, Object parent, Node parentNode, VirtualTreeGroup virtualTreeGroup) { + return internalSetupForController(bean, parent, parentNode, resource, context.processors(), virtualTreeGroup); } @Override - public Node setupForController(Object bean, String resource, FxSetupContext context, Object parent, Node parentNode) { - return internalSetupForController(bean, parent, parentNode, resource, context.processors()); + public VirtualTreeGroup virtualTreeGroup() { + return null; } }); diff --git a/module-fx/src/main/java/place/sita/modulefx/FxSceneBuilderProcessors.java b/module-fx/src/main/java/place/sita/modulefx/FxSceneBuilderProcessors.java index 66d0f09..03ff87f 100644 --- a/module-fx/src/main/java/place/sita/modulefx/FxSceneBuilderProcessors.java +++ b/module-fx/src/main/java/place/sita/modulefx/FxSceneBuilderProcessors.java @@ -16,6 +16,7 @@ public FxSceneBuilderProcessors(ChildrenFactory childrenFactory, UnstableSceneRe processors.add(new InjectChildrenProcessor(childrenFactory)); processors.add(new InjectTabsProcessor(childrenFactory, unstableSceneReporter)); processors.add(new PostFxInjectProcessor()); + processors.add(new MessageBusSupportProcessor()); } public void add(FxSceneBuilderProcessor processor) { diff --git a/module-fx/src/main/java/place/sita/modulefx/FxSetupContext.java b/module-fx/src/main/java/place/sita/modulefx/FxSetupContext.java index a27c2f9..48bf5be 100644 --- a/module-fx/src/main/java/place/sita/modulefx/FxSetupContext.java +++ b/module-fx/src/main/java/place/sita/modulefx/FxSetupContext.java @@ -1,6 +1,7 @@ package place.sita.modulefx; import javafx.scene.Node; +import place.sita.modulefx.vtg.VirtualTreeGroup; public interface FxSetupContext { @@ -15,7 +16,9 @@ public interface FxSetupContext { FxSceneBuilderProcessors processors(); @Deprecated - Node setupForController(Object bean, String resource, FxSetupContext context); + Node setupForController(Object bean, String resource, FxSetupContext context, VirtualTreeGroup virtualTreeGroup); - Node setupForController(Object bean, String resource, FxSetupContext context, Object parent, Node parentNode); + Node setupForController(Object bean, String resource, FxSetupContext context, Object parent, Node parentNode, VirtualTreeGroup virtualTreeGroup); + + VirtualTreeGroup virtualTreeGroup(); } diff --git a/module-fx/src/main/java/place/sita/modulefx/annotations/FxMessageListener.java b/module-fx/src/main/java/place/sita/modulefx/annotations/FxMessageListener.java new file mode 100644 index 0000000..dfa4b88 --- /dev/null +++ b/module-fx/src/main/java/place/sita/modulefx/annotations/FxMessageListener.java @@ -0,0 +1,9 @@ +package place.sita.modulefx.annotations; + +import java.lang.annotation.*; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface FxMessageListener { +} diff --git a/module-fx/src/main/java/place/sita/modulefx/annotations/ModuleFx.java b/module-fx/src/main/java/place/sita/modulefx/annotations/ModuleFx.java new file mode 100644 index 0000000..3390bdf --- /dev/null +++ b/module-fx/src/main/java/place/sita/modulefx/annotations/ModuleFx.java @@ -0,0 +1,12 @@ +package place.sita.modulefx.annotations; + +import java.lang.annotation.*; + +/** + * Generic annotation to autowire a ModuleFx utility. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ModuleFx { +} diff --git a/module-fx/src/main/java/place/sita/modulefx/messagebus/MessageSender.java b/module-fx/src/main/java/place/sita/modulefx/messagebus/MessageSender.java new file mode 100644 index 0000000..0f1ba90 --- /dev/null +++ b/module-fx/src/main/java/place/sita/modulefx/messagebus/MessageSender.java @@ -0,0 +1,10 @@ +package place.sita.modulefx.messagebus; + +/** + * See {@link place.sita.modulefx.annotations.ModuleFx}. + */ +public interface MessageSender { + + void send(Object message); + +} diff --git a/module-fx/src/main/java/place/sita/modulefx/processors/InjectChildrenProcessor.java b/module-fx/src/main/java/place/sita/modulefx/processors/InjectChildrenProcessor.java index 9574aa2..0eaf017 100644 --- a/module-fx/src/main/java/place/sita/modulefx/processors/InjectChildrenProcessor.java +++ b/module-fx/src/main/java/place/sita/modulefx/processors/InjectChildrenProcessor.java @@ -8,6 +8,7 @@ import place.sita.modulefx.FxSetupContext; import place.sita.modulefx.annotations.FxChild; import place.sita.modulefx.annotations.FxNode; +import place.sita.modulefx.vtg.VirtualTreeGroup; import java.lang.reflect.Field; import java.util.Arrays; @@ -41,7 +42,9 @@ private void injectChild(Object parentController, Field fieldWithAnnotation, Cla String resource = classType.getAnnotation(FxNode.class).resourceFile(); Object bean = childrenFactory.create(classType); - Node node = context.setupForController(bean, resource, context, parentController, parentNode); + VirtualTreeGroup virtualTreeGroup = new VirtualTreeGroup(); + context.virtualTreeGroup().addChild(virtualTreeGroup); + Node node = context.setupForController(bean, resource, context, parentController, parentNode, virtualTreeGroup); fieldWithAnnotation.setAccessible(true); fieldWithAnnotation.set(parentController, bean); diff --git a/module-fx/src/main/java/place/sita/modulefx/processors/MessageBusSupportProcessor.java b/module-fx/src/main/java/place/sita/modulefx/processors/MessageBusSupportProcessor.java new file mode 100644 index 0000000..b87490b --- /dev/null +++ b/module-fx/src/main/java/place/sita/modulefx/processors/MessageBusSupportProcessor.java @@ -0,0 +1,26 @@ +package place.sita.modulefx.processors; + +import place.sita.modulefx.FxSceneBuilderProcessor; +import place.sita.modulefx.FxSetupContext; +import place.sita.modulefx.annotations.FxChild; +import place.sita.modulefx.vtg.VirtualTreeGroupElement; + +import java.util.Arrays; + +public class MessageBusSupportProcessor implements FxSceneBuilderProcessor { + @Override + public void process(FxSetupContext context) { + VirtualTreeGroupElement element = new VirtualTreeGroupElement(); + boolean addedToAnyVirtualTreeGroup = false; + + + Object controller = context.controller(); + + Class controllerClass = controller.getClass(); + Arrays.stream(controllerClass.getDeclaredFields()) + .filter(field -> field.isAnnotationPresent(FxChild.class)) + .forEach(field -> { + injectChild(controller, field, controllerClass, context); + }); + } +} diff --git a/module-fx/src/main/java/place/sita/modulefx/processors/tabs/FxSmartTab.java b/module-fx/src/main/java/place/sita/modulefx/processors/tabs/FxSmartTab.java index abfa0d4..d6ec2e3 100644 --- a/module-fx/src/main/java/place/sita/modulefx/processors/tabs/FxSmartTab.java +++ b/module-fx/src/main/java/place/sita/modulefx/processors/tabs/FxSmartTab.java @@ -2,12 +2,13 @@ import javafx.scene.control.Tab; import place.sita.modulefx.UnstableSceneReporter; +import place.sita.modulefx.vtg.VirtualTreeGroup; public interface FxSmartTab { Tab tab(); - void load(UnstableSceneReporter unstableSceneReporter); + VirtualTreeGroup load(UnstableSceneReporter unstableSceneReporter); void unload(); diff --git a/module-fx/src/main/java/place/sita/modulefx/processors/tabs/FxSmartTabFactory.java b/module-fx/src/main/java/place/sita/modulefx/processors/tabs/FxSmartTabFactory.java index 37df3d7..ce91529 100644 --- a/module-fx/src/main/java/place/sita/modulefx/processors/tabs/FxSmartTabFactory.java +++ b/module-fx/src/main/java/place/sita/modulefx/processors/tabs/FxSmartTabFactory.java @@ -6,10 +6,12 @@ import javafx.scene.control.Tab; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Region; +import place.sita.modulefx.BadApiUsageException; import place.sita.modulefx.ChildrenFactory; import place.sita.modulefx.FxSetupContext; import place.sita.modulefx.UnstableSceneReporter; import place.sita.modulefx.annotations.FxTab; +import place.sita.modulefx.vtg.VirtualTreeGroup; import java.util.UUID; @@ -44,16 +46,18 @@ public Tab tab() { } @Override - public void load(UnstableSceneReporter unstableSceneReporter) { + public VirtualTreeGroup load(UnstableSceneReporter unstableSceneReporter) { if (loaded) { - return; + throw new BadApiUsageException("Cannot load a tab that is already loaded"); } + VirtualTreeGroup virtualTreeGroup = new VirtualTreeGroup(); + UUID loadId = UUID.randomUUID(); unstableSceneReporter.markUnstable(loadId, "Loading tab: " + tabClass.getName()); Object bean = factory.create(tabClass); - Node component = setupContext.setupForController(bean, fxTab.resourceFile(), setupContext); + Node component = setupContext.setupForController(bean, fxTab.resourceFile(), setupContext, virtualTreeGroup); AnchorPane anchorPane = new AnchorPane(); if (component instanceof Region region) { @@ -70,6 +74,7 @@ public void load(UnstableSceneReporter unstableSceneReporter) { unstableSceneReporter.markStable(loadId); }); loaded = true; + return virtualTreeGroup; } @Override diff --git a/module-fx/src/main/java/place/sita/modulefx/processors/tabs/FxSmartTabManager.java b/module-fx/src/main/java/place/sita/modulefx/processors/tabs/FxSmartTabManager.java index 59a474d..4052417 100644 --- a/module-fx/src/main/java/place/sita/modulefx/processors/tabs/FxSmartTabManager.java +++ b/module-fx/src/main/java/place/sita/modulefx/processors/tabs/FxSmartTabManager.java @@ -4,17 +4,22 @@ import javafx.scene.control.TabPane; import place.sita.modulefx.UnstableSceneReporter; import place.sita.modulefx.threading.Threading; +import place.sita.modulefx.vtg.VirtualTreeGroup; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; public class FxSmartTabManager { private final Map tabs = new LinkedHashMap<>(); + private final Map virtualTreeGroups = new HashMap<>(); + private final VirtualTreeGroup parentVtg; private final UnstableSceneReporter unstableSceneReporter; - public FxSmartTabManager(UnstableSceneReporter unstableSceneReporter) { + public FxSmartTabManager(VirtualTreeGroup parentVtg, UnstableSceneReporter unstableSceneReporter) { + this.parentVtg = parentVtg; this.unstableSceneReporter = unstableSceneReporter; } @@ -35,16 +40,23 @@ public void register(TabPane tabPane) { if (oldValue != null) { FxSmartTab oldTab = tabs.get(oldValue.getId()); oldTab.unload(); + VirtualTreeGroup group = virtualTreeGroups.get(oldValue.getId()); + parentVtg.removeChild(group.id()); } if (newValue != null) { FxSmartTab newTab = tabs.get(newValue.getId()); - newTab.load(unstableSceneReporter); + VirtualTreeGroup group = newTab.load(unstableSceneReporter); + virtualTreeGroups.put(newValue.getId(), group); + parentVtg.addChild(group); } }); }); Tab firstTab = tabPane.getTabs().get(0); - FxSmartTab firstFxTab = tabs.get(firstTab.getId()); - firstFxTab.load(unstableSceneReporter); + String firstTabId = firstTab.getId(); + FxSmartTab firstFxTab = tabs.get(firstTabId); + VirtualTreeGroup group = firstFxTab.load(unstableSceneReporter); + virtualTreeGroups.put(firstTabId, group); + parentVtg.addChild(group); } } diff --git a/module-fx/src/main/java/place/sita/modulefx/processors/tabs/InjectTabsProcessor.java b/module-fx/src/main/java/place/sita/modulefx/processors/tabs/InjectTabsProcessor.java index 4b18473..619c05d 100644 --- a/module-fx/src/main/java/place/sita/modulefx/processors/tabs/InjectTabsProcessor.java +++ b/module-fx/src/main/java/place/sita/modulefx/processors/tabs/InjectTabsProcessor.java @@ -43,7 +43,7 @@ private void injectTabs(Object controller, Field field, FxSetupContext context) List tabInfos = fetchTabInfoOrder(classes); TabPane tabPane = getTabPane(controller, field); - FxSmartTabManager manager = new FxSmartTabManager(unstableSceneReporter); + FxSmartTabManager manager = new FxSmartTabManager(context.virtualTreeGroup(), unstableSceneReporter); for (TabInfo tabInfo : tabInfos) { FxTab fxTab = tabInfo.clazz.getAnnotation(FxTab.class);