/*
* Copyright (c) 2002-2015, JIDE Software Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package jidefx.scene.control.editor;
import com.jidefx.utils.CacheMap;
import javafx.geometry.BoundingBox;
import javafx.geometry.Dimension2D;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.geometry.Point3D;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import jidefx.scene.control.combobox.BoundingBoxComboBox;
import jidefx.scene.control.combobox.Dimension2DComboBox;
import jidefx.scene.control.combobox.InsetsComboBox;
import jidefx.scene.control.combobox.IntegerComboBox;
import jidefx.scene.control.combobox.Point2DComboBox;
import jidefx.scene.control.combobox.Point3DComboBox;
import jidefx.scene.control.combobox.Rectangle2DComboBox;
import jidefx.scene.control.field.BoundingBoxField;
import jidefx.scene.control.field.CalendarField;
import jidefx.scene.control.field.ColorField;
import jidefx.scene.control.field.DateField;
import jidefx.scene.control.field.Dimension2DField;
import jidefx.scene.control.field.FontField;
import jidefx.scene.control.field.InsetsField;
import jidefx.scene.control.field.IntegerField;
import jidefx.scene.control.field.LocalDateField;
import jidefx.scene.control.field.LocalDateTimeField;
import jidefx.scene.control.field.LocalTimeField;
import jidefx.scene.control.field.NumberField;
import jidefx.scene.control.field.Point2DField;
import jidefx.scene.control.field.Point3DField;
import jidefx.scene.control.field.Rectangle2DField;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Calendar;
import java.util.Date;
import java.util.function.Supplier;
/**
* A global object that can register editor with a type and a EditorContext.
*/
@SuppressWarnings({"UnusedDeclaration", "Convert2MethodRef"})
public class EditorManager {
public static final String PROPERTY_EDITOR_MANAGER = "EditorManager";
/**
* Multi Manager Support
*/
private static EditorManager _instance = createInstance();
/**
* Creates a new instance of the EditorManager.
*
* @return a new instance of the EditorManager.
*/
public static EditorManager createInstance() {
return new EditorManager();
}
/**
* Gets the default instance of the EditorManager.
*
* @return the default instance of the EditorManager.
*/
public static EditorManager getInstance() {
return _instance;
}
/**
* Gets the EditorManager from the node if the node has an EditorManager defined on the Properties. If not
* there, return the default instance.
*
* @param node the node
* @return an EditorManager.
*/
public static EditorManager getInstance(Node node) {
if (node != null && node.getProperties().get(PROPERTY_EDITOR_MANAGER) instanceof EditorManager) {
return (EditorManager) node.getProperties().get(PROPERTY_EDITOR_MANAGER);
}
else {
return getInstance();
}
}
/**
* Instance individual
*/
private boolean _inited = false;
private boolean _initing = false;
private boolean _autoInit = true;
private CacheMap<Object, EditorContext> _cache = new CacheMap<>(EditorContext.CONTEXT_DEFAULT);
private Supplier<Editor> _defaultEditorSupplier = new Supplier<Editor>() {
public Editor get() {
return new TextFieldEditor();
}
};
/**
* Registers a editor with a class and a context.
*
* @param clazz the type
* @param editorFactory the editor factory
* @param context the editor context
*/
public void registerEditor(Class<?> clazz, Supplier<Editor> editorFactory, EditorContext context) {
if (clazz == null) {
throw new IllegalArgumentException("Parameter clazz cannot be null");
}
if (context == null) {
context = EditorContext.CONTEXT_DEFAULT;
}
if (isAutoInit() && !_inited && !_initing) {
initDefaultEditors();
}
_cache.register(clazz, editorFactory, context);
}
/**
* Registers an editor with a class and default context. If no context is specified, this default editor will be
* used for that type.
*
* @param clazz the type
* @param editorFactory the editor factory
*/
public void registerEditor(Class<?> clazz, Supplier<Editor> editorFactory) {
registerEditor(clazz, editorFactory, EditorContext.CONTEXT_DEFAULT);
}
/**
* Unregisters the editor which registers with the class and the context.
*
* @param clazz the type of which the editor will be unregistered.
* @param context the editor context.
*/
public void unregisterEditor(Class<?> clazz, EditorContext context) {
if (context == null) {
context = EditorContext.CONTEXT_DEFAULT;
}
if (isAutoInit() && !_inited && !_initing) {
initDefaultEditors();
}
_cache.unregister(clazz, context);
}
/**
* Unregisters all editors which register with the class.
*
* @param clazz the type of which the editor will be unregistered.
*/
public void unregisterAllEditors(Class<?> clazz) {
_cache.remove(clazz);
}
/**
* Unregisters all the editors which registered before.
*/
public void unregisterAllEditors() {
_cache.clear();
}
/**
* Gets the registered editor.
*
* @param clazz the type.
* @param context the editor context.
* @return the registered editor
*/
public Editor getEditor(Class<?> clazz, EditorContext context) {
if (isAutoInit() && !_inited && !_initing) {
initDefaultEditors();
}
if (context == null) {
context = EditorContext.CONTEXT_DEFAULT;
}
Editor editor;
Object object = _cache.getRegisteredObject(clazz, context);
if (object != null && object instanceof Supplier) {
editor = ((Supplier<Editor>) object).get();
}
else if (object != null && object instanceof Editor) {
editor = (Editor) object;
}
else {
if (context.equals(EditorContext.CONTEXT_DEFAULT)) {
editor = _defaultEditorSupplier.get();
}
else {
editor = getEditor(clazz, EditorContext.CONTEXT_DEFAULT);
}
}
if (editor instanceof LazyInitializeEditor) {
((LazyInitializeEditor) editor).initialize(clazz, context);
}
return editor;
}
/**
* Gets the registered editor using default context.
*
* @param clazz the type.
* @return the registered editor
*/
public Editor getEditor(Class<?> clazz) {
return getEditor(clazz, EditorContext.CONTEXT_DEFAULT);
}
/**
* Checks the value of autoInit.
*
* @return true or false.
* @see #setAutoInit(boolean)
*/
public boolean isAutoInit() {
return _autoInit;
}
/**
* Sets autoInit to true or false. If autoInit is true, whenever someone tries to call methods like as getEditor,
* {@link #initDefaultEditors()} will be called if it has never be called. By default, autoInit is true.
* <p/>
* This might affect the behavior if users provide their own Editors and want to overwrite default Editors.
* In this case, instead of depending on autoInit to initialize default Editors, you should call {@link
* #initDefaultEditors()} first, then call registerEditor to add your own Editors.
*
* @param autoInit true or false.
*/
public void setAutoInit(boolean autoInit) {
_autoInit = autoInit;
}
/**
* Gets the available EditorContext registered with the class.
*
* @param clazz the class.
* @return the available EditorContexts.
*/
public EditorContext[] getEditorContexts(Class<?> clazz) {
return _cache.getKeys(clazz, new EditorContext[0]);
}
/**
* Initial the default editors.
*/
public void initDefaultEditors() {
if (_inited) {
return;
}
_initing = true;
try {
registerEditor(Color.class, () -> new ColorField());
registerEditor(Color.class, () -> new ColorField(ColorField.ColorFormat.RGB), new EditorContext(ColorField.ColorFormat.RGB.name()));
registerEditor(Color.class, () -> new ColorField(ColorField.ColorFormat.HEX_RGB), new EditorContext(ColorField.ColorFormat.HEX_RGB.name()));
registerEditor(Color.class, () -> new ColorField(ColorField.ColorFormat.RGBA), new EditorContext(ColorField.ColorFormat.RGBA.name()));
registerEditor(Color.class, () -> new ColorField(ColorField.ColorFormat.HEX_RGBA), new EditorContext(ColorField.ColorFormat.HEX_RGBA.name()));
registerEditor(Integer.class, () -> new IntegerField());
registerEditor(Integer.class, () -> new IntegerComboBox(), new EditorContext("ComboBox"));
registerEditor(Double.class, () -> new NumberField(NumberField.NumberType.Currency), new EditorContext("Currency"));
registerEditor(Double.class, () -> new NumberField(NumberField.NumberType.Percent), new EditorContext("Percent"));
registerEditor(Date.class, () -> new DateField());
registerEditor(Calendar.class, () -> new CalendarField());
registerEditor(LocalDate.class, () -> new LocalDateField());
registerEditor(LocalDateTime.class, () -> new LocalDateTimeField());
registerEditor(LocalTime.class, () -> new LocalTimeField());
registerEditor(Enum.class, () -> new EnumChoiceBoxEditor());
registerEditor(Enum.class, () -> new EnumComboBoxEditor(), new EditorContext("ComboBox"));
registerEditor(Boolean.class, () -> new CheckBoxEditor());
registerEditor(Point2D.class, () -> new Point2DField());
registerEditor(Point2D.class, () -> new Point2DComboBox(), new EditorContext("ComboBox"));
registerEditor(Point3D.class, () -> new Point3DField());
registerEditor(Point3D.class, () -> new Point3DComboBox(), new EditorContext("ComboBox"));
registerEditor(Dimension2D.class, () -> new Dimension2DField());
registerEditor(Dimension2D.class, () -> new Dimension2DComboBox(), new EditorContext("ComboBox"));
registerEditor(BoundingBox.class, () -> new BoundingBoxField());
registerEditor(BoundingBox.class, () -> new BoundingBoxComboBox(), new EditorContext("ComboBox"));
registerEditor(Insets.class, () -> new InsetsField());
registerEditor(Insets.class, () -> new InsetsComboBox(), new EditorContext("ComboBox"));
registerEditor(Rectangle2D.class, () -> new Rectangle2DField());
registerEditor(Rectangle2D.class, () -> new Rectangle2DComboBox(), new EditorContext("ComboBox"));
registerEditor(Font.class, () -> new FontField());
}
finally {
_initing = false;
_inited = true;
}
}
/**
* If {@link #initDefaultEditors()} is called once, calling it again will have no effect because an internal flag is
* set. This method will reset the internal flag so that you can call {@link #initDefaultEditors()} in case you
* unregister all editors using {@link #unregisterAllEditors()}.
*/
public void resetInit() {
_inited = false;
}
public void clear() {
resetInit();
_cache.clear();
}
}