Package org.beryl.gui

Source Code of org.beryl.gui.Widget

/*
* Beryl - A web platform based on XML, XSLT and Java
* This file is part of the Beryl XML GUI
*
* Copyright (C) 2004 Wenzel Jakob <wazlaf@tigris.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.

* This program 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-3107  USA
*/

package org.beryl.gui;

import java.awt.Component;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragSource;
import java.awt.dnd.DropTarget;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import java.util.StringTokenizer;

import javax.help.HelpBroker;
import javax.help.HelpSet;
import javax.swing.JComponent;
import javax.swing.UIManager;

import org.beryl.gui.model.MapDataModel;
import org.beryl.gui.model.ModelChangeEvent;
import org.beryl.gui.validators.ValidationException;
import org.beryl.gui.validators.Validator;

import cz.autel.dmi.HIGConstraints;

/**
* <tt>Widget</tt> is the base class of all components using the
* Beryl XML GUI framework.
*/

public abstract class Widget extends AbstractView implements LFConstants {
  /* Method cache used to accelerate swing widget introspection */
  private static HashMap methodCache = new HashMap();
  /* Commonly used inside widget sublcasses */
  protected static HIGConstraints constraints = new HIGConstraints();
  /* Widget property information */
  protected static WidgetInfo widgetInfo = null;
  /* Used to invoke getters via reflection */
  private static final Object[] EMPTY_ARRAY = new Object[] {
  };
  /* JavaHelp support */
  protected static HelpBroker helpBroker = null;
  protected static HelpSet helpSet = null;

  /* Members */
  private ArrayList children = null;
  private String name = null;
  private Widget parent = null;
  private HashMap widgetMap = null;
  private ArrayList validators = null;

  static {
    /* Add the basic properties which should be available to most widgets */
    widgetInfo = new WidgetInfo(Widget.class);
    widgetInfo.addProperty("anchor", "anchor", null);
    widgetInfo.addProperty("background", "color", UIManager.getDefaults().getColor("Label.background"));
    widgetInfo.addProperty("foreground", "color", UIManager.getDefaults().getColor("Label.foreground"));
    widgetInfo.addProperty("enabled", "bool", Boolean.TRUE);
    widgetInfo.addProperty("opaque", "bool", Boolean.TRUE);
    widgetInfo.addProperty("helpid", "string", null);
  };

  /**
   * Create a widget with a predefined type
   * @param parent The widget's parent
   * @param name The name of the widget
   * @param preset The preset to use
   * @throws GUIException If something goes wrong during the construction
   */
  public Widget(Widget parent, String name, String preset) throws GUIException {
    throw new GUIException("Could not create the preset [" + preset + "] because there is no implementation");
  }

  /**
   * Create a widget
   * @param parent The widget's parent
   * @param name The name of the widget
   * @throws GUIException If something goes wrong during the construction
   */
  public Widget(Widget parent, String name) throws GUIException {
    children = new ArrayList();
    this.name = name;
    this.parent = parent;
    if (parent != null) {
      widgetMap = parent.widgetMap;
    } else {
      widgetMap = new HashMap();
    }
  }

  /**
   * Return the widget's name
   */

  public String getName() {
    return name;
  }

  /**
   * Change the widget's name. This should
   * only be used by the GUI Builder
   */
  public void setName(String newName) {
    if (name != null) {
      widgetMap.remove(name);
    }
    if (newName != null) {
      widgetMap.put(newName, this);
    }

    name = newName;
  }

  /**
   * Recursively search the widget tree for
   * a child widget
   */

  public Widget getChildWidgetByName(String name) {
    for (int i = 0; i < children.size(); i++) {
      Widget widget = (Widget) children.get(i);
      if (name.equals(widget.getName())) {
        return widget;
      } else {
        Widget result = widget.getChildWidgetByName(name);
        if (result != null)
          return result;
      }
    }
    return null;
  }

  /**
   * Lookup a widget in the widget map. Note that
   * this could be below or above the current widget.
   * Search will, however, be restricted to one widget tree
   */
  public Widget getWidget(String name) {
    return (Widget) widgetMap.get(name);
  }

