/** * Get more info at : www.jrebirth.org . * Copyright JRebirth.org © 2011-2013 * Contact : sebastien.bordes@jrebirth.org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jrebirth.af.core.ui.fxml; import javafx.scene.Node; import org.jrebirth.af.api.resource.fxml.FXMLItem; import org.jrebirth.af.api.ui.Model; import org.jrebirth.af.api.ui.NullView; import org.jrebirth.af.api.ui.fxml.FXMLComponent; import org.jrebirth.af.api.ui.fxml.FXMLController; import org.jrebirth.af.core.resource.fxml.FXML; import org.jrebirth.af.core.ui.object.AbstractObjectModel; /** * The interface <strong>FXMLModel</strong>. * * Default implementation used to manage FXML file. * * @author Sébastien Bordes * * @param <M> the class type of the current model * @param <O> the class type of the bindable object */ public abstract class AbstractFXMLObjectModel<M extends Model, O extends Object> extends AbstractObjectModel<M, NullView, O> { /** The key part prefix used to attach the fxml path to this class. */ public static final String KEYPART_FXML_PREFIX = "fxml:"; /** The key part prefix used to attach the resource bundle path to this class. */ public static final String KEYPART_RB_PREFIX = "rb:"; /** The fxml path. */ private String fxmlPath; /** The resource path. */ private String resourcePath; /** The fxml resource. */ private FXMLItem fxmlItem; /** The fxmlComponent that wrap the node and its controller. */ private FXMLComponent fxmlComponent; /** * Return the fxml item used used to build the fxml component. * * @see FXMLItem * * @return the fxml item used used to build the fxml component */ protected FXMLItem getFXMLItem() { return this.fxmlItem; } /** * Return the fxml path of the the file to load. * * @see FXMLUtils * * @return the fxml path */ protected String getFXMLPath() { return this.fxmlPath; } /** * Return the bundle path of the the properties file to load. * * @see FXMLUtils * * @return the bundle path */ protected String getFXMLBundlePath() { return this.resourcePath; } /** * {@inheritDoc} */ @Override @SuppressWarnings("unchecked") protected void prepareView() { // Grab FXML definition from keypart, properties or by logical name fxmlPreInitialize(); // Initialize the FXML View, by loading the FXML file and creating all Nodes. if (getFXMLItem() != null) { this.fxmlComponent = getFXMLItem().get(); if (this.fxmlComponent.getController() != null) { // Attach manually the model to the FXMLController, because the FXMLBuilder#buildComponent hadn't done it this.fxmlComponent.getController().setModel(this); } } else if (getFXMLPath() != null) { this.fxmlComponent = FXMLUtils.loadFXML(this, getFXMLPath(), getFXMLBundlePath()); } } /** * {@inheritDoc} */ @Override protected final void bindInternal() { // Auto bound ! // Do custom binding stuff bind(); } /** * Pre init. */ protected void fxmlPreInitialize() { // Define fxml path and resource bundle path according to key parts provided // If an FXMLItem is provided, simply map it to the internal item handle if (!getListKeyPart().isEmpty() && getListKeyPart().get(0) instanceof FXMLItem) { this.fxmlItem = (FXMLItem) getListKeyPart().get(0); // if the first key part is a string that begins with fxml: } else if (!getListKeyPart().isEmpty() && getListKeyPart().get(0).toString().startsWith(KEYPART_FXML_PREFIX)) { // Use the string provided and append FXML extension final String baseName = getListKeyPart().get(0).toString().substring(KEYPART_FXML_PREFIX.length()); this.fxmlPath = baseName.replaceAll(FXML.DOT_SEPARATOR, FXML.PATH_SEPARATOR) + FXML.FXML_EXT; // if the second key part is a string that begins with rb: if (getListKeyPart().size() > 1 && getListKeyPart().get(1).toString().startsWith(KEYPART_RB_PREFIX)) { this.resourcePath = getListKeyPart().get(1).toString().substring(KEYPART_RB_PREFIX.length()).replaceAll(FXML.DOT_SEPARATOR, FXML.PATH_SEPARATOR); } else { // Otherwise use the same base name as fxml file this.resourcePath = baseName; } } else { // Otherwise use the current class name to define the fxml and resource bundle file names String baseName = this.getClass().getCanonicalName(); // Remove the Model suffix if any baseName = baseName.substring(0, baseName.lastIndexOf(Model.class.getSimpleName())); // Replace . by / for the fxml loader baseName = baseName.replaceAll(FXML.DOT_SEPARATOR, FXML.PATH_SEPARATOR); this.fxmlPath = baseName + FXML.FXML_EXT; this.resourcePath = baseName; } } /** * {@inheritDoc} */ @Override public Node getRootNode() { return this.fxmlComponent.getNode(); } /** * Return the Controller associated to the FXML file. * * @return the FXML controller */ @SuppressWarnings("unchecked") public FXMLController<M, ?> getFXMLController() { return this.fxmlComponent.getController(); } }