Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support injecting @FXMLLoader with @FxView #79

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package io.quarkiverse.fx;

import io.quarkiverse.fx.views.FxView;
import io.quarkiverse.fx.views.FxViewData;
import io.quarkiverse.fx.views.FxViewRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.Produces;
import jakarta.enterprise.inject.spi.InjectionPoint;
import jakarta.inject.Inject;

import javafx.application.Platform;
import javafx.fxml.FXMLLoader;

@ApplicationScoped
Expand All @@ -13,10 +18,24 @@ public class FXMLLoaderProducer {
@Inject
Instance<Object> instance;

@Inject
FxViewRepository fxViewRepository;

@Produces
FXMLLoader produceFXMLLoader() {
FXMLLoader produceFXMLLoader(InjectionPoint ip) {
FXMLLoader loader = new FXMLLoader();
loader.setControllerFactory(param -> this.instance.select(param).get());

var fxView = ip.getAnnotated().getAnnotation(FxView.class);
if (fxView != null) {
var viewData = fxViewRepository.getViewData(fxView.value());
if (viewData != null) {
loader.setLocation(viewData.getFxmlLocation());
loader.setResources(viewData.getBundle());
Platform.runLater(() -> viewData.getStyleApplier().accept(loader.getRoot()));
}
}

return loader;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import java.lang.annotation.Target;

@Retention(RetentionPolicy.CLASS)
@Target({ ElementType.TYPE })
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER })
public @interface FxView {

/**
Expand Down
31 changes: 28 additions & 3 deletions runtime/src/main/java/io/quarkiverse/fx/views/FxViewData.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import javafx.scene.Parent;

import java.net.URL;
import java.util.ResourceBundle;
import java.util.function.Consumer;

/**
* Combination of loaded FXML elements.
* Provides convenient accessors with automatic casts.
Expand All @@ -18,8 +22,13 @@ public interface FxViewData {
*/
<T> T getController();

static FxViewData of(final Parent rootNode, final Object controller) {
return new FxViewDataImpl(rootNode, controller);
URL getFxmlLocation();
ResourceBundle getBundle();
Consumer<Parent> getStyleApplier();

static FxViewData of(final Parent rootNode, final Object controller, final URL fxmlLocation,
final ResourceBundle bundle, final Consumer<Parent> styleApplier) {
return new FxViewDataImpl(rootNode, controller, fxmlLocation, bundle, styleApplier);
}

/**
Expand All @@ -28,7 +37,8 @@ static FxViewData of(final Parent rootNode, final Object controller) {
* @param rootNode : the UI root element
* @param controller : associated controller
*/
record FxViewDataImpl(Parent rootNode, Object controller) implements FxViewData {
record FxViewDataImpl(Parent rootNode, Object controller, URL fxmlLocation,
ResourceBundle bundle, Consumer<Parent> styleApplier) implements FxViewData {
@Override
@SuppressWarnings("unchecked")
public <T extends Parent> T getRootNode() {
Expand All @@ -43,5 +53,20 @@ public <T extends Parent> T getRootNode() {
public <T> T getController() {
return (T) this.controller;
}

@Override
public URL getFxmlLocation() {
return this.fxmlLocation;
}

@Override
public ResourceBundle getBundle() {
return this.bundle;
}

@Override
public Consumer<Parent> getStyleApplier() {
return this.styleApplier;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
package io.quarkiverse.fx.views;

import io.quarkiverse.fx.FxViewLoadEvent;
import io.quarkiverse.fx.style.StylesheetWatchService;
import io.quarkus.logging.Log;
import io.quarkus.runtime.LaunchMode;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import org.jboss.logging.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
Expand All @@ -12,19 +24,7 @@
import java.util.MissingResourceException;
import java.util.Objects;
import java.util.ResourceBundle;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;

import org.jboss.logging.Logger;

import io.quarkiverse.fx.FxViewLoadEvent;
import io.quarkiverse.fx.style.StylesheetWatchService;
import io.quarkus.runtime.LaunchMode;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import java.util.function.Consumer;

@ApplicationScoped
public class FxViewRepository {
Expand Down Expand Up @@ -115,20 +115,30 @@ void setupViews(@Observes final FxViewLoadEvent event) {
loader.setLocation(url);

Parent rootNode = loader.load(stream);
if (style != null) {
if (stylesheetReload) {
// Stylesheet live reload in dev mode
StylesheetWatchService.setStyleAndStartWatchingTask(rootNode::getStylesheets, style);
} else {
// Regular setting (no live reload)
rootNode.getStylesheets().add(style);

final String stylesheet = style;
Consumer<Parent> styleApplier = node -> {
if (stylesheet != null) {
if (stylesheetReload) {
// Stylesheet live reload in dev mode
try {
StylesheetWatchService.setStyleAndStartWatchingTask(node::getStylesheets, stylesheet);
} catch (IOException e) {
Log.errorf(e, "Failed to load stylesheet (%s)", stylesheet);
}
} else {
// Regular setting (no live reload)
node.getStylesheets().add(stylesheet);
}
}
}
};
styleApplier.accept(rootNode);


Object controller = loader.getController();

// Register view
FxViewData viewData = FxViewData.of(rootNode, controller);
FxViewData viewData = FxViewData.of(rootNode, controller, url, bundle, styleApplier);
this.viewDataMap.put(name, viewData);

} catch (IOException e) {
Expand Down