Package net.xoetrope.html

Source Code of net.xoetrope.html.XHtmlEventHandler

package net.xoetrope.html;

import java.awt.AWTEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.lang.reflect.Method;
import java.util.EventObject;
import java.util.Hashtable;

import net.xoetrope.xui.build.BuildProperties;
import net.xoetrope.debug.DebugLogger;
import net.xoetrope.xui.PageSupport;
import net.xoetrope.xui.WidgetAdapter;
import net.xoetrope.xui.XEventHandler;
import net.xoetrope.xui.XHashCode;
import net.xoetrope.xui.XMethodReference;
import net.xoetrope.xui.XPageHelper;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.evaluator.XAttributeEvaluator;
import net.xoetrope.xui.evaluator.XDefaultAttributeEvaluator;
import net.xoetrope.xui.events.XEventAdapter;
import net.xoetrope.xui.events.XListenerHelper;
import net.xoetrope.xui.events.XuiEventHandler;
import net.xoetrope.xui.exception.XExceptionHandler;
import net.xoetrope.xui.validation.XValidationHandler;
import net.xoetrope.xui.validation.XValidator;
import net.xoetrope.xui.helper.XuiUtilities;

/**
* <p>
* Implements an event handler for XUI. Most of the common events are handled.
* The class is intended as a mixin for a panel class such as XPage and should
* not be used directly
* </p>
* <p>
* Copyright (c) Xoetrope Ltd., 2002-2003
* </p>
* <p>
* License: see license.txt
* </p>
* $Revision: 1.2 $
*/
public class XHtmlEventHandler implements XuiEventHandler, FocusListener, // SelectionListener,
    KeyListener, MouseListener, MouseMotionListener
{
  protected static EventObject currentEvt;

  protected Object container;

  protected XProject currentProject;

  protected Hashtable handlers;

  protected Hashtable classInstances;

  protected static Object mouseDownComponent = null;

  protected static boolean mouseEventInvoked = false;

  protected static int suppressFocusEvents = 0;

  protected XValidationHandler xValidationHandler;

  public XHtmlEventHandler( XProject project, Object c, XValidationHandler vh )
  {
    handlers = new Hashtable( 5 );

    currentProject = project;
    container = c;
    xValidationHandler = vh;

    xValidationHandler.setupEventHandler( this );
  }

  /**
   * Get the validation handler reference. Note that you should not hold a
   * reference to this value as it will probably cause a memory leak.
   *
   * @return the current validation handler
   */
  public XValidationHandler getValidationHandler()
  {
    return xValidationHandler;
  }

  /**
   * Invokes an event. Called in response to an event. If a handler has been
   * added for the event it will be invoked.
   *
   * @param eventType
   *          the event type
   * @param evt
   *          the event object
   */
  public void invoke( long eventType, EventObject evt )
  {
    // If necessary first check for presence of a validation event handler
    // the method name will be "validationHandler" and stop event dispatch if an
    // error has occurred.
    try {
      currentEvt = evt;
      if ( xValidationHandler.validationHandler( this ) > XValidator.LEVEL_WARNING )
        return;

      // Then call any other event handler
      XMethodReference reference = (XMethodReference)handlers.get( new Long( eventType * evt.getSource().hashCode() ) );
      if ( reference == null )
        return;

      Method m = reference.method;
      try {
        if ( ( m != null ) && ( m.getName().compareTo( "validationHandler" ) != 0 ) )
          m.invoke( reference.instance, (Object[])reference.args );
      }
      catch ( Throwable error ) {
        DebugLogger.logWarning( "error invoking '" + m.getName() + "' in XEventHandler" );
        boolean continueHandling = false;
        if ( container instanceof XExceptionHandler )
          continueHandling = ( (XExceptionHandler)container ).handleEventHandlerException( currentProject, container, error );
        if ( continueHandling && ( xValidationHandler != container ) )
          continueHandling = xValidationHandler.handleEventHandlerException( currentProject, container, error );
        if ( continueHandling ) {
          XExceptionHandler exceptionHandler = currentProject.getExceptionHandler();
          if ( exceptionHandler != null )
            continueHandling = exceptionHandler.handleEventHandlerException( currentProject, container, error );
        }
        if ( continueHandling ) {
          if ( BuildProperties.DEBUG )
            DebugLogger.logError( "Error while invoking the method: " + reference.method.getName() + ", in class: " + reference.clazz.getName() );
          error.getCause().printStackTrace();
        }
      }
      currentEvt = null;
    }
    catch ( Exception ex ) {
      System.out.println( "Error invoking" );
    }
  }

  /**
   * Lookup an event for a component.
   *
   * @param evt
   *          the event object
   */
  public Method findEvent( Object src, long eventType )
  {
    XMethodReference reference = (XMethodReference)handlers.get( new Long( eventType * src.hashCode() ) );
    return reference.method;
  }

  /**
   * Check the focus change status
   *
   * @return true if the focus change events are being suppressed.
   */
  public boolean isFocusChangeSuppressed()
  {
    return suppressFocusEvents > 0;
  }

  /**
   * Get the current event
   *
   * @return the AWTEvent that was last triggered
   */
  public EventObject getCurrentEvent()
  {
    return currentEvt;
  }

  /**
   * <p>
   * Adds an event handler. A specific handler such as the addActionHandler
   * should be used instead of calling this method
   * </p>
   * <p>
   * The handler can also be defined in classes other than the current page or
   * classes derived from XPage. The syntax for such expressions is as follows:
   * </p>
   * <ul>
   * <li><code>mypackage.MyClass[referenceName].myMethod</code> for a named
   * object instance</li>
   * <li><code>mypackage.MyClass[].myMethod</code> to create a new instance
   * of the class on each evaluation</li>
   * <li><code>mypackage.MyClass.myMethod</code> to invoke a static method</li>
   * <li><code>myMethod[referenceName]</code> for a method contained with the
   * invoking page</li>
   * </ul>
   * <p>
   * where mypackage is the name of the Java package containing the class
   * MyClass. The value of referenceName is a user defined value that identifies
   * the instance of the class. The application instantiates an instance of the
   * class when the expression is first encountered and thereafter maintains the
   * instance with each subsequent call retrieving the same instance of the
   * class.
   * </p>
   * <p>
   * The page may also reference scripts with the expression
   * <code>${script.XXXXX()}</code> where <code>XXXXX</code> is the name of
   * the script method to be invoked.
   * </p>
   *
   * @param eventType
   *          the event type
   * @param methodStr
   *          the method to be invoked in response to the object
   * @param comp
   *          the component that fires the event
   * @throws java.lang.ClassNotFoundException
   *           The class cannot be found
   * @throws java.lang.NoSuchMethodException
   *           The specified method does not exist in the class
   */
  public XMethodReference addHandler( Object comp, long eventType, String methodStr ) throws ClassNotFoundException, NoSuchMethodException
  {
    XMethodReference reference;
    String className, methodName;
    if ( methodStr == null )
      return null;

    if ( methodStr.startsWith( "${script." ) ) {
      className = "Script";
      methodName = methodStr;
    }
    else {
      int pos = methodStr.lastIndexOf( "." );
      if ( pos < 0 ) {
        methodName = methodStr;
        className = null;
      }
      else {
        className = methodStr.substring( 0, pos );
        methodName = methodStr.substring( pos + 1 );
      }
    }

    reference = getMethodReference( container, className, methodName );

    long hashCode = comp.hashCode();
    if ( comp instanceof XHashCode )
      hashCode = ( (XHashCode)comp ).getComponentHashCode();
    handlers.put( new Long( eventType * hashCode ), reference );
    return reference;
  }

  /**
   * Adds a handler for action events
   *
   * @param srcObj
   *          the menu item that fires the events
   * @param methodName
   *          the method to be invoked in response to the action event
   * @param adderMethod
   *          the adder method name e.g. addActionListener
   * @param listenerInterface
   *          the listener interface e.g. java.awt.event.ActionListener
   * @param eventMask
   *          the event mask e.g. AWTEvent.ACTION_EVENT_MASK
   * @param listener
   *          the listener implementation, usually the page's this pointer
   * @see java.awt.event.ActionListener
   * @see java.awt.event.ActionEvent
   */
  public XMethodReference addHandler( Object srcObj, String methodName, String adderMethod, String listenerInterface, long eventMask, Object listener )
  {
    XMethodReference reference = null;
    addListener( srcObj, adderMethod, listenerInterface, listener );
    try {
      reference = addHandler( srcObj, eventMask, methodName );
    }
    catch ( Error error ) {
      if ( BuildProperties.DEBUG )
        DebugLogger.logError( "Unable to add the handler: " + methodName );
      error.printStackTrace();
    }
    catch ( Exception ex ) {
      ex.printStackTrace();
    }
    return reference;
  }

  /**
   * Remove all the event handlers for a particular object
   *
   * @param comp
   *          the object whose events are being removed
   */
  public void removeHandlers( Object comp )
  {
    long hashCode = comp.hashCode();
    if ( comp instanceof XHashCode )
      hashCode = ( (XHashCode)comp ).getComponentHashCode();
    long[] handledEvents = {
        AWTEvent.ACTION_EVENT_MASK, AWTEvent.FOCUS_EVENT_MASK, AWTEvent.TEXT_EVENT_MASK, AWTEvent.ITEM_EVENT_MASK, AWTEvent.KEY_EVENT_MASK,
        AWTEvent.MOUSE_EVENT_MASK, AWTEvent.MOUSE_MOTION_EVENT_MASK
    };
//    String[] listenerMethods = {
//        "removeActionListener", "removeFocusListener", "removeTextListener", "removeItemListener", "removeKeyListener", "removeMouseListener",
//        "removeMouseMotionListener"
//    };
    String[] listener = {
        "ActionListener", "FocusListener", "TextListener", "ItemListener", "KeyListener", "MouseListener", "MouseMotionListener"
    };
    for ( int i = 0; i < handledEvents.length; i++ ) {
      Object key = new Long( handledEvents[ i ] * hashCode );
      Object handler = handlers.get( key );
      if ( handler != null ) {
        handlers.remove( key );
        // The addListener method just invokes the named method, so it can
        // remove the listener
        // just as easily.
        addListener( comp, "remove" + listener[ i ], "java.awt.event." + listener[ i ], this );
      }
    }
  }

  /**
   * Adds a listener for an event type. This method should not normally be
   * called by an application
   *
   * @param comp
   *          the component that fires events
   * @param listenerName
   *          the name of the listener interface
   * @param argType
   *          the listener arguments
   * @param listener
   *          the listener implementation, usually the page's this pointer
   */
  public void addListener( Object comp, String listenerName, String argType, Object listener )
  {
    // try {
    // Class params[] = new Class[ 1 ];
    // params[ 0 ] = Class.forName( argType.trim() );
    // Method m = comp.getClass().getMethod( listenerName, params );
    // Object args[] = new Object[ 1 ];
    // args[ 0 ] = this;
    // m.invoke( comp, args );
    // }
    // catch ( Exception e )
    // {
    // e.printStackTrace();
    // }
  }

  /**
   * A utility method used to determine if the last event corrseponds to a mouse
   * click. The notion of a click is extended by assuming the a mouse press and
   * release within a single component constitutes a click even if not at the
   * same coordinate. A MouseEvent.MOUSE_CLICKED is only triggered when the
   * press and release are at the same location and this is often inadequate for
   * end-user interaction.
   *
   * @return true if the mouse was clicked
   */
  public boolean wasMouseClicked()
  {
    // if ( currentEvt != null ) {
    // if ( ( currentEvt instanceof MouseEvent ) &&
    // ( (( ((MouseEvent)currentEvt).button & SWT.BUTTON1 ) > 0 ) &&
    // ( currentEvt.getSource() == mouseDownComponent ) )) {
    // mouseDownComponent = null;
    // return true;
    // }
    // }
    //
    // mouseEventInvoked = true;
    return false;
  }

  /**
   * A utility method used to determine if the last event corrseponds to a mouse
   * double click. The notion of a click is extended by assuming the a mouse
   * press and release within a single component constitutes a click even if not
   * at the same coordinate. A MouseEvent.MOUSE_CLICKED is only triggered when
   * the press and release are at the same location and this is often inadequate
   * for end-user interaction.
   *
   * @return true if the mouse was double clicked
   */
  public boolean wasMouseDoubleClicked()
  {
    // if ( currentEvt != null ) {
    // if ( ( currentEvt instanceof MouseEvent ) &&
    // ( (( ((MouseEvent)currentEvt).button & SWT.BUTTON1 ) > 0 ) &&
    // ( currentEvt.getSource() == mouseDownComponent ) )) {
    // mouseDownComponent = null;
    // return true;
    // }
    // }
    // mouseEventInvoked = true;
    return false;
  }

  /**
   * A utility method used to determine if the last event corrseponds to a mouse
   * right click. The notion of a click is extended by assuming the a mouse
   * press and release within a single component constitutes a click even if not
   * at the same coordinate. A MouseEvent.MOUSE_CLICKED is only triggered when
   * the press and release are at the same location and this is often inadequate
   * for end-user interaction.
   *
   * @return true if the mouse was right clicked
   */
  public boolean wasMouseRightClicked()
  {
    // if ( currentEvt != null ) {
    // if ( ( currentEvt instanceof MouseEvent ) &&
    // ( (( ((MouseEvent)currentEvt).button & SWT.BUTTON3 ) > 0 ) &&
    // ( currentEvt.getSource() == mouseDownComponent ) )) {
    // mouseDownComponent = null;
    // return true;
    // }
    // }
    // mouseEventInvoked = true;
    return false;
  }

  // ----------------------------------------------------------------------------
  // public void widgetSelected( SelectionEvent e )
  // {
  // invoke( AWTEvent.ACTION_EVENT_MASK, e );
  // }
  //
  // public void widgetDefaultSelected( SelectionEvent e )
  // {
  // invoke( AWTEvent.ACTION_EVENT_MASK, e );
  // }

  public void focusGained( FocusEvent e )
  {
    // The suppressFocusEvents flag is used as poping up a message dialog causes
    // input fields to loose focus. This in turn could cause a continuous loop
    // of validation errors - messages - loss of focus - validations -
    // validation errors
    if ( suppressFocusEvents < 2 ) {
      invoke( AWTEvent.FOCUS_EVENT_MASK, e );
      if ( suppressFocusEvents == 1 ) {
        suppressFocusEvents++;
      }
    }
  }

  public void focusLost( FocusEvent e )
  {
    if ( suppressFocusEvents == 0 ) {
      invoke( AWTEvent.FOCUS_EVENT_MASK, e );
    }
  }

  public void keyPressed( KeyEvent e )
  {
    invoke( AWTEvent.KEY_EVENT_MASK, e );
  }

  public void keyReleased( KeyEvent e )
  {
    invoke( AWTEvent.KEY_EVENT_MASK, e );
  }

  public void keyTyped( KeyEvent e )
  {
    invoke( AWTEvent.KEY_EVENT_MASK, e );
  }

  public void mouseClicked( MouseEvent e )
  {
    if ( !mouseEventInvoked )
      invoke( AWTEvent.MOUSE_EVENT_MASK, e );
  }

  public void mouseDoubleClicked( MouseEvent e )
  {
    if ( !mouseEventInvoked )
      invoke( AWTEvent.MOUSE_EVENT_MASK, e );
  }

  public void mouseEntered( MouseEvent e )
  {
    invoke( AWTEvent.MOUSE_EVENT_MASK, e );
  }

  public void mouseExited( MouseEvent e )
  {
    invoke( AWTEvent.MOUSE_EVENT_MASK, e );
  }

  public void mousePressed( MouseEvent e )
  {
    mouseDownComponent = e.getSource();
    mouseEventInvoked = false;
    invoke( AWTEvent.MOUSE_EVENT_MASK, e );
  }

  public void mouseReleased( MouseEvent e )
  {
    invoke( AWTEvent.MOUSE_EVENT_MASK, e );
  }

  public void mouseMoved( MouseEvent e )
  {
    invoke( AWTEvent.MOUSE_MOTION_EVENT_MASK, e );
  }

  public void mouseHover( MouseEvent e )
  {
    invoke( AWTEvent.MOUSE_MOTION_EVENT_MASK, e );
  }

  public void mouseDragged( MouseEvent e )
  {
    invoke( AWTEvent.MOUSE_MOTION_EVENT_MASK, e );
  }

  // ----------------------------------------------------------------------------

  /**
   * Used by messageboxes and other dialogs to prevent the display of the dialog
   * causing extra focus events from being fired.
   *
   * @param suppress
   *          true to suppress focus events
   */
  public void suppressFocusEvents( boolean suppress )
  {
    if ( suppress )
      suppressFocusEvents++;
    else
      suppressFocusEvents = Math.max( --suppressFocusEvents, 0 );
  }

  // ----------------------------------------------------------------------------
  /**
   * Get a reference to a method and a class instance.
   *
   * @param container
   *          the page or object whose event is being handled
   * @param className
   *          the name of the class containing the handler
   * @param methodName
   *          the name of the method.
   * @throws ClassNotFoundException
   *           the className class could not be loaded
   * @throws NoSuchMethodException
   *           the methodName method could not be found in the className class
   */
  private XMethodReference getMethodReference( Object container, String className, String methodName ) throws ClassNotFoundException,
      NoSuchMethodException
  {
    Class clazz = null;
    if ( className == null ) {
      clazz = container.getClass();
      className = clazz.getName();
    }

    if ( className.startsWith( "${" ) ) {
      XAttributeEvaluator attEval = (XAttributeEvaluator)currentProject.getObject( "DefaultAttributeEvaluator" );
      if ( attEval == null ) {
        attEval = new XDefaultAttributeEvaluator( currentProject );
        attEval.setCurrentProject( currentProject );
        currentProject.setObject( "DefaultAttributeEvaluator", attEval );
      }
      XMethodReference methodRef = attEval.getMethodReference( (PageSupport)container, className + "." + methodName );
      return methodRef;
    }
    else if ( className.startsWith( "Script" ) ) {
      XMethodReference methodRef = null;
      try {
        XAttributeEvaluator attEval = (XAttributeEvaluator)currentProject.getObject( "ScriptAttributeEvaluator" );
        if ( attEval == null ) {
          attEval = (XAttributeEvaluator)XEventHandler.class.forName( "incubator.net.xoetrope.scripts.ScriptAttributeEvaluator" ).newInstance();
          attEval.setCurrentProject( currentProject );
          currentProject.setObject( "ScriptAttributeEvaluator", attEval );
        }
        methodRef = attEval.getMethodReference( methodName );
      }
      catch ( Throwable t ) {
      }
      return methodRef;
    }
    else {
      Method method = null;
      if ( clazz == null )
        clazz = Class.forName( className.trim());
     
      if ( methodName.endsWith( "}" ) )
        methodName = methodName.substring( 0, methodName.length() - 1 );
     
      if ( methodName.endsWith( "()" ) )
        methodName = methodName.substring( 0, methodName.length() - 2 );

      int pos;
      if ( ( pos = methodName.indexOf( "(" ) ) > 0 ) {
        String argValues = methodName.substring( pos + 1, methodName.indexOf( ')' ) );
        int numArgs = 1 + XuiUtilities.count( argValues, ',' );
        Object[] args = new Object[numArgs];
        Class[] params = new Class[numArgs];
        XuiUtilities.getArguments( argValues, params, args, ',' );

        methodName = methodName.substring( 0, pos );
        method = clazz.getMethod( methodName, params );
        return new XMethodReference( clazz, container, method, args );
      }
      else
        method = clazz.getMethod( methodName, (Class[])null );
      return new XMethodReference( clazz, container, method, null );
    }
  }

  // ----------------------------------------------------------------------------
  /**
   * Adds an event handler.
   *
   * @param xpage
   *          The page that contains the response methods
   * @param targetComp
   *          the component to which the event handler is added
   * @param typeStr
   *          the type of handler
   * @param methodName
   *          the name of the response method
   */
  public void addHandler( PageSupport xpage, Object targetComp, String typeStr, String methodName )
  {
    try {
//      String ifaceName;
//      long mask;
      String types[] = {
          "MouseHandler", "MouseMotionHandler", "ActionHandler", "FocusHandler", "ItemHandler", "KeyHandler", "TextHandler", "MenuHandler"
      };
      String iface[] = {
          "java.awt.event.MouseListener", "java.awt.event.MouseMotionListener", "java.awt.event.ActionListener", "java.awt.event.FocusListener",
          "java.awt.event.ItemListener", "java.awt.event.KeyListener", "java.awt.event.TextListener", "java.awt.event.ActionListener"
      };
      long masks[] = {
          AWTEvent.MOUSE_EVENT_MASK, AWTEvent.MOUSE_MOTION_EVENT_MASK, AWTEvent.ACTION_EVENT_MASK, AWTEvent.FOCUS_EVENT_MASK,
          AWTEvent.ITEM_EVENT_MASK, AWTEvent.KEY_EVENT_MASK, AWTEvent.TEXT_EVENT_MASK, AWTEvent.ACTION_EVENT_MASK
      };
      for ( int i = 0; i < types.length; i++ ) {
        if ( typeStr.equals( types[ i ] ) ) {
          String adder = "add" + iface[ i ].substring( iface[ i ].lastIndexOf( '.' ) + 1 );
          addHandler( targetComp, methodName, adder, iface[ i ], masks[ i ], this );
          return;
        }
      }

      /**
       * @todo handle this in a more generic way
       */
      if ( targetComp.getClass().getName().indexOf( "Button" ) > -1 )
        WidgetAdapter.getInstance().setCursor( targetComp, XPageHelper.hand );

      if ( typeStr.indexOf( '.' ) > 0 ) {
        try {
          XEventAdapter xea = (XEventAdapter)Class.forName( typeStr.trim() ).newInstance();
          xea.setEventHandler( this );
          addHandler( targetComp, methodName, xea.getAddMethodName(), xea.getListenerInterfaceName(), xea.getEventMask(), xea );
        }
        catch ( Exception ex ) {
          ex.printStackTrace();
        }
      }
      else
        ( (XListenerHelper)targetComp ).addHandler( xpage, typeStr, methodName );
    }
    catch ( NoSuchMethodException ex ) {
      if ( BuildProperties.DEBUG )
        DebugLogger.logError( "BUILDER", "Unable to add the event handler method: " + methodName );
    }
  }
}
TOP

Related Classes of net.xoetrope.html.XHtmlEventHandler

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.