/******************************************************************************* * 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; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.osgi.service.log.LogService; import org.eclipse.core.databinding.BindingException; import org.eclipse.core.runtime.Assert; import org.eclipse.equinox.log.Logger; import org.eclipse.riena.core.Log4r; import org.eclipse.riena.core.RienaStatus; import org.eclipse.riena.internal.ui.ridgets.Activator; /** * Default implementation of the {@link IComplexRidget} interface. * <p> * Implementors may extend this class instead from starting from scratch. */ public abstract class AbstractCompositeRidget extends AbstractRidget implements IComplexRidget { private final static Logger LOGGER = Log4r.getLogger(Activator.getDefault(), AbstractCompositeRidget.class); /** * @see ComplexRidgetResolver * @see SimpleRidgetResolver */ private IRidgetResolver ridgetResolver = new ComplexRidgetResolver(); private final PropertyChangeListener propertyChangeListener; private final Map<String, IRidget> ridgets; private Object uiControl; private boolean markedHidden; private boolean enabled; private boolean configured = false; private String toolTip = null; private final RidgetToStatuslineSubscriber ridgetToStatuslineSubscriber = new RidgetToStatuslineSubscriber(); /** * Constructor */ public AbstractCompositeRidget() { super(); propertyChangeListener = new PropertyChangeHandler(); ridgets = new HashMap<String, IRidget>(); enabled = true; } public void addRidget(final String id, final IRidget ridget) { final IRidget oldRidget = getRidgetResolver().addRidget(id, ridget, this, ridgets); if (null == oldRidget) { ridget.addPropertyChangeListener(propertyChangeListener); } else { ridgetToStatuslineSubscriber.removeRidget(oldRidget); } ridgetToStatuslineSubscriber.addRidget(ridget); } /** * @since 5.0 */ public boolean removeRidget(final String id) { ridgetToStatuslineSubscriber.removeRidget(getRidget(id)); return getRidgetResolver().removeRidget(id, ridgets) != null; } /** * @since 5.0 */ public void setStatuslineToShowMarkerMessages(final IStatuslineRidget statuslineToShowMarkerMessages) { ridgetToStatuslineSubscriber.setStatuslineToShowMarkerMessages(statuslineToShowMarkerMessages, getRidgets()); } /** * @since 4.0 */ public String idOfRidget(final IRidget ridget) { for (final String ridgetId : ridgets.keySet()) { if (ridgets.get(ridgetId) == ridget) { return ridgetId; } } return null; } /** * {@inheritDoc} * <p> * The default implementation is empty. Implementors may extend to configure (sub)-ridgets injected into this {@link IComplexRidget}. */ public void configureRidgets() { // implementors may extend } /** * {@inheritDoc} * <p> * Always returns null. Implementors should override. */ public String getID() { return null; } public <R extends IRidget> R getRidget(final String id) { return (R) getRidgetResolver().getRidget(id, ridgets); } /** * @since 2.0 */ public <R extends IRidget> R getRidget(final Class<R> ridgetClazz, final String id) { R ridget = getRidget(id); if (ridget != null) { if (!ridgetClazz.isInstance(ridget)) { String logMessage = "getRidget(Class, String): Actual ridget (id: "; //$NON-NLS-1$ logMessage += id; logMessage += ")"; //$NON-NLS-1$ logMessage += " in this composite (id: "; //$NON-NLS-1$ logMessage += getID(); logMessage += ")"; //$NON-NLS-1$ logMessage += " is not of desired type: ridget is "; //$NON-NLS-1$ logMessage += ridget.getClass().getName(); logMessage += ", desired is "; //$NON-NLS-1$ logMessage += ridgetClazz.getName(); LOGGER.log(LogService.LOG_ERROR, logMessage); } return ridget; } if (allowRidgetCreation()) { try { if (ridgetClazz.isInterface() || Modifier.isAbstract(ridgetClazz.getModifiers())) { final Class<R> mappedRidgetClazz = (Class<R>) ClassRidgetMapper.getInstance().getRidgetClass(ridgetClazz); if (mappedRidgetClazz != null) { ridget = mappedRidgetClazz.newInstance(); } Assert.isNotNull(ridget, "Could not find a corresponding implementation for " + ridgetClazz.getName() + " in " + ClassRidgetMapper.class.getName()); //$NON-NLS-1$ //$NON-NLS-2$ } else { ridget = ridgetClazz.newInstance(); } } catch (final InstantiationException e) { throw new RuntimeException(e); } catch (final IllegalAccessException e) { throw new RuntimeException(e); } addRidget(id, ridget); } return ridget; } /** * @since 3.0 */ protected boolean allowRidgetCreation() { return RienaStatus.isTest() || !SubModuleUtils.isPrepareView(); } public Collection<? extends IRidget> getRidgets() { return new ArrayList<IRidget>(ridgets.values()); } public String getToolTipText() { return toolTip; } public Object getUIControl() { return uiControl; } public boolean hasFocus() { final Collection<? extends IRidget> myRidgets = getRidgets(); for (final IRidget ridget : myRidgets) { if (ridget.hasFocus()) { return true; } } return false; } public boolean isEnabled() { return enabled; } public boolean isFocusable() { return null != getFirstFocusableRidget(); } public boolean isVisible() { // check for "hidden.marker". This marker overrules any other visibility rule if (markedHidden) { return false; } if (getUIControl() != null) { // the swt control is bound return isUIControlVisible(); } // control is not bound return savedVisibleState; } public void requestFocus() { final IRidget firstFocusableRidget = getFirstFocusableRidget(); if (null != firstFocusableRidget) { firstFocusableRidget.requestFocus(); } } private IRidget getFirstFocusableRidget() { for (final IRidget ridget : getRidgets()) { if (ridget.isFocusable() && ridget.isEnabled()) { if (ridget instanceof IMarkableRidget && ((IMarkableRidget) ridget).isOutputOnly()) { continue; } if (ridget instanceof ILabelRidget) { continue; } if (ridget instanceof IStatusMeterRidget) { continue; } return ridget; } } return null; } public void setEnabled(final boolean enabled) { if (this.enabled != enabled) { this.enabled = enabled; updateEnabled(); if (enabled) { updateMarkersOfChildRidgets(); } } } private void updateMarkersOfChildRidgets() { for (final IRidget ridget : getRidgets()) { if (ridget instanceof IMarkableRidget) { ((IMarkableRidget) ridget).updateMarkers(); } } } public void setFocusable(final boolean focusable) { for (final IRidget ridget : getRidgets()) { ridget.setFocusable(focusable); } } public void setToolTipText(final String toolTipText) { final String oldValue = toolTip; toolTip = toolTipText; updateToolTipText(); firePropertyChange(IRidget.PROPERTY_TOOLTIP, oldValue, toolTip); } public void setUIControl(final Object uiControl) { checkUIControl(uiControl); unbindUIControl(); // save state this.savedVisibleState = getUIControl() != null ? isUIControlVisible() : savedVisibleState; this.uiControl = uiControl; updateVisible(); updateEnabled(); updateToolTipText(); bindUIControl(); } public void setVisible(final boolean visible) { if (this.markedHidden == visible) { this.markedHidden = !visible; updateVisible(); } } /** * Bind the current <tt>uiControl</tt> to the ridget. * <p> * Implementors must call {@link #getUIControl()} to obtain the current control. If the control is non-null they must do whatever necessary to bind it to * the ridget. * * @since 1.2 */ protected void bindUIControl() { // implementors should overwrite } /** * Performs checks on the control about to be bound by this ridget. * <p> * Implementors must make sure the given <tt>uiControl</tt> has the expected type. * * @param uiControl * a {@link Widget} instance or null * @throws BindingException * if the <tt>uiControl</tt> fails the check * @since 1.2 */ protected void checkUIControl(final Object uiControl) { // implementors should overwrite } @Override public void updateFromModel() { super.updateFromModel(); //delegate to inner ridgets for (final IRidget ridget : ridgets.values()) { ridget.updateFromModel(); } } /** * Returns true if the ridget is marked as hidden (visible = false). Note: this reflects the ridget state, not the control state. The ridget may not have * control yet. * * @since 2.0 */ protected final boolean isMarkedHidden() { return markedHidden; } /** * Returns true if the control of this ridget is visible, false otherwise. This default implementation always returns true and should be overridden by * subclasses. * <p> * Note: this will only be called when the UI control is know to be non-null. */ protected boolean isUIControlVisible() { return true; } /** * Remove all ridgets contained in this instance. * * @since 1.2 */ protected final void removeRidgets() { for (final IRidget r : getRidgets()) { ridgetToStatuslineSubscriber.removeRidget(r); } ridgets.clear(); } /** * Unbind the current <tt>uiControl</tt> from the ridget. * <p> * Implementors ensure they dispose the control-to-ridget binding and dispose any data structures that are not necessary in an unbound state. * * @since 1.2 */ protected void unbindUIControl() { // implementors should overwrite } /** * Updates the enabled state of the complex UI control (and of the UI controls it contains). This default implementation does nothing and should be * overridden by subclasses. */ protected void updateEnabled() { // empty default implementation } /** * Does nothing by default. * <p> * Subclasses should override to update the tooltip(s) of their controls in an appropriate way. */ protected void updateToolTipText() { // does nothing } /** * Updates the visibility of the complex UI control (and of the UI controls it contains). This default implementation does nothing and should be overridden * by subclasses. */ protected void updateVisible() { // empty default implementation } // helping classes ////////////////// /** * Forwards a property change event fired by a (sub) ridget contained in this composite ridget, to the listeners of the composite ridget. */ private class PropertyChangeHandler implements PropertyChangeListener { public void propertyChange(final PropertyChangeEvent evt) { propertyChangeSupport.firePropertyChange(evt); } } /** * {@inheritDoc} * * @since 4.0 */ public void setConfigured(final boolean configured) { this.configured = configured; } /** * {@inheritDoc} * * @since 4.0 * */ public boolean isConfigured() { return configured; } /** * @return the ridgetResolver * @since 5.0 */ public IRidgetResolver getRidgetResolver() { return ridgetResolver; } /** * @param ridgetResolver * the ridgetResolver to set * @since 5.0 */ public void setRidgetResolver(final IRidgetResolver ridgetResolver) { this.ridgetResolver = ridgetResolver; } }