/* * Copyright [2014] [Christian Loehnert, krampenschiesser@gmail.com] * 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 de.ks.application.fxml; import de.ks.i18n.Localized; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; import javafx.fxml.JavaFXBuilderFactory; import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.control.*; import javafx.scene.input.Clipboard; import javafx.scene.input.DataFormat; import javafx.scene.input.MouseButton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.URL; import java.util.HashMap; import java.util.LinkedList; import java.util.Locale; import java.util.ResourceBundle; import java.util.concurrent.atomic.AtomicBoolean; /** * @param <V> the view * @param <C> the controller */ public class DefaultLoader<V extends Node, C> { private static final Logger log = LoggerFactory.getLogger(DefaultLoader.class); private final Class<?> controller; private final URL fxmlFile; private FXMLLoader loader; protected final AtomicBoolean loaded = new AtomicBoolean(false); private ControllerFactory controllerFactory; private ResourceBundle resourceBundle; private C loadedInstance; public DefaultLoader(Class<?> modelController) { this(modelController, guessFxmlFile(modelController)); } private static URL guessFxmlFile(Class<?> modelController) { String controllerName = modelController.getSimpleName(); URL resource = modelController.getResource(controllerName + ".fxml"); if (resource == null) { log.trace("Trying {}", controllerName + "View.fxml"); resource = modelController.getResource(controllerName + "View.fxml"); } if (resource == null) { if (controllerName.toLowerCase(Locale.ROOT).endsWith("controller")) { String substring = controllerName.substring(0, controllerName.length() - "controller".length()); log.trace("Trying {}", substring + ".fxml"); resource = modelController.getResource(substring + ".fxml"); if (resource == null) { log.trace("Trying {}", substring + "View.fxml"); resource = modelController.getResource(substring + "View.fxml"); } } } return resource; } public DefaultLoader(URL fxmlFile) { this(null, fxmlFile); } protected DefaultLoader(Class<?> controller, URL fxmlFile) { this.controller = controller; this.fxmlFile = fxmlFile; if (fxmlFile == null && controller == null) { log.error("FXML file not found, is null!"); throw new FXMLFileNotFoundException("FXML file not found, is null!"); } controllerFactory = new ControllerFactory(); if (controller != null) { resourceBundle = Localized.getBundle(controller); } else { resourceBundle = Localized.getBundle(); } loader = new FXMLLoader(fxmlFile, resourceBundle, new JavaFXBuilderFactory(), controllerFactory); } @SuppressWarnings("unchecked") public DefaultLoader<V, C> load() { try { if (loaded.compareAndSet(false, true)) { if (fxmlFile == null) { Object instance = controllerFactory.call(controller); if (instance instanceof Initializable) { ((Initializable) instance).initialize(null, resourceBundle); } this.loadedInstance = (C) instance; } else { log.debug("Loading fxml file {}", fxmlFile); Node loadedNode = loader.load(); if (loadedNode != null) { fillLabelCopyMenu(loadedNode); } loaded.set(true); } } } catch (IOException e) { log.error("Could not load fxml file {}", fxmlFile, e); throw new RuntimeException(e); } return this; } protected void fillLabelCopyMenu(Node loadedNode) { LinkedList<Node> stack = new LinkedList<>(); stack.add(loadedNode); while (!stack.isEmpty()) { Node node = stack.pollFirst(); if (node instanceof Parent) { stack.addAll(((Parent) node).getChildrenUnmodifiable()); } if (node instanceof TabPane) { ((TabPane) node).getTabs().forEach(t -> { log.info("Found tab pane, child node= {}", t.getContent()); stack.add(t.getContent()); }); } if (node instanceof Accordion) { ((Accordion) node).getPanes().forEach(t -> stack.add(t.getContent())); } if (node instanceof SplitPane) { ((SplitPane) node).getItems().forEach(t -> stack.add(t)); } if (node instanceof Label) { Label label = (Label) node; label.setOnMouseClicked(e -> { if (e.getButton() == MouseButton.SECONDARY) { MenuItem item = new MenuItem(Localized.get("copy")); ContextMenu contextMenu = new ContextMenu(item); item.setOnAction(actionEvent -> { HashMap<DataFormat, Object> content = new HashMap<>(); content.put(DataFormat.PLAIN_TEXT, label.getText()); Clipboard.getSystemClipboard().setContent(content); }); contextMenu.show(label, e.getScreenX(), e.getScreenY()); } }); } } } public V getView() { if (fxmlFile == null) { return null; } else { return getLoader().getRoot(); } } private FXMLLoader getLoader() { load(); return loader; } public C getController() { if (fxmlFile == null) { load(); return loadedInstance; } else { return getLoader().getController(); } } public URL getFxmlFile() { return fxmlFile; } @Override public String toString() { return "DefaultLoader{" + "fxmlFile=" + fxmlFile + '}'; } }