Configurator.java :  » UML » Quick-Sequence-Diagram-Editor » net » sf » sdedit » ui » components » configuration » Java Open Source

Java Open Source » UML » Quick Sequence Diagram Editor 
Quick Sequence Diagram Editor » net » sf » sdedit » ui » components » configuration » Configurator.java
// Copyright (c) 2006 - 2008, Markus Strauch.
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 
// * Redistributions of source code must retain the above copyright notice, 
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, 
// this list of conditions and the following disclaimer in the documentation 
// and/or other materials provided with the distribution.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
// THE POSSIBILITY OF SUCH DAMAGE.

package net.sf.sdedit.ui.components.configuration;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyDescriptor;

import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

/**
 * An abstract base class for the components used by
 * {@linkplain ConfigurationUI} for configuring properties of a
 * {@linkplain Bean}.
 * 
 * @author Markus Strauch
 * 
 * @param <C>
 *            the type of the data object to be configured
 * @param <T>
 *            the type of the property to be configured
 */
public abstract class Configurator<T, C extends DataObject> extends JPanel
    implements PropertyChangeListener, ActionListener {

  /**
   * The bean to be configured.
   */
  private Bean<C> bean;

  /**
   * The particular property that is configured.
   */
  private PropertyDescriptor property;

  private String[] dependentProperty;

  private String[] dependentValue;

  private boolean[] isDependencyEquality;

  protected Configurator(Bean<C> bean, PropertyDescriptor property) {
    super();
    this.bean = bean;
    this.property = property;
    Adjustable adj = property.getWriteMethod().getAnnotation(
        Adjustable.class);
    if (!adj.depends().equals("")) {
      String[] dependencies = adj.depends().split(",");
      int n = dependencies.length;
      dependentProperty = new String[n];
      dependentValue = new String[n];
      isDependencyEquality = new boolean[n];

      for (int i = 0; i < n; i++) {
        String dependency = dependencies[i];
        String[] split;
        if (dependency.indexOf('!') == -1) {
          isDependencyEquality[i] = true;
          split = dependency.split("=");
        } else {
          isDependencyEquality[i] = false;
          split = dependency.split("!=");
        }
        dependentProperty[i] = split[0];
        dependentValue[i] = split[1];
      }
    }
    bean.addPropertyChangeListener(this);
  }

  public int getLabelWidth() {
    return -1;
  }

  public void setLabelWidth(int width) {

  }

  /**
   * Changes the components for configuring the property such that they
   * reflect the given value.
   * 
   * @param value
   *            the current value of the property
   */
  protected abstract void refresh(T value);

  /**
   * Returns a non-null value that is used as a replacement when a property
   * has the value <tt>null</tt>.
   * 
   * @return a non-null value that is used as a replacement when a property
   *         has the value <tt>null</tt>
   */
  protected abstract T getNullValue();

  /**
   * Returns true if there is no boolean property that the configurability of
   * the property managed by this <tt>Configurator</tt> depends on, or if
   * there is such a boolean property that is set <tt>true</tt>.
   * 
   * @return flag denoting if the boolean property the configurability depends
   *         on is true
   */
  public boolean isDependencySatisfied() {
    if (dependentProperty == null) {
      return true;
    }
    for (int i = 0; i < dependentProperty.length; i++) {
      String value = bean.getValue(dependentProperty[i]).toString();
      boolean sat = dependentValue[i].equals(value);
      if (!isDependencyEquality[i]) {
        sat = !sat;
      }
      if (!sat) {
        return false;
      }
    }
    return true;
  }

  public void setBean(Bean<C> bean) {
    this.bean = bean;
    bean.addPropertyChangeListener(this);
    refresh();
  }

  /**
   * Returns the underlying <tt>Bean</tt>, of which a property is
   * configured by this <tt>Configurator</tt>.
   * 
   * @return the underlying <tt>Bean</tt>, of which a property is
   *         configured by this <tt>Configurator</tt>
   */
  public Bean<C> getBean() {
    return bean;
  }

  /**
   * Returns the <tt>PropertyDescriptor</tt> for the particular property
   * that is being configured.
   * 
   * @return the <tt>PropertyDescriptor</tt> for the particular property
   *         that is being configured
   */
  public PropertyDescriptor getProperty() {
    return property;
  }

  /**
   * Changes the component(s) used for configuration such that the current
   * value of the property is reflected
   */
  @SuppressWarnings("unchecked")
  public void refresh() {
    refresh(getValue());
    setEnabled(isDependencySatisfied());
  }

  /**
   * This method is called by the underlying {@linkplain Bean} when one of its
   * properties changes. If that property is the one that is configured by
   * this <tt>Configurator</tt>, we call {@linkplain #refresh(Object)} with
   * the new value as a parameter, so it is graphically reflected.
   * <p>
   * We always check if the dependency of this <tt>Configurator</tt> is
   * satisfied, i. e. we disable/enable it, depending on the state of the
   * property it depends on.
   * 
   * @param evt
   *            encapsulates the property change
   */
  public void propertyChange(PropertyChangeEvent evt) {
    if (evt.getPropertyName().equals(property.getName())) {
      refresh((T) evt.getNewValue());
    }
    setEnabled(isDependencySatisfied());
  }

  /**
   * Applies the given value, which means that the property that this
   * Configurator configures is set to the value.
   * 
   * @param value
   *            the value to be applied
   */
  protected void applyValue(T value) {
    bean.setValue(property, value);
  }

  /**
   * Returns the current value of the underlying property, or the non-null
   * {@linkplain #getNullValue()} if the property has the value <tt>null</tt>.
   * 
   * @return the current value of the underlying property, or the non-null
   *         {@linkplain #getNullValue()} if the property has the value
   *         <tt>null</tt>
   */
  @SuppressWarnings("unchecked")
  protected T getValue() {
    T value = (T) getBean().getValue(getProperty().getName());
    return value != null ? value : getNullValue();
  }

  @Override
  public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);
    _setEnabled(enabled);
    for (Component comp : getComponents()) {
      comp.setEnabled(enabled);
    }
  }

  @Override
  public void setToolTipText(String tooltip) {
    super.setToolTipText(tooltip);
    for (Component comp : getComponents()) {
      ((JComponent) comp).setToolTipText(tooltip);
    }
  }

  public void actionPerformed(final ActionEvent e) {
    // invoke this later to assert that all component models are in
    // the appropriate state (reflecting the action) - we then apply the
    // value to the underlying bean
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        _actionPerformed(e);
      }
    });
  }

  protected Adjustable getAdjustable() {
    return property.getWriteMethod().getAnnotation(Adjustable.class);
  }

  /**
   * Change the underlying bean such that the it is consistent with the value
   * displayed by this Configurator.
   * 
   * @param evt
   */
  protected abstract void _actionPerformed(ActionEvent evt);

  protected abstract void _setEnabled(boolean enabled);

  // /**
  // * Enable or disable the components belonging to this Configurator.
  // *
  // * @param on
  // */
  // protected abstract void _setEnabled (boolean on);
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.