/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.ui.ridgets.uibinding; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.eclipse.riena.core.util.ReflectionFailure; import org.eclipse.riena.core.wire.Wire; import org.eclipse.riena.internal.ui.ridgets.Activator; import org.eclipse.riena.ui.common.IComplexComponent; import org.eclipse.riena.ui.ridgets.IComplexRidget; import org.eclipse.riena.ui.ridgets.ILabelRidget; import org.eclipse.riena.ui.ridgets.IRidget; import org.eclipse.riena.ui.ridgets.IRidgetContainer; import org.eclipse.riena.ui.ridgets.SubModuleUtils; /** * This class manages the binding between UI-control and ridget. In contrast to the {@link InjectBindingManager} which calls a setter method for each ridget * immediately after ridget creation and addition to the {@link IRidgetContainer} managed ridget collection this {@link IBindingManager} implementation only * calls the method {@link IInjectAllRidgets#configureRidgets()} once. Therefore the {@link IRidgetContainer} is required to interface {@link IInjectAllRidgets} * if using this binding policy. The binding policy is configured in the view to be bound. */ public class DefaultBindingManager implements IBindingManager { private final IBindingPropertyLocator propertyStrategy; private final IControlRidgetMapper<Object> mapper; /** * Creates the managers of all bindings of a view. * * @param propertyStrategy * strategy to get the property for the binding from the UI-control. * @param mapper * mapping for UI control-classes to ridget-classes */ public DefaultBindingManager(final IBindingPropertyLocator propertyStrategy, final IControlRidgetMapper<Object> mapper) { this.propertyStrategy = propertyStrategy; this.mapper = mapper; } public void injectRidgets(final IRidgetContainer ridgetContainer, final List<Object> uiControls) { final CorrespondingLabelMapper ridgetMapper = new CorrespondingLabelMapper(ridgetContainer); if (Activator.getDefault() != null) { Wire.instance(ridgetMapper).andStart(Activator.getDefault().getContext()); } final Map<String, IRidget> controls = new HashMap<String, IRidget>(); for (final Object control : uiControls) { final String bindingProperty = propertyStrategy.locateBindingProperty(control); if (bindingProperty != null) { IRidget ridget = null; if (!SubModuleUtils.isPrepareView()) { final String id = propertyStrategy.getComplexBindingId(control); if (id != null) { ridget = getPreparedRidget(ridgetContainer, id); } } if (ridget == null) { if (!SubModuleUtils.isPrepareView()) { ridget = ridgetContainer.getRidget(bindingProperty); } } if (ridget == null) { ridget = createRidget(control); } injectRidget(ridgetContainer, bindingProperty, ridget); //because the ridgets are not bound yet, we have to save the bindingProperty separately if (!(ridget instanceof ILabelRidget)) { controls.put(bindingProperty, ridget); } if (control instanceof IComplexComponent) { final IComplexRidget complexRidget = (IComplexRidget) ridget; final IComplexComponent complexComponent = (IComplexComponent) control; injectRidgets(complexRidget, complexComponent.getUIControls()); } } } // iterate over all controls that are not ILabelRidgets and try to connect // them with their corresponding Label final Iterator<Entry<String, IRidget>> it = controls.entrySet().iterator(); while (it.hasNext()) { final Entry<String, IRidget> entry = it.next(); ridgetMapper.connectCorrespondingLabel(entry.getValue(), entry.getKey()); } if (Activator.getDefault() != null) { // TODO This unveils a weakness of the wiring stuff because the dependency (to the wiring) is just moved the ridget containers to here :-( Wire.instance(ridgetContainer).andStart(Activator.getDefault().getContext()); } if (!ridgetContainer.isConfigured() || SubModuleUtils.isPrepareView()) { ridgetContainer.configureRidgets(); ridgetContainer.setConfigured(true); } } /** * Returns an already created Ridget that is a child of a complex Ridget. * <p> * The Ridget will be removed from the former parent container. * * @param ridgetContainer * @param id * complex ID of the UI control * @return already created Ridget */ private IRidget getPreparedRidget(final IRidgetContainer ridgetContainer, final String id) { if (id.indexOf('.') == -1) { return null; } if (ridgetContainer instanceof IComplexRidget) { final IComplexRidget complexRidget = (IComplexRidget) ridgetContainer; final IRidgetContainer parent = complexRidget.getController(); if (parent == null) { return null; } IRidget ridget = parent.getRidget(id); if (ridget == null) { ridget = getPreparedRidget(parent, id); } if (ridget != null) { parent.removeRidget(id); return ridget; } } return null; } /** * Injects the given ridget into the given container.<br> * Adds the ridget to the container. * * @param ridgetContainer * @param bindingProperty * @param ridget * ridget to inject */ protected void injectRidget(final IRidgetContainer ridgetContainer, final String bindingProperty, final IRidget ridget) { ridgetContainer.addRidget(bindingProperty, ridget); ridget.setController(ridgetContainer); } /** * Creates for the given UI-control the appropriate ridget. * * @param control * UI-control * @return ridget * @throws ReflectionFailure */ public IRidget createRidget(final Object control) throws ReflectionFailure { final Class<? extends IRidget> ridgetClass = mapper.getRidgetClass(control); try { return ridgetClass.newInstance(); } catch (final Exception e) { throw new ReflectionFailure(String.format("Could not instantiate ridget '%s' for control '%s'", //$NON-NLS-1$ ridgetClass, control), e); } } /** * Returns form the given ridget container the ridget with the given property value. * * @param bindingProperty * value of the binding property * @param controller * ridget container * @return ridget */ protected <R extends IRidget> R getRidget(final String bindingProperty, final IRidgetContainer controller) { return controller.getRidget(bindingProperty); } /** * @see org.eclipse.riena.ui.internal.ridgets.uibinding.IBindingManager#bind(IRidgetContainer, java.util.List) */ public void bind(final IRidgetContainer controller, final List<Object> uiControls) { updateBindings(controller, uiControls, false); } /** * @see org.eclipse.riena.ui.internal.ridgets.uibinding.IBindingManager#unbind(IRidgetContainer, java.util.List) */ public void unbind(final IRidgetContainer controller, final List<Object> uiControls) { updateBindings(controller, uiControls, true); } private void updateBindings(final IRidgetContainer controller, final List<Object> uiControls, final boolean unbind) { for (final Object control : uiControls) { final String bindingProperty = propertyStrategy.locateBindingProperty(control); if (bindingProperty == null) { continue; } if (control instanceof IComplexComponent) { final IComplexComponent complexComponent = (IComplexComponent) control; final IComplexRidget complexRidget = getRidget(bindingProperty, controller); if (complexRidget != null) { updateBindings(complexRidget, complexComponent.getUIControls(), unbind); bindRidget(complexRidget, complexComponent, unbind); } } else { final IRidget ridget = getRidget(bindingProperty, controller); if (ridget != null) { bindRidget(ridget, control, unbind); } } } } private void bindRidget(final IRidget ridget, final Object uiControl, final boolean unbind) { if (unbind) { ridget.setUIControl(null); } else { ridget.setUIControl(uiControl); } } }