  /**
   * Return the parent widget
   */
  public Widget getParentWidget() {
    return parent;
  }

  /**
   * Return a parent widget with a given name
   */
  public Widget getParentWidgetByName(String name) {
    if (parent == null)
      return null;
    if (name.equals(parent.getName()))
      return parent;
    else
      return parent.getParentWidgetByName(name);
  }

  /**
   * Return the first parent widget with is an
   * instance of the given class
   */

  public Widget getParentWidgetByClass(Class type) {
    if (parent == null)
      return null;
    if (type.equals(parent.getClass()))
      return parent;
    else
      return parent.getParentWidgetByClass(type);
  }

  /**
   * Return the amount of child widgets
   */

  public int getChildCount() {
    return children.size();
  }

  /**
   * Return the child widget at the given index
   */
  public Widget getChild(int index) {
    return (Widget) children.get(index);
  }

  /**
   * Return the index of a child
   */
  public int getChildIndex(Widget child) {
    return children.indexOf(child);
  }

  /**
   * Set a property using the reflection api
   */
  public void setProperty(String name, Object value) throws GUIException {
    if (name.equals("helpid")) {
      if (helpBroker == null)
        throw new GUIException("JavaHelp has not been activated");
      if (value != null)
        helpBroker.enableHelp(getRealWidget(), (String) value, helpSet);
    } else {
      String cacheName = this.getClass().getName() + ":" + name + ":" + value.getClass().getName() + "S";
      try {
        Method setter = (Method) methodCache.get(cacheName);

        if (setter == null) {
          setter = findSetter(name, value);
          methodCache.put(cacheName, setter);
        }
        setter.invoke(getRealWidget(), new Object[] { value });
      } catch (InvocationTargetException e) {
        throw new GUIException("Property setter threw an exception", e);
      } catch (IllegalAccessException e) {
        throw new GUIException("Property setter method is inaccessible", e);
      }
    }
  }

  /**
   * Get a property using the reflection API
   */
  public Object getProperty(String name) throws GUIException {
    String cacheName = this.getClass().getName() + ":" + name + "G";
    try {
      Method getter = (Method) methodCache.get(cacheName);

      if (getter == null) {
        getter = findGetter(name);
        methodCache.put(cacheName, getter);
      }
      return getter.invoke(getRealWidget(), EMPTY_ARRAY);
    } catch (InvocationTargetException e) {
      throw new GUIException("Property getter threw an exception", e);
    } catch (IllegalAccessException e) {
      throw new GUIException("Property getter method is inaccessible", e);
    }
  }

  private Method findGetter(String name) throws GUIException {
    Object widget = getRealWidget();
    String setterName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
    try {
      return widget.getClass().getMethod(setterName, new Class[] {
      });
    } catch (Exception e) {
      throw new GUIException(
        "Cannot acquire getter method in widget ["
          + this.getClass().getName()
          + "] for property ["
          + name
          + "]",
        e);
    }
  }

  private Method findSetter(String name, Object value) throws GUIException {
    Object widget = getRealWidget();
    Class valueClass = value.getClass();
    String setterName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);

    /* Prefer builtin types to their boxed counterparts */
    if (valueClass.equals(Boolean.class))
      valueClass = boolean.class;
    else if (valueClass.equals(Integer.class))
      valueClass = int.class;
    else if (valueClass.equals(Long.class))
      valueClass = long.class;
    else if (valueClass.equals(Double.class))
      valueClass = double.class;
    else if (valueClass.equals(Float.class))
      valueClass = float.class;
    else if (valueClass.equals(Character.class))
      valueClass = char.class;
    else if (valueClass.equals(Short.class))
      valueClass = short.class;
    else if (valueClass.equals(Byte.class))
      valueClass = byte.class;

