Package net.helipilot50.stocktrade.displayproject.events

Source Code of net.helipilot50.stocktrade.displayproject.events.FocusListener

/*
Copyright (c) 2003-2009 ITerative Consulting Pty Ltd. All Rights Reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

o Redistributions of source code must retain the above copyright notice, this list of conditions and
the following disclaimer.
 
o 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.
   
o This jcTOOL Helper Class software, whether in binary or source form may not be used within,
or to derive, any other product without the specific prior written permission of the copyright holder

 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "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.helipilot50.stocktrade.displayproject.events;

import java.awt.Component;
import java.awt.Container;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.util.Hashtable;

import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTable;

import net.helipilot50.stocktrade.displayproject.Constants;
import net.helipilot50.stocktrade.displayproject.DataField;
import net.helipilot50.stocktrade.displayproject.FocusHelper;
import net.helipilot50.stocktrade.displayproject.PasswordDataField;
import net.helipilot50.stocktrade.displayproject.controls.ArrayField;
import net.helipilot50.stocktrade.displayproject.controls.MultiLineTextField;
import net.helipilot50.stocktrade.displayproject.table.ArrayFieldCellHelper;
import net.helipilot50.stocktrade.framework.EventManager;
import net.helipilot50.stocktrade.framework.ForteKeyboardFocusManager;
import net.helipilot50.stocktrade.framework.ParameterHolder;


/**
* Listen and post on focus loss + gained events.
*
* Focus events are a little strange in the forte implementation. It's like they have a child listener built in. For
* example, if DataField D1 in GridField G1 loses focus and that focus loss takes the focus out of grid field G1 then
* there should be 2 focus loss events fired, that from D1 and also that from G1. However, if D1 loses focus to another
* data field D2 inside G1, then only D1 should fire a focus loss event, not G1 (as one of it's children has still
* retained the focus)<p>
* <p>
* There are 2 ways of implementing this. The first is to register a focus change handler on all the children, and process
* the focus gain / focus loss events for all these children, looking to see if the old child and the new child are both children
* and fire the appropriate events if they're not. This will result in a lot of focus listeners at higher grid field levels.
* The other way is to monitor the permanent focus owner in a method similar to the TraverseListener and fire events when
* this changes. We use the former way, even though it posts obsolete events because it is the cleanest to implement -- using
* the property change event on the permanent focus owner, you won't necessarily know who the other side of the event is.
* <p>
* There is another issue to consider: When a new child is added to the hierarchy of a container, if that container listens
* for the focus change events the new field must automatically post these events. We use container listeners to ensure that
* when the hierarchy changes, the appropriate focus events are registered on the new components, or deregistered on the old
* components.
* <p>
* Some components automatically post their own focus events -- this class is aware of these and prevents duplicate events being
* posted.
* @author Tim
* @since 17/07/2007
*/
public class FocusListener extends FocusAdapter implements InstallableListener, ChildInstallableListener, ContainerListener {

  public static final String cAFTER_FOCUS_GAIN = "AfterFocusGain";
  public static final String cBEFORE_FOCUS_LOSS = "BeforeFocusLoss";
 
    public void install(Object o, String pEvent) {
        // TF:12/10/07:Don't allow the registration of focus events on an array, the array will fire these for itself.
        if (o instanceof ArrayField || (o instanceof Component && ArrayFieldCellHelper.getArrayField((Component)o) != null)) {
            return;
        }

        if (o instanceof JPanel ||
            o instanceof JTabbedPane ||
            o instanceof JTable) {

            // Recursively install this notification on our children
            ChildEventHelper.installOnAllChildren((JComponent)o, pEvent, this);
        }
        else if (o instanceof Component){
            ((Component)o).removeFocusListener(this);
            ((Component)o).addFocusListener(this);
        }
       
        // We also need to register this as the component handler
        if (o instanceof Container){
            ((Container)o).removeContainerListener(this);
            ((Container)o).addContainerListener(this);
        }
    }

    /**
     * A component is being added to the hierarchy, add the focus event to is
     */
  public void componentAdded(ContainerEvent e) {
    if (e.getChild() instanceof JComponent) {
      JComponent child = (JComponent)e.getChild();
            // TF:12/10/07:Don't allow the registration of focus events on an array, the array will fire these for itself.
            if (child instanceof ArrayField || ArrayFieldCellHelper.getArrayField(child) != null) {
                return;
            }
          child.removeContainerListener(this);
          child.addContainerListener(this);
            ChildEventHelper.installOnAllChildren((JComponent)e.getChild(), cAFTER_FOCUS_GAIN, this);
    }
  }

  /**
   * A component is being removed from the hierarchy -- remove this listener from that child and all it's children
   */
  public void componentRemoved(ContainerEvent e) {
    recursiveRemove(e.getChild());
  }
 
  /**
   * A component is being removed from the hierarchy -- remove this listener from that child and all it's children
   */
  private void recursiveRemove(Component c) {
    c.removeFocusListener(this);
    if (c instanceof Container) {
      Container container = (Container)c;
      container.removeContainerListener(this);
      int kidCount = container.getComponentCount();
      for (int i = 0; i < kidCount; i++) {
        recursiveRemove(container.getComponent(i));
      }
    }
  }

