/*
* 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.field.popup;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Label;
import jidefx.scene.control.decoration.DecorationPane;
import jidefx.scene.control.field.FormattedTextField;
import net.miginfocom.layout.AC;
import net.miginfocom.layout.CC;
import net.miginfocom.layout.LC;
import org.tbee.javafx.scene.layout.MigPane;
import java.util.ArrayList;
import java.util.List;
/**
* An editor pane for any type that can be represented by a value arrays, such as Insets which is basically an four
* double value array, Point2D is a two double value array.
*
* @param <S> the type the pane is editing. In the two examples above, it would be the Insets or the Point2D
* @param <T> the element type of the array. In both examples above, it would be Double.
*/
public abstract class ValuesPopupContent<S, T> extends DecorationPane implements PopupContent<S> {
private List<FormattedTextField<T>> _fields;
private static final String STYLE_CLASS_DEFAULT = "popup-content"; //NON-NLS
private String[] _labels;
/**
* The labels of all the fields.
*
* @param labels the labels of all the fields
*/
public ValuesPopupContent(String[] labels) {
super(new MigPane(new LC().minWidth("100px").insets("10 10 10 10"), //NON-NLS
new AC().align("right", 0).size("pref", 0).size("100px", 1).fill(1).grow(1).gap("10px"), //NON-NLS
new AC().gap("6px"))); //NON-NLS
getStylesheets().add(PopupContent.class.getResource("PopupContent.css").toExternalForm()); //NON-NLS
getStyleClass().add(STYLE_CLASS_DEFAULT);
initializeComponents(labels);
}
/**
* Coverts from the editor data type to the elements.
*
* @param value the value for the editor
* @return the list of each element values.
*/
public abstract List<T> toValues(S value);
/**
* Coverts from the elements to the editor value.
*
* @param values the element values
* @return the editor value.
*/
public abstract S fromValues(List<T> values);
/**
* Creates a text field for the element.
*
* @return the text field
*/
public abstract FormattedTextField<T> createTextField(String label);
private void initializeComponents(String[] labels) {
_labels = labels;
_fields = new ArrayList<>();
MigPane content = (MigPane) getContent();
ChangeListener<T> changeListener = new ChangeListener<T>() {
@Override
public void changed(ObservableValue<? extends T> observable, T oldValue, T newValue) {
List<T> list = getValues();
if (list.size() == _fields.size()) { // make sure all values are there
S value = fromValues(list);
if (value != null) {
setValue(value);
}
}
}
};
for (String text : labels) {
Label label = new Label(text);
content.add(label);
FormattedTextField<T> field = createTextField(text);
field.valueProperty().addListener(changeListener);
_fields.add(field);
field.installAdjustmentMouseHandler(label);
content.add(field, new CC().wrap());
}
}
protected int getFieldIndex(String label) {
for (int i = 0; i < _labels.length; i++) {
if (_labels[i].equals(label)) {
return i;
}
}
return -1;
}
private ObjectProperty<S> _valueProperty = null;
@Override
public final ObjectProperty<S> valueProperty() {
if (_valueProperty == null) {
_valueProperty = new SimpleObjectProperty<S>(this, "value") { //NON-NLS
@Override
protected void invalidated() {
super.invalidated();
updateFields(get());
}
};
}
return _valueProperty;
}
@Override
public final S getValue() {
return valueProperty().get();
}
@Override
public final void setValue(S value) {
valueProperty().set(value);
}
protected void updateFields(S value) {
List<T> values = toValues(value);
if (values.size() != _fields.size()) {
throw new IllegalStateException("The number of the values return from toValues method must be the same as the number of labels passed in to ValuePopupContent's constructor.");
}
for (int i = 0; i < _fields.size(); i++) {
_fields.get(i).setValue(values.get(i));
}
}
protected List<T> getValues() {
List<T> values = new ArrayList<>();
for (FormattedTextField<T> field : _fields) {
T value = field.getValue();
if (value != null) {
values.add(value);
}
}
return values;
}
}