| 
001 /*002  * Copyright 2008-2015 the original author or authors.
 003  *
 004  * Licensed under the Apache License, Version 2.0 (the "License");
 005  * you may not use this file except in compliance with the License.
 006  * You may obtain a copy of the License at
 007  *
 008  *     http://www.apache.org/licenses/LICENSE-2.0
 009  *
 010  * Unless required by applicable law or agreed to in writing, software
 011  * distributed under the License is distributed on an "AS IS" BASIS,
 012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 013  * See the License for the specific language governing permissions and
 014  * limitations under the License.
 015  */
 016 package org.codehaus.griffon.runtime.javafx.artifact;
 017
 018 import griffon.core.GriffonApplication;
 019 import griffon.core.artifact.GriffonClass;
 020 import griffon.core.artifact.GriffonController;
 021 import griffon.core.controller.Action;
 022 import griffon.core.controller.ActionManager;
 023 import griffon.exceptions.GriffonException;
 024 import griffon.exceptions.InstanceMethodInvocationException;
 025 import griffon.javafx.support.JavaFXAction;
 026 import griffon.javafx.support.JavaFXUtils;
 027 import javafx.event.ActionEvent;
 028 import javafx.fxml.FXMLLoader;
 029 import javafx.fxml.JavaFXBuilderFactory;
 030 import javafx.scene.Node;
 031 import javafx.scene.Parent;
 032 import javafx.scene.control.ButtonBase;
 033 import javafx.scene.control.MenuItem;
 034 import javafx.util.Callback;
 035 import org.codehaus.griffon.runtime.core.artifact.AbstractGriffonView;
 036
 037 import javax.annotation.Nonnull;
 038 import javax.annotation.Nullable;
 039 import javax.inject.Inject;
 040 import java.io.IOException;
 041 import java.net.URL;
 042 import java.util.Map;
 043
 044 import static griffon.javafx.support.JavaFXUtils.findElement;
 045 import static griffon.util.ConfigUtils.stripFilenameExtension;
 046 import static griffon.util.GriffonClassUtils.invokeInstanceMethod;
 047 import static griffon.util.GriffonNameUtils.isBlank;
 048 import static griffon.util.GriffonNameUtils.requireNonBlank;
 049 import static java.util.Objects.requireNonNull;
 050
 051 /**
 052  * JavaFX-friendly implementation of the GriffonView interface.
 053  *
 054  * @author Andres Almiray
 055  * @since 2.0.0
 056  */
 057 public abstract class AbstractJavaFXGriffonView extends AbstractGriffonView {
 058     private static final String ACTION_TARGET_SUFFIX = "ActionTarget";
 059     private static final String FXML_SUFFIX = ".fxml";
 060
 061     public AbstractJavaFXGriffonView() {
 062
 063     }
 064
 065     /**
 066      * Creates a new instance of this class.
 067      *
 068      * @param application the GriffonApplication that holds this artifact.
 069      * @deprecated Griffon prefers field injection over constructor injector for artifacts as of 2.1.0
 070      */
 071     @Inject
 072     @Deprecated
 073     public AbstractJavaFXGriffonView(@Nonnull GriffonApplication application) {
 074         super(application);
 075     }
 076
 077     @Nullable
 078     protected Node loadFromFXML() {
 079         return loadFromFXML(resolveBasename());
 080     }
 081
 082     @Nullable
 083     protected Node loadFromFXML(@Nonnull String baseName) {
 084         requireNonBlank(baseName, "Argument 'baseName' must not be blank");
 085         if (baseName.endsWith(FXML_SUFFIX)) {
 086             baseName = stripFilenameExtension(baseName);
 087         }
 088         baseName = baseName.replace('.', '/');
 089         String viewName = baseName + FXML_SUFFIX;
 090         String styleName = baseName + ".css";
 091
 092         URL viewResource = getResourceAsURL(viewName);
 093         if (viewResource == null) {
 094             return null;
 095         }
 096
 097         FXMLLoader fxmlLoader = new FXMLLoader(viewResource);
 098         fxmlLoader.setResources(getApplication().getMessageSource().asResourceBundle());
 099         fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory(getApplication().getApplicationClassLoader().get()));
 100         fxmlLoader.setClassLoader(getApplication().getApplicationClassLoader().get());
 101         fxmlLoader.setControllerFactory(new Callback<Class<?>, Object>() {
 102             @Override
 103             public Object call(Class<?> aClass) {
 104                 return getMvcGroup().getView();
 105             }
 106         });
 107
 108         try {
 109             fxmlLoader.load();
 110         } catch (IOException e) {
 111             throw new GriffonException(e);
 112         }
 113
 114         Parent node = fxmlLoader.getRoot();
 115
 116         URL cssResource = getResourceAsURL(styleName);
 117         if (cssResource != null) {
 118             String uriToCss = cssResource.toExternalForm();
 119             node.getStylesheets().add(uriToCss);
 120         }
 121
 122         return node;
 123     }
 124
 125     protected String resolveBasename() {
 126         GriffonClass griffonClass = getGriffonClass();
 127         String packageName = griffonClass.getPackageName();
 128         String baseName = griffonClass.getLogicalPropertyName();
 129         if (!isBlank(packageName)) {
 130             baseName = packageName + "." + baseName;
 131         }
 132         return baseName;
 133     }
 134
 135     protected void connectActions(@Nonnull Node node, @Nonnull GriffonController controller) {
 136         requireNonNull(node, "Argument 'node' must not be null");
 137         requireNonNull(controller, "Argument 'controller' must not be null");
 138         ActionManager actionManager = getApplication().getActionManager();
 139         for (Map.Entry<String, Action> e : actionManager.actionsFor(controller).entrySet()) {
 140             String actionTargetName = actionManager.normalizeName(e.getKey()) + ACTION_TARGET_SUFFIX;
 141             Object control = findElement(node, actionTargetName);
 142             if (control == null) continue;
 143             JavaFXAction action = (JavaFXAction) e.getValue().getToolkitAction();
 144
 145             if (control instanceof ButtonBase) {
 146                 JavaFXUtils.configure(((ButtonBase) control), action);
 147             } else if (control instanceof MenuItem) {
 148                 JavaFXUtils.configure(((MenuItem) control), action);
 149             } else if (control instanceof Node) {
 150                 ((Node) control).addEventHandler(ActionEvent.ACTION, action.getOnAction());
 151             } else {
 152                 // does it support the onAction property?
 153                 try {
 154                     invokeInstanceMethod(control, "setOnAction", action.getOnAction());
 155                 } catch (InstanceMethodInvocationException imie) {
 156                     // ignore
 157                 }
 158             }
 159         }
 160     }
 161
 162     @Nullable
 163     protected JavaFXAction toolkitActionFor(@Nonnull GriffonController controller, @Nonnull String actionName) {
 164         Action action = actionFor(controller, actionName);
 165         return action != null ? (JavaFXAction) action.getToolkitAction() : null;
 166     }
 167 }
 |