All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.carne.jfx.fxml.FXMLController Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2016-2020 Holger de Carne and contributors, All Rights Reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package de.carne.jfx.fxml;

import java.io.IOException;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.jdt.annotation.Nullable;

import de.carne.boot.logging.Log;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.stage.Window;

/**
 * This class is used for setting up and controlling FXML based scenes.
 * 

* Controller classes must conform to the name pattern (.+)Controller and must be derived from one of this class' * subclasses. In addition a FXML file has to be created for defining the scene content as well as a resource bundle for * text resources. All these artifacts are bound together by their names as follows: *

    *
  • MyStageController (controller class)
  • *
  • MyStage.fxml (FXML resource defining the stage content)
  • *
  • MyStageI18N*.properties (resource bundle)
  • *
* * @param The actual JavaFX UI type. */ public abstract class FXMLController { private static final Log LOG = new Log(); private static final Pattern CONTROLLER_NAME_PATTERN = Pattern.compile("^(.*)\\.(.+)Controller$"); @Nullable private ResourceBundle resources = null; @Nullable private U ui = null; final void setResources(ResourceBundle resources) { this.resources = resources; } /** * Get the UI resource bundle. * * @return The UI resource bundle. */ protected final ResourceBundle getResources() { return Objects.requireNonNull(this.resources); } final void setUI(U ui) { this.ui = ui; } /** * Get the UI object. * * @return The UI object. */ public final U getUI() { return Objects.requireNonNull(this.ui); } /** * Get the UI window. * * @return The UI window. */ public abstract Window getWindow(); /** * Perform the basic UI setup by loading the UI resource bundle, the scene content as well as the controller class * and bind all together. * * @param The JavaFX UI object type. * @param The actual {@code FXMLController} type. * @param owner The UI object's owner (may by {@code null}). * @param uiFactory The factory function used to create the actual UI object by invoking it with the constructed * controller. * @param controllerClass The controller class to use. * @return The constructed controller which is bound to the constructed scene and UI object. * @throws IOException if an I/O error occurs during stage setup. */ protected static > C loadUI(@Nullable Window owner, Function uiFactory, Class controllerClass) throws IOException { String controllerName = controllerClass.getName(); LOG.debug("Loading UI for controller: {0}", controllerName); Matcher controllerNameMatcher = CONTROLLER_NAME_PATTERN.matcher(controllerName); if (!controllerNameMatcher.find()) { throw new IllegalArgumentException("Invalid controller class name: " + controllerName); } String baseName = controllerNameMatcher.group(2); String fxmlResourceName = baseName + ".fxml"; String packageName = controllerNameMatcher.group(1); String bundleName = packageName + "." + baseName + "I18N"; ResourceBundle bundle = ResourceBundle.getBundle(bundleName); FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(controllerClass.getResource(fxmlResourceName)), bundle); Parent fxmlRoot = loader.load(); C controller = loader.getController(); controller.setResources(loader.getResources()); U ui = uiFactory.apply(controller); controller.setUI(ui); controller.setupUI(owner, ui, fxmlRoot); return controller; } /** * This function is called during UI initialization to perform the actual UI setup. * * @param owner The UI object's owner (may by {@code null}). * @param ui The constructed UI object. * @param fxmlRoot The scene's root node as defined by the FXML resource. */ protected abstract void setupUI(@Nullable Window owner, U ui, Parent fxmlRoot); }