/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.fib.utils;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Observable;
import java.util.Observer;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.openflexo.antar.binding.AbstractBinding;
import org.openflexo.antar.binding.Bindable;
import org.openflexo.antar.binding.BindingDefinition;
import org.openflexo.antar.binding.BindingDefinition.BindingDefinitionType;
import org.openflexo.antar.binding.BindingDefinitionTypeChanged;
import org.openflexo.antar.binding.BindingExpression;
import org.openflexo.antar.binding.BindingExpression.BindingValueConstant;
import org.openflexo.antar.binding.BindingExpression.BindingValueFunction;
import org.openflexo.antar.binding.BindingExpression.BindingValueVariable;
import org.openflexo.antar.binding.BindingFactory;
import org.openflexo.antar.binding.BindingModel;
import org.openflexo.antar.binding.BindingModelChanged;
import org.openflexo.antar.binding.BindingPathElement;
import org.openflexo.antar.binding.BindingValue;
import org.openflexo.antar.binding.BindingVariable;
import org.openflexo.antar.binding.BindingVariableImpl;
import org.openflexo.antar.binding.BooleanStaticBinding;
import org.openflexo.antar.binding.ComplexPathElement;
import org.openflexo.antar.binding.DefaultBindingFactory;
import org.openflexo.antar.binding.FloatStaticBinding;
import org.openflexo.antar.binding.IntegerStaticBinding;
import org.openflexo.antar.binding.MethodCall;
import org.openflexo.antar.binding.MethodDefinition;
import org.openflexo.antar.binding.SimplePathElement;
import org.openflexo.antar.binding.StaticBinding;
import org.openflexo.antar.binding.StaticBindingFactory;
import org.openflexo.antar.binding.StringStaticBinding;
import org.openflexo.antar.binding.TypeUtils;
import org.openflexo.antar.expr.Expression;
import org.openflexo.fib.controller.FIBController;
import org.openflexo.fib.model.FIBCustom;
import org.openflexo.fib.model.FIBCustom.FIBCustomComponent;
import org.openflexo.icon.UtilsIconLibrary;
import org.openflexo.logging.FlexoLoggingManager;
import org.openflexo.swing.ButtonsControlPanel;
import org.openflexo.swing.SwingUtils;
import org.openflexo.swing.TextFieldCustomPopup;
import org.openflexo.swing.VerticalLayout;
import org.openflexo.toolbox.HasPropertyChangeSupport;
import org.openflexo.toolbox.StringUtils;
/**
* Widget allowing to edit a binding
*
* @author sguerin
*
*/
public class BindingSelector extends TextFieldCustomPopup<AbstractBinding> implements FIBCustomComponent<AbstractBinding, BindingSelector>,
Observer, PropertyChangeListener {
static final Logger logger = Logger.getLogger(BindingSelector.class.getPackage().getName());
private AbstractBinding _revertBindingValue;
protected boolean _allowsBindingExpressions = true;
protected boolean _allowsCompoundBindings = true;
protected boolean _allowsStaticValues = true;
protected boolean _hideFilteredObjects = false;
protected AbstractBindingSelectorPanel _selectorPanel;
boolean isUpdatingModel = false;
private boolean textIsEditing = false;
protected KeyEventDispatcher tabDispatcher = new KeyEventDispatcher() {
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_TYPED && (e.getKeyChar() == KeyEvent.VK_RIGHT || e.getKeyChar() == KeyEvent.VK_TAB)) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Calling tab pressed " + e);
}
getCustomPanel().processTabPressed();
e.consume();
}
return false;
}
};
static enum EditionMode {
NORMAL_BINDING, COMPOUND_BINDING, STATIC_BINDING, BINDING_EXPRESSION;/*,
NEW_ENTRY;*/
boolean useCommonPanel() {
return this != BINDING_EXPRESSION;
}
}
EditionMode editionMode = EditionMode.NORMAL_BINDING;
public KeyAdapter shortcutsKeyAdapter;
private DocumentListener documentListener;
private Color defaultForeground;
private Color defaultSelectedColor;
public BindingSelector(AbstractBinding editedObject) {
this(editedObject, -1);
}
public BindingSelector(AbstractBinding editedObject, int cols) {
super(null, cols);
setFocusable(true);
getTextField().setFocusable(true);
getTextField().setEditable(true);
getTextField().addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent focusEvent) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(tabDispatcher);
}
@Override
public void focusLost(FocusEvent focusEvent) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(tabDispatcher);
Component opposite = focusEvent.getOppositeComponent();
if (logger.isLoggable(Level.FINER)) {
logger.finer("focus lost for " + (opposite != null ? SwingUtils.getComponentPath(opposite) : "null"));
}
if (opposite == null || !SwingUtilities.isDescendingFrom(opposite, BindingSelector.this)
&& !SwingUtilities.isDescendingFrom(opposite, _selectorPanel)) {
// Little hook used to automatically apply a valid value which has generally been edited
// By typing text in text field
if (getEditedObject() != null && getEditedObject().isBindingValid()) {
apply();
}
}
}
});
shortcutsKeyAdapter = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
// if command-key is pressed, do not open popup
if (e.isAltDown() || e.isAltGraphDown() || e.isControlDown() || e.isMetaDown()) {
return;
}
boolean isSignificativeKey = e.getKeyCode() >= KeyEvent.VK_A && e.getKeyCode() <= KeyEvent.VK_Z
|| e.getKeyCode() >= KeyEvent.VK_0 && e.getKeyCode() <= KeyEvent.VK_9;
if (!popupIsShown() && getTextField().getText() != null
&& !isAcceptableAsBeginningOfStaticBindingValue(getTextField().getText()) && isSignificativeKey) {
boolean requestFocus = getTextField().hasFocus();
openPopup();
if (requestFocus) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
getTextField().requestFocusInWindow();
}
});
}
}
// This code was added to allow direct typing without opening selector panel (sic !)
// TODO:provide better implementation !!!
if (_selectorPanel == null) {
createCustomPanel(getEditedObject());
}
if (_selectorPanel != null) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (StringUtils.isNotEmpty(getTextField().getText()) && textFieldNotSynchWithEditedObject()) {
if (_selectorPanel instanceof BindingSelectorPanel) {
BindingSelectorPanel selectorPanel = (BindingSelectorPanel) _selectorPanel;
if (selectorPanel.isKeyPathFromTextASubKeyPath(getTextField().getText())
&& selectorPanel.isKeyPathFromPanelValid()) {
setEditedObject(selectorPanel.makeBindingValueFromPanel());
apply();
} else {
String input = getTextField().getText();
if (input.indexOf(".") > -1) {
String pathIgnoringLastPart = input.substring(0, input.lastIndexOf("."));
if (isKeyPathValid(pathIgnoringLastPart)) {
String inexitingPart = input.substring(input.lastIndexOf(".") + 1);
Type hostType = selectorPanel.getEndingTypeForSubPath(pathIgnoringLastPart);
}
}
}
}
}
_selectorPanel.processEnterPressed();
e.consume();
}
else if (e.getKeyCode() == KeyEvent.VK_UP) {
_selectorPanel.processUpPressed();
e.consume();
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
_selectorPanel.processDownPressed();
e.consume();
} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
_selectorPanel.processLeftPressed();
e.consume();
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
_selectorPanel.processRightPressed();
e.consume();
}
}
}
};
documentListener = new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
textEdited(e);
}
@Override
public void insertUpdate(DocumentEvent e) {
textEdited(e);
}
@Override
public void removeUpdate(DocumentEvent e) {
textEdited(e);
}
public void textEdited(DocumentEvent e) {
if (isProgrammaticalySet()) {
return;
}
String textValue = getTextField().getText();
textIsEditing = true;
try {
synchronizeWithTextFieldValue(textValue);
} finally {
textIsEditing = false;
}
}
};
getTextField().addKeyListener(shortcutsKeyAdapter);
getTextField().getDocument().addDocumentListener(documentListener);
updateUI(); // Just to initiate the default color values
// setEditedObjectAndUpdateBDAndOwner(editedObject);
setEditedObject(editedObject);
/*(new Thread() {
@Override
public void run() {
while(true) {
Component c = (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner());
if (c != null)
System.out.println("focus owner = "+c.hashCode()+" "+c.getClass().getSimpleName()+" is "+c);
try {
sleep(3000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}).start();*/
}
@Override
public void updateUI() {
super.updateUI();
if (getTextField() != null) {
defaultForeground = getTextField().getForeground();
defaultSelectedColor = getTextField().getSelectedTextColor();
}
}
@Override
public void init(FIBCustom component, FIBController controller) {
}
@Override
public Class<AbstractBinding> getRepresentedType() {
return AbstractBinding.class;
}
protected void synchronizeWithTextFieldValue(String textValue) {
try {
isUpdatingModel = true;
AbstractBinding newEditedBinding = makeBindingFromString(textValue);
if (newEditedBinding != null) {
logger.fine("Decoding binding as " + newEditedBinding);
// if (newEditedBinding instanceof BindingValue) logger.info("BV="+((BindingValue)newEditedBinding).getBindingVariable());
if (newEditedBinding.isBindingValid()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Decoded as VALID binding: " + newEditedBinding);
}
getTextField().setForeground(defaultForeground);
getTextField().setSelectedTextColor(defaultSelectedColor);
if (!newEditedBinding.equals(getEditedObject())) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("This is a new one, i take this");
}
setEditedObject(newEditedBinding);
return;
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Skipping as it represents the same binding");
}
return;
}
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Decoded as INVALID binding: " + newEditedBinding + " trying to synchronize panel");
}
getTextField().setForeground(Color.RED);
getTextField().setSelectedTextColor(Color.RED);
if (_selectorPanel != null) {
_selectorPanel.synchronizePanelWithTextFieldValue(textValue);
}
return;
}
}
else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Couldn't decode as binding, trying to synchronize panel anyway");
}
getTextField().setForeground(Color.RED);
getTextField().setSelectedTextColor(Color.RED);
if (_selectorPanel != null) {
_selectorPanel.synchronizePanelWithTextFieldValue(textValue);
}
return;
}
} finally {
isUpdatingModel = false;
}
}
/*public void setEditedObjectAndUpdateBDAndOwner(AbstractBinding object)
{
setEditedObject(object);
if (object != null) {
if (object.getBindingDefinition() != null) setBindingDefinition(object.getBindingDefinition());
if (object.getOwner() != null) setBindable((Bindable)object.getOwner());
}
}*/
@Override
public void setEditedObject(AbstractBinding object) {
setEditedObject(object, true);
if (object != null) {
if (object.getBindingDefinition() != null) {
setBindingDefinition(object.getBindingDefinition());
}
if (object.getOwner() != null) {
setBindable(object.getOwner());
}
}
// SGU: I suppress this code that was the cause for huge problems
// in BindingSelector, making it quite unusable
// I don't think this code was usefull, was it ?
/*else {
setBindingDefinition(null);
setBindable(null);
}*/
}
public void setEditedObject(AbstractBinding object, boolean updateBindingSelectionMode) {
// logger.info(">>>>>>>>>>>>>> setEditedObject() with "+object);
if (updateBindingSelectionMode) {
if (object != null) {
object = checkIfDisplayModeShouldChange(object, false);
} else {
activateNormalBindingMode();
}
}
super.setEditedObject(object);
if (getEditedObject() != null && getEditedObject().isBindingValid()) {
getTextField().setForeground(defaultForeground);
getTextField().setSelectedTextColor(defaultSelectedColor);
} else {
getTextField().setForeground(Color.RED);
getTextField().setSelectedTextColor(Color.RED);
}
}
AbstractBinding checkIfDisplayModeShouldChange(AbstractBinding object, boolean setValueAsNewEditedValue) {
AbstractBinding returned = object;
EditionMode oldEditionMode = editionMode;
EditionMode newEditionMode = editionMode;
if (object != null) {
if (object instanceof BindingExpression && ((BindingExpression) object).getExpression() != null) {
Expression exp = ((BindingExpression) object).getExpression();
if (exp instanceof BindingValueConstant) {
returned = ((BindingValueConstant) exp).getStaticBinding();
}
if (exp instanceof BindingValueVariable) {
returned = ((BindingValueVariable) exp).getBindingValue();
}
if (exp instanceof BindingValueFunction) {
returned = ((BindingValueFunction) exp).getBindingValue();
}
}
}
if (returned instanceof StaticBinding) {
newEditionMode = EditionMode.STATIC_BINDING;
}
if (returned instanceof BindingExpression) {
newEditionMode = EditionMode.BINDING_EXPRESSION;
}
if (returned instanceof BindingValue) {
if (((BindingValue) returned).isCompoundBinding() || getBindingDefinition() != null
&& getBindingDefinition().getBindingDefinitionType() == BindingDefinitionType.EXECUTE) {
newEditionMode = EditionMode.COMPOUND_BINDING;
} else if (oldEditionMode != EditionMode.NORMAL_BINDING && oldEditionMode != EditionMode.COMPOUND_BINDING) {
newEditionMode = EditionMode.NORMAL_BINDING;
}
}
if (returned == null) {
newEditionMode = EditionMode.NORMAL_BINDING;
}
if (logger.isLoggable(Level.FINE)) {
logger.fine("DISPLAY_MODE was: " + oldEditionMode + " is now " + newEditionMode);
}
if (oldEditionMode.useCommonPanel() != newEditionMode.useCommonPanel()) {
if (newEditionMode.useCommonPanel()) {
if (newEditionMode == EditionMode.COMPOUND_BINDING) {
activateCompoundBindingMode();
} else {
activateNormalBindingMode();
}
} else if (object instanceof BindingExpression) {
activateBindingExpressionMode((BindingExpression) object);
}
}
if (oldEditionMode != EditionMode.COMPOUND_BINDING && newEditionMode == EditionMode.COMPOUND_BINDING) {
activateCompoundBindingMode();
}
editionMode = newEditionMode;
// Should i change edited object ???
if (returned != object && setValueAsNewEditedValue) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Switching edited object from " + object + " to " + returned);
}
_editedObject = returned;
updateCustomPanel(getEditedObject());
}
return returned;
}
boolean isKeyPathValid(String pathIgnoringLastPart) {
if (!(_selectorPanel instanceof BindingSelectorPanel)) {
return false;
}
StringTokenizer token = new StringTokenizer(pathIgnoringLastPart, ".", false);
Object obj = null;
int i = 0;
while (token.hasMoreTokens()) {
obj = ((BindingSelectorPanel) _selectorPanel).findElementEquals(((BindingSelectorPanel) _selectorPanel).listAtIndex(i)
.getModel(), token.nextToken());
if (obj == null) {
return false;
}
i++;
}
return true;
}
@Override
public void fireEditedObjectChanged() {
updateCustomPanel(getEditedObject());
if (!getIsUpdatingModel()) {
_isProgrammaticalySet = true;
if (!textIsEditing) {
getTextField().setText(renderedString(getEditedObject()));
}
if (getEditedObject() != null) {
getTextField().setForeground(getEditedObject().isBindingValid() ? defaultForeground : Color.RED);
getTextField().setSelectedTextColor(getEditedObject().isBindingValid() ? defaultSelectedColor : Color.RED);
} else {
getTextField().setForeground(Color.RED);
getTextField().setSelectedTextColor(Color.RED);
}
_isProgrammaticalySet = false;
}
}
public boolean areCompoundBindingAllowed() {
// if (getBindingDefinition() != null && getBindingDefinition().getIsSettable()) return false;
return _allowsCompoundBindings;
}
public void allowsCompoundBindings() {
_allowsCompoundBindings = true;
rebuildPopup();
}
public void denyCompoundBindings() {
_allowsCompoundBindings = false;
rebuildPopup();
}
public boolean areBindingExpressionsAllowed() {
if (getBindingDefinition() != null
&& (getBindingDefinition().getIsSettable() || getBindingDefinition().getBindingDefinitionType() == BindingDefinitionType.EXECUTE)) {
return false;
}
return _allowsBindingExpressions;
}
public void allowsBindingExpressions() {
_allowsBindingExpressions = true;
rebuildPopup();
}
public void denyBindingExpressions() {
_allowsBindingExpressions = false;
rebuildPopup();
}
public boolean areStaticValuesAllowed() {
if (getBindingDefinition() != null
&& (getBindingDefinition().getIsSettable() || getBindingDefinition().getBindingDefinitionType() == BindingDefinitionType.EXECUTE)) {
return false;
}
return _allowsStaticValues;
}
public void allowsStaticValues() {
_allowsStaticValues = true;
rebuildPopup();
}
public void denyStaticValues() {
_allowsStaticValues = false;
rebuildPopup();
}
private void rebuildPopup() {
boolean showAgain = false;
if (popupIsShown()) {
showAgain = true;
closePopup(false);
}
deletePopup();
if (showAgain) {
openPopup();
updateCustomPanel(getEditedObject());
}
}
public void activateCompoundBindingMode() {
if (logger.isLoggable(Level.FINE)) {
logger.fine("ActivateCompoundBindingMode() getEditedObject()=" + getEditedObject() + " editionMode=" + editionMode
+ " popupIsShown()=" + popupIsShown() + " _selectorPanel=" + _selectorPanel);
}
if (_selectorPanel != null && editionMode != EditionMode.COMPOUND_BINDING) {
editionMode = EditionMode.COMPOUND_BINDING;
boolean showAgain = false;
if (popupIsShown()) {
showAgain = true;
closePopup(false);
}
if (getEditedObject() != null && !(getEditedObject() instanceof BindingValue)) {
_editedObject = makeBinding(); // I dont want to notify it !!!
}
deleteCustomPanel();
if (showAgain) {
openPopup();
updateCustomPanel(getEditedObject());
}
}
editionMode = EditionMode.COMPOUND_BINDING;
}
public void activateNormalBindingMode() {
if (logger.isLoggable(Level.FINE)) {
logger.fine("activateNormalBindingMode()");
}
if (_selectorPanel != null && editionMode != EditionMode.NORMAL_BINDING) {
editionMode = EditionMode.NORMAL_BINDING;
boolean showAgain = false;
if (popupIsShown()) {
showAgain = true;
closePopup(false);
}
if (getEditedObject() != null && !(getEditedObject() instanceof BindingValue)) {
_editedObject = makeBinding(); // I dont want to notify it !!!
}
deleteCustomPanel();
if (showAgain) {
openPopup();
updateCustomPanel(getEditedObject());
}
}
editionMode = EditionMode.NORMAL_BINDING;
}
public void activateBindingExpressionMode(BindingExpression bindingExpression) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("activateBindingExpressionMode()");
}
if (_selectorPanel != null) {
editionMode = EditionMode.BINDING_EXPRESSION;
boolean showAgain = false;
if (popupIsShown()) {
showAgain = true;
closePopup(false);
}
if (bindingExpression != null) {
_editedObject = bindingExpression;
} else {
_editedObject = new BindingExpression(getBindingDefinition(), getBindable()); // I dont want to notify it !!!
}
deleteCustomPanel();
if (showAgain) {
openPopup();
updateCustomPanel(getEditedObject());
}
}
}
@Override
public void delete() {
super.delete();
unregisterListenerForBindable();
unregisterListenerForBindingDefinition();
if (_selectorPanel != null) {
_selectorPanel.delete();
}
_selectorPanel = null;
_bindable = null;
}
@Override
protected void deleteCustomPanel() {
super.deleteCustomPanel();
if (_selectorPanel != null) {
_selectorPanel.delete();
}
_selectorPanel = null;
}
@Override
public void setRevertValue(AbstractBinding oldValue) {
if (oldValue != null) {
_revertBindingValue = oldValue.clone();
} else {
_revertBindingValue = null;
}
}
@Override
public AbstractBinding getRevertValue() {
return _revertBindingValue;
}
@Override
protected ResizablePanel createCustomPanel(AbstractBinding editedObject) {
if (editionMode == EditionMode.BINDING_EXPRESSION) {
_selectorPanel = new BindingExpressionSelectorPanel(this);
_selectorPanel.init();
}
/*else if (editionMode == EditionMode.NEW_ENTRY) {
_selectorPanel = new BindingExpressionSelectorPanel(this);
_selectorPanel.init();sqddqs
}*/
else {
// When creating use normal mode
if (editedObject instanceof StaticBinding) {
editionMode = EditionMode.NORMAL_BINDING;
}
_selectorPanel = new BindingSelectorPanel(this);
_selectorPanel.init();
}
refreshBindingModel();
return _selectorPanel;
}
public void refreshBindingModel() {
if (_bindable != null && _selectorPanel != null) {
_selectorPanel.update();
}
}
public void refreshBindingDefinitionType() {
if (_selectorPanel != null) {
_selectorPanel.fireBindingDefinitionChanged();
}
}
@Override
public void updateCustomPanel(AbstractBinding editedObject) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("updateCustomPanel() with " + editedObject);
}
if (editedObject != null && editedObject instanceof BindingValue && ((BindingValue) editedObject).isCompoundBinding()) {
activateCompoundBindingMode();
}
if (_selectorPanel != null) {
_selectorPanel.update();
}
if (getBindingDefinition() != null && getBindingDefinition().getIsMandatory() && getEditedObject() == null) {
getLabel().setVisible(true);
getLabel().setIcon(UtilsIconLibrary.WARNING_ICON);
} else if (getEditedObject() != null && !getEditedObject().isBindingValid()) {
getLabel().setVisible(true);
getLabel().setIcon(UtilsIconLibrary.ERROR_ICON);
} else if (getEditedObject() != null && getEditedObject().isBindingValid()) {
getLabel().setVisible(true);
getLabel().setIcon(UtilsIconLibrary.OK_ICON);
} else {
getLabel().setVisible(false);
}
}
public void resetMethodCallPanel() {
if (_selectorPanel != null && _selectorPanel instanceof BindingSelectorPanel) {
((BindingSelectorPanel) _selectorPanel).resetMethodCallPanel();
}
}
@Override
public String renderedString(AbstractBinding editedObject) {
if (editedObject != null) {
return editedObject.getStringRepresentation();
}
return "";
}
public Bindable getBindable() {
return _bindable;
}
@CustomComponentParameter(name = "bindable", type = CustomComponentParameter.Type.MANDATORY)
public void setBindable(Bindable bindable) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("setBindable with " + bindable);
}
unregisterListenerForBindable();
_bindable = bindable;
if (bindable != null && _selectorPanel != null) {
_selectorPanel.fireBindableChanged();
}
registerListenerForBindable();
// getCustomPanel().setBindingModel(bindable.getBindingModel());
updateTextFieldProgrammaticaly();
}
public void registerListenerForBindable() {
if (_bindable instanceof Observable) {
((Observable) _bindable).addObserver(this);
}
if (_bindable instanceof HasPropertyChangeSupport) {
// System.out.println("registering " + bindable + " for " + this);
if (((HasPropertyChangeSupport) _bindable).getPropertyChangeSupport() != null) {
((HasPropertyChangeSupport) _bindable).getPropertyChangeSupport().addPropertyChangeListener(
BindingModelChanged.BINDING_MODEL_CHANGED, this);
}
}
}
public void unregisterListenerForBindable() {
if (_bindable instanceof Observable) {
((Observable) _bindable).deleteObserver(this);
}
if (_bindable instanceof HasPropertyChangeSupport) {
if (((HasPropertyChangeSupport) _bindable).getPropertyChangeSupport() != null) {
((HasPropertyChangeSupport) _bindable).getPropertyChangeSupport().removePropertyChangeListener(this);
}
}
}
@Override
public void updateTextFieldProgrammaticaly() {
// Don't update textfield if original event was triggered by a textfield edition
if (!textIsEditing) {
super.updateTextFieldProgrammaticaly();
}
}
@Override
public void update(Observable observable, Object notification) {
if (observable == _bindable) {
if (notification instanceof BindingModelChanged) {
logger.fine("Refreshing Binding Model");
refreshBindingModel();
}
}
if (observable == _bindingDefinition) {
if (notification instanceof BindingDefinitionTypeChanged) {
logger.fine("Updating BindingDefinition type");
refreshBindingDefinitionType();
}
}
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(BindingModelChanged.BINDING_MODEL_CHANGED)) {
logger.fine("Refreshing Binding Model");
refreshBindingModel();
} else if (evt.getPropertyName().equals(BindingDefinitionTypeChanged.BINDING_DEFINITION_TYPE_CHANGED)) {
logger.fine("Updating BindingDefinition type");
refreshBindingDefinitionType();
}
}
/*public void setCustomBindingModel(BindingModel aBindingModel)
{
setBindingModel(aBindingModel);
}*/
/*private BindingDefinition _bindingDefinitionForSelector = null;
public BindingDefinition getBindingDefinition()
{
if (getCustomPanel() != null)
return getCustomPanel().getBindingDefinition();
return _bindingDefinitionForSelector;dqsdsq
}
public void setBindingDefinition(BindingDefinition bindingDefinition)
{
if (logger.isLoggable(Level.FINE))
logger.fine("setBindingDefinition with " + bindingDefinition);
getCustomPanel().setBindingDefinition(bindingDefinition);
}*/
BindingDefinition _bindingDefinition;
// BindingModel _bindingModel;
public BindingDefinition getBindingDefinition() {
return _bindingDefinition;
}
@CustomComponentParameter(name = "bindingDefinition", type = CustomComponentParameter.Type.MANDATORY)
public void setBindingDefinition(BindingDefinition bindingDefinition) {
if (logger.isLoggable(Level.FINE)) {
logger.fine(toString() + "Setting new binding definition: " + bindingDefinition + " old: " + _bindingDefinition);
}
if (bindingDefinition != _bindingDefinition) {
unregisterListenerForBindingDefinition();
_bindingDefinition = bindingDefinition;
AbstractBinding bindingValue = getEditedObject();
if (bindingValue != null) {
bindingValue.setBindingDefinition(bindingDefinition);
if (logger.isLoggable(Level.FINE)) {
logger.fine("set BD " + bindingDefinition + " for BV " + bindingValue);
}
}
if (_selectorPanel != null) {
_selectorPanel.fireBindingDefinitionChanged();
}
registerListenerForBindingDefinition();
updateCustomPanel(getEditedObject());
}
}
public void registerListenerForBindingDefinition() {
if (_bindingDefinition instanceof Observable) {
((Observable) _bindingDefinition).addObserver(this);
}
if (_bindingDefinition instanceof HasPropertyChangeSupport) {
((HasPropertyChangeSupport) _bindingDefinition).getPropertyChangeSupport().addPropertyChangeListener(
BindingDefinitionTypeChanged.BINDING_DEFINITION_TYPE_CHANGED, this);
((HasPropertyChangeSupport) _bindingDefinition).getPropertyChangeSupport().addPropertyChangeListener(this);
}
}
public void unregisterListenerForBindingDefinition() {
if (_bindingDefinition instanceof Observable) {
((Observable) _bindingDefinition).deleteObserver(this);
}
if (_bindingDefinition instanceof HasPropertyChangeSupport) {
((HasPropertyChangeSupport) _bindingDefinition).getPropertyChangeSupport().removePropertyChangeListener(
BindingDefinitionTypeChanged.BINDING_DEFINITION_TYPE_CHANGED, this);
((HasPropertyChangeSupport) _bindingDefinition).getPropertyChangeSupport().removePropertyChangeListener(this);
}
}
public BindingModel getBindingModel() {
if (getBindable() != null) {
return getBindable().getBindingModel();
}
return null;
}
@Override
public AbstractBindingSelectorPanel getCustomPanel() {
return (AbstractBindingSelectorPanel) super.getCustomPanel();
}
protected BindingExpression makeBindingExpression() {
if (getBindable() != null) {
// BindingExpressionFactory factory = getBindable().getBindingFactory().getBindingExpressionFactory();
BindingExpression returned = new BindingExpression(getBindingDefinition(), getBindable());
returned.setExpression(new BindingValueVariable("", getBindable()));
return returned;
}
return null;
}
protected AbstractBinding makeBinding() {
AbstractBinding returned = null;
if (editionMode == EditionMode.BINDING_EXPRESSION) {
if (getBindingDefinition() != null && getBindable() != null) {
returned = makeBindingExpression();
}
} else if (editionMode == EditionMode.STATIC_BINDING) {
if (getBindingDefinition() != null && getBindable() != null) {
if (getBindingDefinition().getType() != null) {
if (TypeUtils.isBoolean(getBindingDefinition().getType())) {
returned = new BooleanStaticBinding(getBindingDefinition(), getBindable(), false);
} else if (TypeUtils.isInteger(getBindingDefinition().getType()) || TypeUtils.isLong(getBindingDefinition().getType())
|| TypeUtils.isShort(getBindingDefinition().getType()) || TypeUtils.isChar(getBindingDefinition().getType())
|| TypeUtils.isByte(getBindingDefinition().getType())) {
returned = new IntegerStaticBinding(getBindingDefinition(), getBindable(), 0);
} else if (TypeUtils.isFloat(getBindingDefinition().getType()) || TypeUtils.isDouble(getBindingDefinition().getType())) {
returned = new FloatStaticBinding(getBindingDefinition(), getBindable(), 0.0);
}
} else if (TypeUtils.isString(getBindingDefinition().getType())) {
returned = new StringStaticBinding(getBindingDefinition(), getBindable(), "");
}
}
} else if (editionMode == EditionMode.NORMAL_BINDING || editionMode == EditionMode.COMPOUND_BINDING) { // Normal or compound binding
if (getBindingDefinition() != null && getBindable() != null) {
returned = new BindingValue(getBindingDefinition(), getBindable());
}
}
return returned;
}
AbstractBinding recreateBindingValue() {
setEditedObject(makeBinding());
logger.info("Recreating Binding with mode " + editionMode + " as " + getEditedObject());
return getEditedObject();
}
Bindable _bindable;
protected abstract class AbstractBindingSelectorPanel extends ResizablePanel {
protected abstract void synchronizePanelWithTextFieldValue(String textValue);
protected abstract void init();
protected abstract void update();
protected abstract void fireBindingDefinitionChanged();
protected abstract void fireBindableChanged();
protected abstract void processTabPressed();
protected abstract void processDownPressed();
protected abstract void processUpPressed();
protected abstract void processLeftPressed();
protected abstract void processRightPressed();
protected abstract void processEnterPressed();
protected abstract void processBackspace();
protected abstract void processDelete();
protected abstract void willApply();
protected abstract void delete();
}
@Override
protected void openPopup() {
if (_selectorPanel != null) {
if (_selectorPanel instanceof BindingSelectorPanel) {
JList list = ((BindingSelectorPanel) _selectorPanel).listAtIndex(0);
if (list.getModel().getSize() == 1) {
list.setSelectedIndex(0);
}
}
}
super.openPopup();
if (_selectorPanel != null) {
ButtonsControlPanel controlPanel = null;
if (_selectorPanel instanceof BindingSelectorPanel) {
controlPanel = ((BindingSelectorPanel) _selectorPanel)._controlPanel;
} else if (_selectorPanel instanceof BindingExpressionSelectorPanel) {
controlPanel = ((BindingExpressionSelectorPanel) _selectorPanel)._controlPanel;
}
if (controlPanel != null) {
controlPanel.applyFocusTraversablePolicyTo(controlPanel, false);
}
}
}
@Override
public void closePopup() {
super.closePopup();
// logger.info("closePopup()");
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
getTextField().requestFocusInWindow();
}
});
}
@Override
public void apply() {
if (_selectorPanel != null) {
_selectorPanel.willApply();
}
AbstractBinding bindingValue = getEditedObject();
if (bindingValue != null) {
if (bindingValue.isBindingValid()) {
if (bindingValue instanceof BindingValue) {
((BindingValue) bindingValue).connect();
}
getTextField().setForeground(defaultForeground);
getTextField().setSelectedTextColor(defaultSelectedColor);
} else {
getTextField().setForeground(Color.RED);
getTextField().setSelectedTextColor(Color.RED);
}
_revertBindingValue = bindingValue.clone();
} else {
_revertBindingValue = null;
}
updateTextFieldProgrammaticaly();
if (popupIsShown()) {
closePopup();
}
super.apply();
}
@Override
public void cancel() {
setEditedObject(_revertBindingValue);
closePopup();
super.cancel();
}
@Override
protected void pointerLeavesPopup() {
cancel();
}
public boolean getIsUpdatingModel() {
return isUpdatingModel;
}
public void setUpdatingModel(boolean isUpdatingModelFlag) {
this.isUpdatingModel = isUpdatingModelFlag;
}
protected AbstractListModel getRootListModel() {
if (_selectorPanel != null && _selectorPanel instanceof BindingSelectorPanel) {
return ((BindingSelectorPanel) _selectorPanel).getRootColumnListModel();
}
return null;
}
protected final AbstractListModel getListModelFor(BindingPathElement element, Type resultingType) {
if (_selectorPanel != null && _selectorPanel instanceof BindingSelectorPanel) {
return ((BindingSelectorPanel) _selectorPanel).getColumnListModel(element, resultingType);
}
return null;
}
protected void valueSelected(int index, JList list, AbstractBinding binding) {
if (!(binding instanceof BindingValue)) {
editionMode = EditionMode.NORMAL_BINDING;
binding = makeBinding(); // Should create a BindingValue instance !!!
if (!(binding instanceof BindingValue)) {
logger.severe("Should never happen: valueSelected() called for a non-BindingValue instance !");
return;
}
}
BindingValue bindingValue = (BindingValue) binding;
if (logger.isLoggable(Level.FINE)) {
logger.fine("Value selected: index=" + index + " list=" + list + " bindingValue=" + bindingValue);
}
BindingSelectorPanel.BindingColumnElement selectedValue = (BindingSelectorPanel.BindingColumnElement) list.getSelectedValue();
if (selectedValue == null) {
return;
}
if (index == 0 && selectedValue.getElement() instanceof BindingVariable) { // ICI
if (list.getSelectedValue() != bindingValue.getBindingVariable()) {
bindingValue.setBindingVariable((BindingVariable) selectedValue.getElement());
setEditedObject(bindingValue);
fireEditedObjectChanged();
}
} else {
if (selectedValue.getElement() instanceof SimplePathElement) {
// FIXED invalid type object comparison
if (selectedValue.getElement() != bindingValue.getBindingPathElementAtIndex(index - 1)) {
bindingValue.setBindingPathElementAtIndex(selectedValue.getElement(), index - 1);
setEditedObject(bindingValue);
fireEditedObjectChanged();
}
} else if (selectedValue.getElement() instanceof ComplexPathElement && editionMode == EditionMode.COMPOUND_BINDING) {
// TODO: we need to handle here generic ComplexPathElement and not only MethodCall
BindingPathElement currentElement = bindingValue.getBindingPathElementAtIndex(index - 1);
if (!(currentElement instanceof MethodCall)
|| ((MethodCall) currentElement).getMethod() != ((MethodDefinition) selectedValue.getElement()).getMethod()) {
Method method = ((MethodDefinition) selectedValue.getElement()).getMethod();
MethodCall newMethodCall = new MethodCall(bindingValue, method, bindingValue.getAccessedType());
bindingValue.setBindingPathElementAtIndex(newMethodCall, index - 1);
setEditedObject(bindingValue);
fireEditedObjectChanged();
}
}
}
}
boolean isAcceptableStaticBindingValue(String stringValue) {
if (getBindingDefinition() == null || getBindingDefinition().getType() == null) {
return false;
}
StaticBinding b = makeStaticBindingFromString(stringValue);
if (b == null) {
return false;
}
if (TypeUtils.isObject(getBindingDefinition().getType()) && !stringValue.endsWith(".")) {
return true;
}
if (TypeUtils.isBoolean(getBindingDefinition().getType())) {
return b instanceof BooleanStaticBinding;
} else if (TypeUtils.isInteger(getBindingDefinition().getType()) || TypeUtils.isLong(getBindingDefinition().getType())
|| TypeUtils.isShort(getBindingDefinition().getType()) || TypeUtils.isChar(getBindingDefinition().getType())
|| TypeUtils.isByte(getBindingDefinition().getType())) {
return b instanceof IntegerStaticBinding;
} else if (TypeUtils.isFloat(getBindingDefinition().getType()) || TypeUtils.isDouble(getBindingDefinition().getType())) {
if (stringValue.endsWith(".")) {
return false;
}
return b instanceof IntegerStaticBinding || b instanceof FloatStaticBinding;
} else if (TypeUtils.isString(getBindingDefinition().getType())) {
return b instanceof StringStaticBinding;
}
return false;
}
private boolean isAcceptableAsBeginningOfBooleanStaticBindingValue(String stringValue) {
if (stringValue.length() > 0) {
if (stringValue.length() <= 4 && "true".substring(0, stringValue.length()).equalsIgnoreCase(stringValue)) {
return true;
}
if (stringValue.length() <= 5 && "false".substring(0, stringValue.length()).equalsIgnoreCase(stringValue)) {
return true;
}
return false;
} else {
return true;
}
}
boolean isAcceptableAsBeginningOfStringStaticBindingValue(String stringValue) {
if (stringValue.length() > 0) {
if (stringValue.indexOf("\"") == 0 || stringValue.indexOf("'") == 0) {
return true;
}
return false;
} else {
return true;
}
}
boolean isAcceptableAsBeginningOfStaticBindingValue(String stringValue) {
// logger.info("isAcceptableAsBeginningOfStaticBindingValue for ? "+stringValue+" project="+getProject()+" bd="+getBindingDefinition());
if (getBindingDefinition() == null || getBindingDefinition().getType() == null) {
return false;
}
if (stringValue.length() == 0) {
return true;
}
if (TypeUtils.isObject(getBindingDefinition().getType())) {
// In this case, any of matching is enough
return isAcceptableStaticBindingValue(stringValue)
&& !stringValue.endsWith(".") // Special case to handle float on-the-fly
// typing
|| isAcceptableAsBeginningOfBooleanStaticBindingValue(stringValue)
|| isAcceptableAsBeginningOfStringStaticBindingValue(stringValue);
}
if (TypeUtils.isBoolean(getBindingDefinition().getType())) {
return isAcceptableAsBeginningOfBooleanStaticBindingValue(stringValue);
} else if (TypeUtils.isInteger(getBindingDefinition().getType()) || TypeUtils.isLong(getBindingDefinition().getType())
|| TypeUtils.isShort(getBindingDefinition().getType()) || TypeUtils.isChar(getBindingDefinition().getType())
|| TypeUtils.isByte(getBindingDefinition().getType())) {
return isAcceptableStaticBindingValue(stringValue);
} else if (TypeUtils.isFloat(getBindingDefinition().getType()) || TypeUtils.isDouble(getBindingDefinition().getType())) {
if (stringValue.endsWith(".") && stringValue.length() > 1) {
return isAcceptableStaticBindingValue(stringValue.substring(0, stringValue.length() - 1));
}
return isAcceptableStaticBindingValue(stringValue);
} else if (TypeUtils.isString(getBindingDefinition().getType())) {
return isAcceptableAsBeginningOfStringStaticBindingValue(stringValue);
}
return false;
}
StaticBinding makeStaticBindingFromString(String stringValue) {
if (getBindable() != null) {
StaticBindingFactory factory = getBindable().getBindingFactory().getStaticBindingFactory();
StaticBinding returned = factory.convertFromString(stringValue);
if (returned == null) {
return null;
}
returned.setOwner(getBindable());
returned.setBindingDefinition(getBindingDefinition());
return returned;
}
return null;
}
AbstractBinding makeBindingFromString(String stringValue) {
if (getBindable() != null) {
BindingFactory factory = getBindable().getBindingFactory();
if (factory == null) {
logger.info("OK, je tiens le probleme, factory=null");
logger.info("bindable=" + getBindable());
}
factory.setWarnOnFailure(false);
AbstractBinding returned = factory.convertFromString(stringValue, getBindable());
if (returned == null) {
return null;
}
returned.setOwner(getBindable());
returned.setBindingDefinition(getBindingDefinition());
factory.setWarnOnFailure(true);
return returned;
}
return null;
}
boolean textFieldSynchWithEditedObject() {
if (StringUtils.isEmpty(getTextField().getText())) {
return getEditedObject() == null || StringUtils.isEmpty(renderedString(getEditedObject()));
}
return getTextField().getText() != null && getTextField().getText().equals(renderedString(getEditedObject()));
}
boolean textFieldNotSynchWithEditedObject() {
return !textFieldSynchWithEditedObject();
}
@Override
public BindingSelector getJComponent() {
return this;
}
public static class TestBindable implements Bindable {
private BindingFactory bindingFactory = new DefaultBindingFactory();
private BindingModel bindingModel = new BindingModel();
public TestBindable() {
bindingModel.addToBindingVariables(new BindingVariableImpl(this, "aString", String.class));
bindingModel.addToBindingVariables(new BindingVariableImpl(this, "anInteger", Integer.class));
bindingModel.addToBindingVariables(new BindingVariableImpl(this, "aFloat", Float.TYPE));
}
@Override
public BindingModel getBindingModel() {
return bindingModel;
}
@Override
public BindingFactory getBindingFactory() {
return bindingFactory;
}
}
public static void main(String[] args) {
final JDialog dialog = new JDialog((Frame) null, false);
JButton closeButton = new JButton("Close");
closeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
System.exit(0);
}
});
JButton logButton = new JButton("Logs");
logButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
FlexoLoggingViewer.showLoggingViewer(FlexoLoggingManager.instance(), dialog);
}
});
Bindable testBindable = new TestBindable();
BindingDefinition bd = new BindingDefinition("testString", String.class, BindingDefinitionType.GET, true);
BindingFactory factory = new DefaultBindingFactory();
AbstractBinding binding = factory.convertFromString("aString", testBindable);
binding.setBindingDefinition(bd);
// AbstractBinding bv = operatorIF.getConditionPrimitive();
BindingSelector _selector = new BindingSelector(null) {
@Override
public void apply() {
super.apply();
System.out.println("Apply, getEditedObject()=" + getEditedObject());
}
@Override
public void cancel() {
super.cancel();
System.out.println("Cancel, getEditedObject()=" + getEditedObject());
}
};
_selector.setBindable(testBindable);
_selector.setBindingDefinition(bd);
_selector.setEditedObject(binding);
_selector.setRevertValue(binding.clone());
JPanel panel = new JPanel(new VerticalLayout());
panel.add(_selector);
panel.add(closeButton);
panel.add(logButton);
dialog.setPreferredSize(new Dimension(550, 600));
dialog.getContentPane().add(panel);
dialog.pack();
dialog.setVisible(true);
}
}