/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2014, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library 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
* Lesser General Public License for more details.
*/
package org.geotoolkit.internal;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.logging.Level;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.value.ObservableValue;
import javafx.embed.swing.SwingFXUtils;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.image.Image;
import javafx.scene.image.WritableImage;
import javax.imageio.ImageIO;
import org.apache.sis.util.ArgumentChecks;
import org.controlsfx.dialog.ExceptionDialog;
import org.geotoolkit.factory.FactoryFinder;
import org.geotoolkit.font.FontAwesomeIcons;
import org.geotoolkit.font.IconBuilder;
import org.geotoolkit.style.MutableStyleFactory;
import org.opengis.filter.FilterFactory2;
import org.opengis.util.InternationalString;
/**
* Internalization, IconBundle, JavaFX utilities for geotoolkit javafx widgets.
*
* @author Johann Sorel (Geomatys)
*/
public final class GeotkFX {
public static final Image ICON_STYLE = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_BOOK,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_FTS = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_TAG,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_RULE = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_FILTER,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_NEW = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_PLUS,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_DUPLICATE = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_FILES_O,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_DELETE = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_TRASH_O,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_MOVEUP = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_CHEVRON_UP,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_MOVEDOWN = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_CHEVRON_DOWN,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_SLIDERS = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_SLIDERS,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_FILTER = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_FILTER,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_CALENDAR = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_CALENDAR,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_EDIT = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_PENCIL,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_ADD = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_PLUS,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_OPEN = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_FOLDER_OPEN,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_SAVE = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_SAVE_ALIAS,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_UNLINK = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_CHAIN_BROKEN,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_UNDO = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_UNDO,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_MOVE = SwingFXUtils.toFXImage(IconBuilder.createImage(FontAwesomeIcons.ICON_ARROWS,16,FontAwesomeIcons.DEFAULT_COLOR),null);
public static final Image ICON_EMPTY = new WritableImage(16, 16);
public static final String BUNDLE_PATH = "org/geotoolkit/gui/javafx/internal/Bundle";
public static final String CSS_PATH = "/org/geotoolkit/gui/javafx/style/StyleEditor.css";
public static final ResourceBundle BUNDLE = ResourceBundle.getBundle(BUNDLE_PATH,Locale.getDefault(),GeotkFX.class.getClassLoader());
private static FilterFactory2 FF;
private static MutableStyleFactory SF;
public synchronized static FilterFactory2 getFilterFactory(){
if(FF==null)FF = (FilterFactory2) FactoryFinder.getFilterFactory(null);
return FF;
}
public synchronized static MutableStyleFactory getStyleFactory(){
if(SF==null)SF = (MutableStyleFactory) FactoryFinder.getStyleFactory(null);
return SF;
}
/**
* Get the local string for the given class and key.
* The object class name will be pre-concatenate with the key.
*
* @param base base class
* @param key Bundle key
* @return I18N String
*/
public static String getString(Object base, final String key){
return getString(base.getClass(), key);
}
/**
* Get the local string for the given class and key.
* The class name will be pre-concatenate with the key.
*
* @param clazz base class
* @param key Bundle key
* @return I18N String
*/
public static String getString(Class clazz, final String key){
try{
return BUNDLE.getString(clazz.getName()+"."+key);
}catch(MissingResourceException ex){
return "Missing key : "+key;
}
}
/**
* Get the local string for the given key.
*
* @param key Bundle key
* @return I18N String
*/
public static String getString(final String key){
try{
return BUNDLE.getString(key);
}catch(MissingResourceException ex){
return "Missing key : "+key;
}
}
/**
* Get I18N String with parameters.
*
* @param key Bundle key
* @param obj1 first argument
* @return I18N String
*/
public static String getString(final String key, Object obj1){
return getString(key, new Object[]{obj1});
}
/**
* Get I18N String with parameters.
*
* @param key Bundle key
* @param objects arguments
* @return I18N String
*/
public static String getString(final String key, final Object[] objects){
String text = getString(key);
String pattern;
for (int i = 0; i < objects.length; i++) {
pattern = "{"+i+"}";
if (text.contains(pattern)) {
text = text.replace(pattern, objects[i].toString());
}
}
return text;
}
/**
* Get I18N String.
*
* @param key Bundle key
* @return I18N String
*/
public static InternationalString getI18NString(final String key){
try{
String text = BUNDLE.getString(key);
if(text.startsWith("$")){
return getI18NString(text.substring(1));
}
}catch(MissingResourceException ex){
throw new RuntimeException("Missing resource key : "+key,ex);
}
return new ClassLoaderInternationalString(GeotkFX.class,BUNDLE_PATH, key);
}
public static InternationalString getI18NString(Class clazz, final String key){
return getI18NString(clazz.getName()+"."+key);
}
public static final BufferedImage EMPTY_ICON_16;
static {
try {
EMPTY_ICON_16 = ImageIO.read(GeotkFX.class.getResource("/org/geotoolkit/gui/javafx/icon/empty16.png"));
} catch (IOException ex) {
throw new RuntimeException(ex.getMessage(),ex);
}
}
public static BufferedImage getBufferedImage(final String key) {
try {
return ImageIO.read(GeotkFX.class.getResourceAsStream("/org/geotoolkit/gui/javafx/icon/"+key+".png"));
} catch (IOException ex) {
Loggers.JAVAFX.log(Level.WARNING, ex.getMessage(), ex);
return null;
}
}
public static BufferedImage getBufferedImage(final String key, Dimension resize) {
try {
final BufferedImage img = ImageIO.read(GeotkFX.class.getResourceAsStream("/org/geotoolkit/gui/javafx/icon/"+key+".png"));
final BufferedImage resized = new BufferedImage(resize.width, resize.height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g = resized.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.drawImage(img, 0, 0, resize.width, resize.height, null);
g.dispose();
return resized;
} catch (IOException ex) {
Loggers.JAVAFX.log(Level.WARNING, ex.getMessage(), ex);
return null;
}
}
public static Image getImage(final String key) throws IOException{
return SwingFXUtils.toFXImage(getBufferedImage(key), null);
}
/**
* Load and initialize geotk bundle,css,loader for given object.
*
* @param candidate widget to load JRXML in
* @param cdtClass class as base for resource classloader
*/
public static void loadJRXML(Parent candidate, Class cdtClass) {
loadJRXML(candidate, cdtClass, true);
}
public static void loadJRXML(Parent candidate, Class cdtClass, boolean loadDefaultCSS) {
loadJRXML(candidate, cdtClass, loadDefaultCSS, null);
}
public static void loadJRXML(Parent candidate, Class cdtClass, boolean loadDefaultCSS, ResourceBundle bundle) {
final String fxmlpath = "/"+cdtClass.getName().replace('.', '/')+".fxml";
final FXMLLoader loader = new FXMLLoader(cdtClass.getResource(fxmlpath));
loader.setResources(bundle==null ? GeotkFX.BUNDLE : bundle);
loader.setController(candidate);
loader.setRoot(candidate);
//in special environement like osgi or other, we must use the proper class loaders
//not necessarly the one who loaded the FXMLLoader class
loader.setClassLoader(cdtClass.getClassLoader());
try {
loader.load();
} catch (IOException ex) {
throw new IllegalArgumentException(ex.getMessage(), ex);
}
if (loadDefaultCSS) {
candidate.getStylesheets().add(GeotkFX.CSS_PATH);
}
}
public static ExceptionDialog newExceptionDialog(final String headerText, final Throwable t) {
ArgumentChecks.ensureNonNull("Exception to display", t);
ExceptionDialog d = new ExceptionDialog(t);
d.setResizable(true);
if (headerText != null) {
d.setHeaderText(headerText);
}
d.setWidth(400);
d.setHeight(500);
return d;
}
private GeotkFX(){}
/**
* Binding which checks if the given object is an instance of given class.
* Binding value is null otherwise.
*
* @param <T> binding class
* @param value observed value
* @param clazz binding class
* @return binding object
*/
public static <T> ObjectBinding<T> isInstance(ObservableValue<?> value, Class<T> clazz){
return new IsInstanceBinding<>(value,clazz);
}
private static class IsInstanceBinding<T> extends ObjectBinding<T>{
private final ObservableValue value;
private final Class clazz;
private IsInstanceBinding(ObservableValue value, Class clazz){
this.value = value;
this.clazz = clazz;
bind(value);
}
@Override
protected T computeValue() {
final Object candidate = value.getValue();
return clazz.isInstance(candidate) ? (T)candidate : null;
}
}
}