/* * (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.model; import java.awt.event.MouseEvent; import java.lang.reflect.Type; import java.util.Enumeration; import java.util.List; import javax.swing.Icon; import javax.swing.tree.TreeNode; import org.openflexo.antar.binding.Bindable; import org.openflexo.antar.binding.BindingDefinition; import org.openflexo.antar.binding.BindingDefinition.BindingDefinitionType; import org.openflexo.antar.binding.BindingModel; import org.openflexo.antar.binding.BindingVariableImpl; import org.openflexo.antar.binding.ParameterizedTypeImpl; import org.openflexo.fib.controller.FIBComponentDynamicModel; import org.openflexo.fib.model.validation.FixProposal; import org.openflexo.fib.model.validation.ValidationIssue; import org.openflexo.fib.model.validation.ValidationReport; import org.openflexo.fib.model.validation.ValidationRule; import org.openflexo.fib.model.validation.ValidationWarning; import org.openflexo.toolbox.StringUtils; public abstract class FIBWidget extends FIBComponent { public static final BindingDefinition TOOLTIP = new BindingDefinition("tooltip", String.class, BindingDefinitionType.GET, false); public static final BindingDefinition ENABLE = new BindingDefinition("enable", Boolean.class, BindingDefinitionType.GET, false); public static final BindingDefinition FORMAT = new BindingDefinition("format", String.class, BindingDefinitionType.GET, false); public static final BindingDefinition ICON = new BindingDefinition("icon", Icon.class, BindingDefinitionType.GET, false); public static final BindingDefinition VALUE_VALIDATOR = new BindingDefinition("valueValidator", Boolean.class, BindingDefinitionType.GET, false); public static final BindingDefinition VALUE_CHANGED_ACTION = new BindingDefinition("valueChangedAction", Void.class, BindingDefinitionType.EXECUTE, false); public static final BindingDefinition CLICK_ACTION = new BindingDefinition("clickAction", Void.class, BindingDefinitionType.EXECUTE, false); public static final BindingDefinition DOUBLE_CLICK_ACTION = new BindingDefinition("doubleClickAction", Void.class, BindingDefinitionType.EXECUTE, false); public static final BindingDefinition RIGHT_CLICK_ACTION = new BindingDefinition("rightClickAction", Void.class, BindingDefinitionType.EXECUTE, false); public static final BindingDefinition ENTER_PRESSED_ACTION = new BindingDefinition("enterPressedAction", Void.class, BindingDefinitionType.EXECUTE, false); public static enum Parameters implements FIBModelAttribute { enable, format, icon, tooltip, tooltipText, localize, manageDynamicModel, readOnly, clickAction, doubleClickAction, rightClickAction, enterPressedAction, valueChangedAction, valueTransform, valueValidator } private DataBinding tooltip; private DataBinding enable; private DataBinding format; private DataBinding icon; private Boolean manageDynamicModel = false; private Boolean readOnly = false; private Boolean localize = true; private String tooltipText; private DataBinding clickAction; private DataBinding doubleClickAction; private DataBinding rightClickAction; private DataBinding enterPressedAction; private DataBinding valueChangedAction; private DataBinding valueValidator; private BindingDefinition VALUE_TRANSFORMER; private final FIBFormatter formatter; private final FIBValueBindable valueBindable; private final FIBEventListener eventListener; private DataBinding valueTransform; public FIBWidget() { super(); formatter = new FIBFormatter(); valueBindable = new FIBValueBindable(); eventListener = new FIBEventListener(); } @Override public String getIdentifier() { return null; } @Override public Enumeration children() { return null; } @Override public boolean getAllowsChildren() { return false; } @Override public TreeNode getChildAt(int childIndex) { return null; } @Override public int getChildCount() { return 0; } @Override public int getIndex(TreeNode node) { return -1; } @Override public boolean isLeaf() { return true; } public DataBinding getTooltip() { if (tooltip == null) { tooltip = new DataBinding(this, Parameters.tooltip, TOOLTIP); } return tooltip; } public void setTooltip(DataBinding tooltip) { tooltip.setOwner(this); tooltip.setBindingAttribute(Parameters.tooltip); tooltip.setBindingDefinition(TOOLTIP); this.tooltip = tooltip; } public DataBinding getEnable() { if (enable == null) { enable = new DataBinding(this, Parameters.enable, ENABLE); } return enable; } public void setEnable(DataBinding enable) { enable.setOwner(this); enable.setBindingAttribute(Parameters.enable); enable.setBindingDefinition(ENABLE); this.enable = enable; } @Override public void finalizeDeserialization() { super.finalizeDeserialization(); getEventListener().createEventListenerBindingModel(); if (enable != null) { enable.finalizeDeserialization(); } if (format != null) { format.finalizeDeserialization(); } if (icon != null) { icon.finalizeDeserialization(); } if (tooltip != null) { tooltip.finalizeDeserialization(); } if (clickAction != null) { clickAction.finalizeDeserialization(); } if (doubleClickAction != null) { doubleClickAction.finalizeDeserialization(); } if (rightClickAction != null) { rightClickAction.finalizeDeserialization(); } if (enterPressedAction != null) { enterPressedAction.finalizeDeserialization(); } if (valueChangedAction != null) { valueChangedAction.finalizeDeserialization(); } if (valueTransform != null) { valueTransform.finalizeDeserialization(); } if (valueValidator != null) { valueValidator.finalizeDeserialization(); } } @Override public Type getDataType() { if (getData() != null && getData().getBinding() != null) { return getData().getBinding().getAccessedType(); } return getDefaultDataClass(); } @Override public abstract Type getDefaultDataClass(); // Default behaviour: only data is managed @Override public Type getDynamicAccessType() { if (getManageDynamicModel()) { if (getData() != null && getData().isSet()) { return super.getDynamicAccessType(); } else { Type[] args = new Type[1]; args[0] = getDataType(); return new ParameterizedTypeImpl(FIBComponentDynamicModel.class, args); } } return null; } public Boolean getManageDynamicModel() { return manageDynamicModel; } public void setManageDynamicModel(Boolean manageDynamicModel) { FIBAttributeNotification<Boolean> notification = requireChange(Parameters.manageDynamicModel, manageDynamicModel); if (notification != null) { this.manageDynamicModel = manageDynamicModel; updateBindingModel(); hasChanged(notification); } } public Boolean getReadOnly() { return readOnly; } public void setReadOnly(Boolean readOnly) { FIBAttributeNotification<Boolean> notification = requireChange(Parameters.readOnly, readOnly); if (notification != null) { this.readOnly = readOnly; hasChanged(notification); } } public String getTooltipText() { return tooltipText; } public void setTooltipText(String tooltipText) { FIBAttributeNotification<String> notification = requireChange(Parameters.tooltipText, tooltipText); if (notification != null) { this.tooltipText = tooltipText; hasChanged(notification); } } @Override public void setDataClass(Class<?> dataClass) { super.setDataClass(dataClass); VALUE_TRANSFORMER = null; getValueTransform().setBindingDefinition(getValueTransformBindingDefinition()); } public DataBinding getValueTransform() { if (valueTransform == null) { valueTransform = new DataBinding(valueBindable, Parameters.valueTransform, getValueTransformBindingDefinition()); } return valueTransform; } public void setValueTransform(DataBinding valueTransform) { FIBAttributeNotification<DataBinding> notification = requireChange(Parameters.valueTransform, valueTransform); if (notification != null) { valueTransform.setOwner(valueBindable); valueTransform.setBindingAttribute(Parameters.valueTransform); valueTransform.setBindingDefinition(getValueTransformBindingDefinition()); this.valueTransform = valueTransform; hasChanged(notification); } } public BindingDefinition getValueTransformBindingDefinition() { if (VALUE_TRANSFORMER == null) { VALUE_TRANSFORMER = new BindingDefinition("valueTransform", getDataType(), BindingDefinitionType.GET, false); } return VALUE_TRANSFORMER; } public FIBValueBindable getValueBindable() { return valueBindable; } public DataBinding getFormat() { if (format == null) { format = new DataBinding(formatter, Parameters.format, FORMAT); } return format; } public void setFormat(DataBinding format) { FIBAttributeNotification<DataBinding> notification = requireChange(Parameters.format, format); if (notification != null) { format.setOwner(formatter); format.setBindingAttribute(Parameters.format); format.setBindingDefinition(FORMAT); this.format = format; hasChanged(notification); } } public DataBinding getIcon() { if (icon == null) { icon = new DataBinding(formatter, Parameters.icon, ICON); } return icon; } public void setIcon(DataBinding icon) { FIBAttributeNotification<DataBinding> notification = requireChange(Parameters.icon, icon); if (notification != null) { icon.setOwner(formatter); icon.setBindingAttribute(Parameters.icon); icon.setBindingDefinition(ICON); this.icon = icon; hasChanged(notification); } } public Boolean getLocalize() { return localize; } public void setLocalize(Boolean localize) { FIBAttributeNotification<Boolean> notification = requireChange(Parameters.localize, localize); if (notification != null) { this.localize = localize; hasChanged(notification); } } public FIBFormatter getFormatter() { return formatter; } public Type getFormattedObjectType() { return getDataType(); } private class FIBFormatter extends FIBModelObject implements Bindable { private BindingModel formatterBindingModel = null; @Override public BindingModel getBindingModel() { if (formatterBindingModel == null) { createFormatterBindingModel(); } return formatterBindingModel; } private void createFormatterBindingModel() { formatterBindingModel = new BindingModel(FIBWidget.this.getBindingModel()); formatterBindingModel.addToBindingVariables(new BindingVariableImpl<Object>(this, "object", Object.class) { @Override public Type getType() { return getFormattedObjectType(); } }); } @Override public FIBComponent getRootComponent() { return FIBWidget.this.getRootComponent(); } @Override public String toString() { if (FIBWidget.this instanceof FIBDropDown) { return "FIBFormatter[" + FIBWidget.this + "] iteratorClass=" + ((FIBDropDown) FIBWidget.this).getIteratorClass() + " dataType=" + ((FIBDropDown) FIBWidget.this).getDataType() + " obtained from " + ((FIBDropDown) FIBWidget.this).getDescription(); } return "FIBFormatter[" + FIBWidget.this + "]" + " dataType=" + FIBWidget.this.getDataType(); } @Override public void notifyBindingChanged(DataBinding binding) { if (binding == getFormat()) { FIBWidget.this.notifyBindingChanged(binding); } super.notifyBindingChanged(binding); } @Override public List<? extends FIBModelObject> getEmbeddedObjects() { return null; } } private class FIBValueBindable extends FIBModelObject implements Bindable { private BindingModel valueTransformerBindingModel = null; @Override public BindingModel getBindingModel() { if (valueTransformerBindingModel == null) { createValueTransformerBindingModel(); } return valueTransformerBindingModel; } private void createValueTransformerBindingModel() { valueTransformerBindingModel = new BindingModel(FIBWidget.this.getBindingModel()); valueTransformerBindingModel.addToBindingVariables(new BindingVariableImpl<Object>(this, "value", Object.class) { @Override public Type getType() { return getDataType(); } }); } @Override public FIBComponent getRootComponent() { return FIBWidget.this.getRootComponent(); } @Override public String toString() { if (FIBWidget.this instanceof FIBDropDown) { return "FIBValueBindable[" + FIBWidget.this + "] iteratorClass=" + ((FIBDropDown) FIBWidget.this).getIteratorClass() + " dataType=" + ((FIBDropDown) FIBWidget.this).getDataType() + " obtained from " + ((FIBDropDown) FIBWidget.this).getDescription(); } return "FIBValueBindable[" + FIBWidget.this + "]" + " dataType=" + FIBWidget.this.getDataType(); } @Override public void notifyBindingChanged(DataBinding binding) { if (binding == getValueTransform()) { FIBWidget.this.notifyBindingChanged(binding); } else if (binding == getValueValidator()) { FIBWidget.this.notifyBindingChanged(binding); } super.notifyBindingChanged(binding); } @Override public List<? extends FIBModelObject> getEmbeddedObjects() { return null; } } @Override public void updateBindingModel() { super.updateBindingModel(); if (deserializationPerformed) { getEventListener().createEventListenerBindingModel(); getFormatter().createFormatterBindingModel(); } } public FIBEventListener getEventListener() { return eventListener; } private class FIBEventListener extends FIBModelObject implements Bindable { private BindingModel eventListenerBindingModel = null; @Override public BindingModel getBindingModel() { if (eventListenerBindingModel == null) { createEventListenerBindingModel(); } return eventListenerBindingModel; } private void createEventListenerBindingModel() { eventListenerBindingModel = new BindingModel(FIBWidget.this.getBindingModel()); eventListenerBindingModel.addToBindingVariables(new BindingVariableImpl<Object>(this, "event", MouseEvent.class)); } @Override public FIBComponent getRootComponent() { return FIBWidget.this.getRootComponent(); } @Override public String toString() { return "FIBEventListener[" + FIBWidget.this + "]"; } @Override public void notifyBindingChanged(DataBinding binding) { if (binding == getClickAction() || binding == getDoubleClickAction() || binding == getRightClickAction()) { FIBWidget.this.notifyBindingChanged(binding); } super.notifyBindingChanged(binding); } @Override public List<? extends FIBModelObject> getEmbeddedObjects() { return null; } } public DataBinding getValueValidator() { if (valueValidator == null) { valueValidator = new DataBinding(this, Parameters.valueValidator, VALUE_VALIDATOR); } return valueValidator; } public void setValueValidator(DataBinding valueValidator) { valueValidator.setOwner(this); valueValidator.setBindingAttribute(Parameters.valueValidator); valueValidator.setBindingDefinition(VALUE_VALIDATOR); this.valueValidator = valueValidator; } public DataBinding getValueChangedAction() { if (valueChangedAction == null) { valueChangedAction = new DataBinding(this, Parameters.valueChangedAction, VALUE_CHANGED_ACTION); } return valueChangedAction; } public void setValueChangedAction(DataBinding valueChangedAction) { valueChangedAction.setOwner(this); valueChangedAction.setBindingAttribute(Parameters.valueChangedAction); valueChangedAction.setBindingDefinition(VALUE_CHANGED_ACTION); this.valueChangedAction = valueChangedAction; } public boolean hasClickAction() { return clickAction != null && clickAction.isValid(); } public final DataBinding getClickAction() { if (clickAction == null) { clickAction = new DataBinding(eventListener, Parameters.clickAction, CLICK_ACTION); } return clickAction; } public final void setClickAction(DataBinding clickAction) { clickAction.setOwner(eventListener); clickAction.setBindingAttribute(Parameters.clickAction); clickAction.setBindingDefinition(CLICK_ACTION); this.clickAction = clickAction; } public boolean hasDoubleClickAction() { return doubleClickAction != null && doubleClickAction.isValid(); } public DataBinding getDoubleClickAction() { if (doubleClickAction == null) { doubleClickAction = new DataBinding(eventListener, Parameters.doubleClickAction, DOUBLE_CLICK_ACTION); } return doubleClickAction; } public void setDoubleClickAction(DataBinding doubleClickAction) { doubleClickAction.setOwner(eventListener); doubleClickAction.setBindingAttribute(Parameters.doubleClickAction); doubleClickAction.setBindingDefinition(DOUBLE_CLICK_ACTION); this.doubleClickAction = doubleClickAction; } public boolean hasRightClickAction() { return rightClickAction != null && rightClickAction.isValid(); } public DataBinding getRightClickAction() { if (rightClickAction == null) { rightClickAction = new DataBinding(eventListener, Parameters.rightClickAction, RIGHT_CLICK_ACTION); } return rightClickAction; } public void setRightClickAction(DataBinding rightClickAction) { rightClickAction.setOwner(eventListener); rightClickAction.setBindingAttribute(Parameters.rightClickAction); rightClickAction.setBindingDefinition(RIGHT_CLICK_ACTION); this.rightClickAction = rightClickAction; } public boolean hasEnterPressedAction() { return enterPressedAction != null && enterPressedAction.isValid(); } public DataBinding getEnterPressedAction() { if (enterPressedAction == null) { enterPressedAction = new DataBinding(this, Parameters.enterPressedAction, ENTER_PRESSED_ACTION); } return enterPressedAction; } public void setEnterPressedAction(DataBinding enterPressedAction) { enterPressedAction.setOwner(this); enterPressedAction.setBindingAttribute(Parameters.enterPressedAction); enterPressedAction.setBindingDefinition(ENTER_PRESSED_ACTION); this.enterPressedAction = enterPressedAction; } public boolean isPaletteElement() { return getParameter("isPaletteElement") != null && getParameter("isPaletteElement").equalsIgnoreCase("true"); } @Override public List<? extends FIBModelObject> getEmbeddedObjects() { return null; } @Override protected void applyValidation(ValidationReport report) { super.applyValidation(report); performValidation(FIBWidgetDeclaredAsDynamicShouldHaveAName.class, report); performValidation(TooltipBindingMustBeValid.class, report); performValidation(EnableBindingMustBeValid.class, report); performValidation(FormatBindingMustBeValid.class, report); performValidation(IconBindingMustBeValid.class, report); performValidation(ClickActionBindingMustBeValid.class, report); performValidation(DoubleClickActionBindingMustBeValid.class, report); performValidation(RightClickActionBindingMustBeValid.class, report); performValidation(ValueChangeActionBindingMustBeValid.class, report); } public static class FIBWidgetDeclaredAsDynamicShouldHaveAName extends ValidationRule<FIBWidgetDeclaredAsDynamicShouldHaveAName, FIBWidget> { public FIBWidgetDeclaredAsDynamicShouldHaveAName() { super(FIBWidget.class, "widgets_declaring_managing_dynamic_model_should_have_a_name"); } @Override public ValidationIssue<FIBWidgetDeclaredAsDynamicShouldHaveAName, FIBWidget> applyValidation(FIBWidget object) { if (object.getManageDynamicModel() && StringUtils.isEmpty(object.getName())) { GenerateDefaultName fixProposal1 = new GenerateDefaultName(); DisableDynamicModelManagement fixProposal2 = new DisableDynamicModelManagement(); return new ValidationWarning<FIBWidgetDeclaredAsDynamicShouldHaveAName, FIBWidget>(this, object, "widget_($object.toString)_declares_managing_dynamic_model_but_does_not_have_a_name", fixProposal1, fixProposal2); } return null; } protected static class GenerateDefaultName extends FixProposal<FIBWidgetDeclaredAsDynamicShouldHaveAName, FIBWidget> { public GenerateDefaultName() { super("generate_default_name_:_($defaultName)"); } @Override protected void fixAction() { getObject().setName(getDefaultName()); } public String getDefaultName() { return getObject().generateUniqueName(getObject().getBaseName()); } } protected static class DisableDynamicModelManagement extends FixProposal<FIBWidgetDeclaredAsDynamicShouldHaveAName, FIBWidget> { public DisableDynamicModelManagement() { super("disable_dynamic_model_management"); } @Override protected void fixAction() { getObject().setManageDynamicModel(false); } } } public static class TooltipBindingMustBeValid extends BindingMustBeValid<FIBWidget> { public TooltipBindingMustBeValid() { super("'tooltip'_binding_is_not_valid", FIBWidget.class); } @Override public DataBinding getBinding(FIBWidget object) { return object.getTooltip(); } @Override public BindingDefinition getBindingDefinition(FIBWidget object) { return TOOLTIP; } } public static class EnableBindingMustBeValid extends BindingMustBeValid<FIBWidget> { public EnableBindingMustBeValid() { super("'enable'_binding_is_not_valid", FIBWidget.class); } @Override public DataBinding getBinding(FIBWidget object) { return object.getEnable(); } @Override public BindingDefinition getBindingDefinition(FIBWidget object) { return ENABLE; } } public static class FormatBindingMustBeValid extends BindingMustBeValid<FIBWidget> { public FormatBindingMustBeValid() { super("'format'_binding_is_not_valid", FIBWidget.class); } @Override public DataBinding getBinding(FIBWidget object) { return object.getFormat(); } @Override public BindingDefinition getBindingDefinition(FIBWidget object) { return FORMAT; } } public static class IconBindingMustBeValid extends BindingMustBeValid<FIBWidget> { public IconBindingMustBeValid() { super("'icon'_binding_is_not_valid", FIBWidget.class); } @Override public DataBinding getBinding(FIBWidget object) { return object.getIcon(); } @Override public BindingDefinition getBindingDefinition(FIBWidget object) { return ICON; } } public static class ClickActionBindingMustBeValid extends BindingMustBeValid<FIBWidget> { public ClickActionBindingMustBeValid() { super("'click_action'_binding_is_not_valid", FIBWidget.class); } @Override public DataBinding getBinding(FIBWidget object) { return object.getClickAction(); } @Override public BindingDefinition getBindingDefinition(FIBWidget object) { return CLICK_ACTION; } } public static class DoubleClickActionBindingMustBeValid extends BindingMustBeValid<FIBWidget> { public DoubleClickActionBindingMustBeValid() { super("'double_click_action'_binding_is_not_valid", FIBWidget.class); } @Override public DataBinding getBinding(FIBWidget object) { return object.getDoubleClickAction(); } @Override public BindingDefinition getBindingDefinition(FIBWidget object) { return DOUBLE_CLICK_ACTION; } } public static class RightClickActionBindingMustBeValid extends BindingMustBeValid<FIBWidget> { public RightClickActionBindingMustBeValid() { super("'right_click_action'_binding_is_not_valid", FIBWidget.class); } @Override public DataBinding getBinding(FIBWidget object) { return object.getRightClickAction(); } @Override public BindingDefinition getBindingDefinition(FIBWidget object) { return RIGHT_CLICK_ACTION; } } public static class ValueChangeActionBindingMustBeValid extends BindingMustBeValid<FIBWidget> { public ValueChangeActionBindingMustBeValid() { super("'value_change_acion'_binding_is_not_valid", FIBWidget.class); } @Override public DataBinding getBinding(FIBWidget object) { return object.getValueChangedAction(); } @Override public BindingDefinition getBindingDefinition(FIBWidget object) { return VALUE_CHANGED_ACTION; } } }