    try {
      /* 1. Simple method */
      return widget.getClass().getMethod(setterName, new Class[] { valueClass });
    } catch (NoSuchMethodException e) {
      /* 2. Tricky method */
      Method methods[] = widget.getClass().getMethods();
      for (int i = 0; i < methods.length; i++) {
        Method method = methods[i];
        if (method.getName().equals(setterName)
          && method.getParameterTypes().length == 1
          && method.getParameterTypes()[0].isAssignableFrom(valueClass)) {
          return method;
        }
      }
    }
    throw new GUIException(
      "Cannot acquire setter method in widget ["
        + this.getClass().getName()
        + "] for property ["
        + name
        + "], value class ["
        + valueClass.getName()
        + "] and value ["
        + value
        + "]");
  }

  /**
   * Notify the widget about a data model event
   */

  public void modelChanged(ModelChangeEvent e) throws GUIException {
    /* Do nothing, to be overwritten by subclasses */
  }

  /**
   * Add a child widget with a constraint
   */

  public void addChild(Widget widget, Object constraint) throws GUIException {
    throw new GUIException(
      "Child widget functionality not implemented for widget [" + this.getClass().getName() + "]");
  }

  /**
   * Add a child widget to the widget tree
   */
  public void addChild(Widget widget) throws GUIException {
    children.add(widget);
    String name = widget.getName();
    if (name != null) {
      if (!widgetMap.containsKey(name))
        widgetMap.put(name, widget);
      else
        throw new GUIException("There is already a widget named [" + name + "]");
    }
  }

  /**
   * Return a structure containing the widget's children
   */

  protected final List getChildren() {
    return children;
  }

  /**
   * Remove all of this widget's children from the
   * widget tree
   */

  public void removeAllChildWidgets() {
    for (Iterator i = children.iterator(); i.hasNext();) {
      Widget child = (Widget) i.next();
      widgetMap.remove(child.getName());
      i.remove();
    }
  }

  /**
   * Remove a child widget from the widget tree
   */

  public void removeChildWidget(Widget widget) throws GUIException {
    widgetMap.remove(widget.getName());
    children.remove(widget);
  }

  /**
   * Add a listener for a given event
   *
   * Every widget can support DnD, to enable it add a "drag"
   * event or an event in the form "drop[mimeType1,mimeType2]"
   */
  public void addListener(String event, String name, GUIEventListener listener) throws GUIException {
    if (event.equals("drag")) {
      DragHandler handler = new DragHandler(this, listener, name);
      DragSource dragSource = DragSource.getDefaultDragSource();
      dragSource.createDefaultDragGestureRecognizer(getRealWidget(), DnDConstants.ACTION_COPY_OR_MOVE, handler);
    } else if (event.startsWith("drop[") && event.endsWith("]")) {
      try {
        StringTokenizer tokenizer = new StringTokenizer(event.substring(5, event.length() - 1), ", ");
        DataFlavor flavors[] = new DataFlavor[tokenizer.countTokens()];

        int counter = 0;
        while (tokenizer.hasMoreTokens()) {
          flavors[counter++] = new DataFlavor(tokenizer.nextToken());
        }

        DropHandler handler = new DropHandler(this, listener, name, flavors);
        new DropTarget(getRealWidget(), handler);
      } catch (Exception e) {
        throw new GUIException("Error while creating drop target support", e);
      }
    } else {
      throw new GUIException(
        "Event functionality not implemented for widget [" + this.getClass().getName() + "]");
    }
  }

  /**
   * Add a validator to this widget
   */

  public void addValidator(Validator validator) {
    if (validators == null)
      validators = new ArrayList();
    validators.add(validator);
  }

  /**
   * Remove a validator from this widget
   */

  public void removeValidator(Validator validator) {
    if (validators != null)
      validators.remove(validator);
  }

  /**
   * Validate this widget
   * @throws ValidationException If the widget did not validate
   */

  public void validate() throws ValidationException, GUIException {
    if (validators != null) {
      for (int i = 0; i < validators.size(); i++) {
        ((Validator) validators.get(i)).validate(this);
      }
    }
  }

  /**
   * Recursively validate the widget tree
   * @throws ValidationException If the widget tree did not validate
   */

  public void recursiveValidate() throws ValidationException, GUIException {
    validate();
    for (int i = 0; i < children.size(); i++) {
      ((Widget) children.get(i)).recursiveValidate();
    }
  }

  /**
   * Set a new data model for the whole widget tree
   */

  public void recursiveSetDataModel(MapDataModel model) throws GUIException {
    setDataModel(model);
    for (int i = 0; i < children.size(); i++) {
      ((Widget) children.get(i)).recursiveSetDataModel(model);
    }
  }

  /**
   * Return whether this widget has any validators
   * associated with it
   */

  public boolean hasValidators() {
    return (validators != null && validators.size() > 0);
  }

  /**
   *  Return the underlying swing component
   */
  public abstract Component getWidget();

  /**
   * Return information about the widget's available
   * properties. This is mostly used by the Builder
   */
  public WidgetInfo getWidgetInfo() {
    return widgetInfo;
  }

  /**
   * Sometimes, a widget needs to be encapsulated - for example
   * inside a JPanel. This function then returns the actual widget
   */
  public Component getRealWidget() {
    return getWidget();
  }

  /**
   * This is called after a component has been completely constructed
   * from an XML description file. Can be overwritten by subclasses if
   * such funtionality is required.
   */
  public void finalizeConstruction() throws GUIException {
    /* Do nothing by default */
  }

  /**
   * Return an ASCII-Art representation of the tree
   */
  public String dumpStructure() {
    return dumpStructure(new Stack());
  }

  private String dumpStructure(Stack stack) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < stack.size(); i++) {
      boolean last = ((Boolean) stack.get(i)).booleanValue();
      if ((i == stack.size() - 1) && last) {
        buf.append(" `");
      } else {
        if (last)
          buf.append("  ");
        else
          buf.append(" |");
      }
    }
    buf.append("-o ").append(toString()).append('\n');
    for (int i = 0; i < children.size(); i++) {
      stack.push(new Boolean(children.size() - 1 == i));
      buf.append(((Widget) children.get(i)).dumpStructure(stack));
      stack.pop();
    }
    return buf.toString();
  }

  /**
   * Return a string description of this widget
   */

  public String toString() {
    StringBuffer buf = new StringBuffer();
    buf.append(getClass().getName());

    if (name != null)
      buf.append("[name='" + name + "']");
    return buf.toString();
  }

  /* =============== JComponent Base funtions ================= */

  /**
   * Set a tooltip for this widget
   */
  public void setTooltipText(String text) throws GUIException {
    try {
      ((JComponent) getWidget()).setToolTipText(text);
    } catch (ClassCastException e) {
      throw new GUIException("Widget does not contain a JComponent : " + getWidget().getClass().toString(), e);
    }
  }

  /**
   * Request the focus
   */
  public void requestFocus() {
    getWidget().requestFocus();
  }

  /**
   * Set whether this widget is enabled or disabled
   */
  public void setEnabled(boolean enabled) throws GUIException {
    try {
      ((JComponent) getRealWidget()).setEnabled(enabled);
    } catch (ClassCastException e) {
      throw new GUIException("Widget does not contain a JComponent : " + getWidget().getClass().toString(), e);
    }
  }

  /**
   * Revalidate the swing widget tree
   */
  public void revalidate() throws GUIException {
    try {
      ((JComponent) getWidget()).revalidate();
      getWidget().repaint();
    } catch (ClassCastException e) {
      throw new GUIException("Widget does not contain a JComponent : " + getWidget().getClass().toString(), e);
    }
  }

  /**
   * Set the application's help set. Note that this
   * help set is static to the whole application
   */
  public static void setHelpSet(HelpSet helpSet) {
    Widget.helpSet = helpSet;
    helpBroker = helpSet.createHelpBroker();
  }

  /**
   * Get the application's help set. Note that this
   * help is static to the whole application
   */
  public static HelpSet getHelpSet() {
    return helpSet;
  }

  /**
   * Get the application's help broker. Note that this
   * help is static to the whole application
   */
  public static HelpBroker getHelpBroker() {
    return helpBroker;
  }
}
TOP

Related Classes of org.beryl.gui.Widget

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.