  /**
   * When a focus loss event occurs, we need to possibly post events all the way up the hierarchy, until
   * we find a component which is still retaining focus. (That is, it is the owning parent of both the
   * losing focus component and the gaining focus component).
   */
    @Override
    public void focusLost(FocusEvent e) {
    Component losingFocusField = e.getComponent();
    Component gainingFocusField = e.getOppositeComponent();
   
    // Don't post the events on the array field if the array field is retaining the focus --
    // the array field will post this automatically
    if (losingFocusField instanceof ArrayField && ((ArrayField)losingFocusField).isLosingFocus() == false) {
            return;
        }

    // If the traversal reason is SUPRESS, we cannot post this event
        int realReason = ForteKeyboardFocusManager.getTraversalReason();
        if (realReason == Constants.FC_SUPRESS) {
          return;
        }
       
        EventManager.startEventChain();
        try {
          FocusHelper.addSetFocusPurgeAction((JComponent)losingFocusField);
          Hashtable<String, Object> params = new Hashtable<String, Object>();
 
          if (losingFocusField instanceof JComponent) {
              Object table = ArrayFieldCellHelper.getArrayField(losingFocusField);
 
              if (table != null && table instanceof JTable) {
                  params.put( "ArrayField", new ParameterHolder(table) );
              }
          }
          params.put("reason", new ParameterHolder(realReason));
          while (losingFocusField != null) {
            if (gainingFocusField != null && losingFocusField instanceof Container && ((Container)losingFocusField).isAncestorOf(gainingFocusField)) {
              // This component is the parent of the other component too, so it's not really losing focus. Nor are it's parents
              return;
            }
            if (losingFocusField instanceof JComponent &&
                losingFocusField instanceof DataField == false &&
                losingFocusField instanceof MultiLineTextField == false &&
                losingFocusField instanceof PasswordDataField == false &&
                losingFocusField instanceof JTabbedPane == false) {
           
                  ClientEventManager.postEvent( losingFocusField, cBEFORE_FOCUS_LOSS, params);
            }
            losingFocusField = losingFocusField.getParent();
          }
        }
        finally {
          EventManager.endEventChain();
        }
    }

  /**
   * When a focus gain event occurs, we need to possibly post events all the way up the hierarchy, until
   * we find a component which is still retaining focus. (That is, it is the owning parent of both the
   * losing focus component and the gaining focus component).
   */
    @Override
    public void focusGained(FocusEvent e) {
    Component gainingFocusField = e.getComponent();
    Component losingFocusField = e.getOppositeComponent();
   
    // Don't post the events on the array field if the array field is retaining the focus --
    // the array field will post this automatically
    if (gainingFocusField instanceof ArrayField && ((ArrayField)gainingFocusField).isLosingFocus() == false) {
            return;
        }

    // If the traversal reason is SUPRESS, we cannot post this event
        int realReason = ForteKeyboardFocusManager.getTraversalReason();
        if (realReason == Constants.FC_SUPRESS) {
          return;
        }
       
        EventManager.startEventChain();
        try {
          FocusHelper.addSetFocusPurgeAction((JComponent)gainingFocusField);
          Hashtable<String, Object> params = new Hashtable<String, Object>();
 
          if (gainingFocusField instanceof JComponent) {
              Object table = ArrayFieldCellHelper.getArrayField(gainingFocusField);
 
              if (table != null && table instanceof JTable) {
                  params.put( "ArrayField", new ParameterHolder(table) );
              }
          }
          params.put("reason", new ParameterHolder(realReason));
          while (gainingFocusField != null) {
            if (losingFocusField != null && gainingFocusField instanceof Container && ((Container)gainingFocusField).isAncestorOf(losingFocusField)) {
              // This component is the parent of the other component too, so it's not really losing focus. Nor are it's parents
              return;
            }
            if (gainingFocusField instanceof JComponent &&
                gainingFocusField instanceof DataField == false &&
                gainingFocusField instanceof MultiLineTextField == false &&
                gainingFocusField instanceof PasswordDataField == false &&
                gainingFocusField instanceof JTabbedPane == false) {
           
                  ClientEventManager.postEvent( gainingFocusField, cAFTER_FOCUS_GAIN, params);
            }
            gainingFocusField = gainingFocusField.getParent();
          }
        }
        finally {
          EventManager.endEventChain();
        }
    }

    /**
     * Interface method to install this listener on this child
     */
  public void installChildForParent(JComponent child, Container parent, String event) {
        // TF:12/10/07:Don't allow the registration of focus events on an array, the array will fire these for itself.
      if (child instanceof ArrayField || ArrayFieldCellHelper.getArrayField(child) != null) {
        return;
    }
      // Only install at the lowest level. It doesn't really matter if it gets installed above the lowest level, as
      // the focus will only ever go to focusable components, and these containers aren't focusable.
        if (!(child instanceof JPanel ||
                child instanceof JTabbedPane ||
                child instanceof JTable)) {
         
          // Remove the focus listener first to ensure there is only ever one copy installed
          child.removeFocusListener(this);
          child.addFocusListener(this);
        }
    child.removeContainerListener(this);
    child.addContainerListener(this);
  }
}
TOP

Related Classes of net.helipilot50.stocktrade.displayproject.events.FocusListener

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.