Package DisplayProject.actions

Source Code of DisplayProject.actions.Focus

/*
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 DisplayProject.actions;

import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.awt.KeyboardFocusManager;

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

import DisplayProject.ArrayColumn;
import DisplayProject.ArrayColumnModel;
import DisplayProject.CompoundField;
import DisplayProject.Constants;
import DisplayProject.UIutils;
import DisplayProject.WindowManager;
import DisplayProject.controls.ArrayField;
import DisplayProject.controls.CompoundGraphic;
import DisplayProject.events.ClientEventManager;
import DisplayProject.table.ArrayFieldCellHelper;
import Framework.EventHandle;
import Framework.EventManager;
import Framework.ForteKeyboardFocusManager;
/**
* This pending action allows the request focus to be effected on the EDT
*
*/
public class Focus extends ReversableAction {
    public static final String QQ_INITIAL_FOCUS_COMPONENT = "qq_InitialFocusComponent"; // CraigM: 26/02/2008.
    public static final String QQ_INITIAL_FOCUS_ROW = "qq_InitialFocusRow"; // CraigM:01/05/2008.
    private int row = 0;
    int scrollpolicy = Constants.AF_AUTOMATIC; // CraigM: 20/02/2008.

    public Focus(Component pComponent) {
        super(pComponent);
    }

    public Focus(Component pComponent, int row) {
        this(pComponent);
        this.row = row;
    }

    public Focus(Component pComponent, int row, int policy) {
        this(pComponent);
        this.row = row;
        this.scrollpolicy = policy;
    }

    public void performAction() {
        performAction(this.getComponent());
    }

    public void performAction(Component component) {
        // Don't move the focus if the focus can't be moved (keeping with what Forte did).  CraigM 30/11/2007.
        if(component == null || component.isFocusable() == false || component.isEnabled() == false) {
          // TF:20/06/2008:If this component is a compoundfield then don't return, as there is code lower down
          // which will set the focus to the first component within this compound field.
          if (!(component instanceof CompoundField)) {
                return;
          }
        }
        Component rootComponent = SwingUtilities.getRoot(component);
       
        // If we are in an ArrayField, then we need to go from there
        if (rootComponent == null) {
          ArrayField af = ArrayFieldCellHelper.getArrayField(component);
          if (af != null) {
            rootComponent = SwingUtilities.getRoot(af);
          }
        }

        // If our frame is not visible, then we can't set the focus yet.  We just flag our form
        // to set the focus once it becomes visible.  CraigM: 26/02/2008.
        if (rootComponent instanceof JFrame && ((JFrame)rootComponent).isVisible() == false) {
          JPanel form = UIutils.getForm((JFrame)rootComponent);

          if (form != null) {
            form.putClientProperty(QQ_INITIAL_FOCUS_COMPONENT, component);
            form.putClientProperty(QQ_INITIAL_FOCUS_ROW, row);
            return;
          }
        }
       
        // TF:10/7/07: Added in the application traversal type for the Forte-style focus manager
        // Since this pending action only ever occurs as the result of the application requesting
        // the focus to change, we set a flag to indicate that this is the case.
        ForteKeyboardFocusManager.setApplicationTraversal();
       
        // TF:11/03/2009:DET-82:In forte, you could try to focus on an array field, and either provide a row
        // in which case the focus would go to the first row or the row'th row if specified.
        if (component instanceof JComponent) {
            ArrayField af;
            if (component instanceof ArrayField) {
              af = (ArrayField)component;
              // Now set the component to the first visible column on the designated row
              component = ArrayFieldCellHelper.getArrayEditorComponent(af, row, 0);
              if (component == null) {
                // We cannot find the first visible component, do nothing
                return;
              }
            }
            else {
              af = ArrayFieldCellHelper.getArrayField(component);
            }
            if (af != null) {
                int col = ArrayFieldCellHelper.getArrayFieldColumn((JComponent)component);
                //PM:23/11/07 correct for invisible columns
                ArrayColumn ac = (ArrayColumn)((ArrayColumnModel)af.getColumnModel()).getRealColumn(col);
                col = ((ArrayColumnModel)af.getColumnModel()).getColumnIndex(ac.getIdentifier());

                // If an explicit focus request occurs on an empty array field that allows append, then create
                // a new row (that's what Forte did).  CraigM 16/10/2007.
                if (af.getRowCount() == 0 && af.isAllowsAppend()) {
                    af.appendRow(col);
                }
                else if (row >= af.getRowCount()) {
                  // TF:11/03/2009:A request has been made to focus to a non-existant row, do nothing
                  return;
                }

                // CraigM:01/05/2008 - Let all other swing event happen before requesting the focus in here
                final ArrayField afFinal = af;
                final int colFinal = col;
               
                // CraigM:25/06/2008 - Switched from SwingUtilities.invokeLater
                UIutils.invokeOnGuiThread(new Runnable() {
                  public void run() {
                    // CraigM:09/07/2008 - Now ArrayField has been fixed, we can just change the selection
                    afFinal.changeSelection(row, colFinal, false, false);
                  }
                });
            } else {
                // TF:27/11/07:(Credit to java almanac...) If we can't set the focus in the window, it's possibly
                // because we're not focusable, such as a grid field. In this case we want to set the focus to our
                // first focusable child. This is done most easily by getting the focusable component before us,
                // and then getting it's following component. If we just use getComponentAfter, we run the risk of
                // selecting the first component in the next container
                if (!component.requestFocusInWindow()) {
                  // TF:Mar 4, 2010:If we have a large list of children in a compound graphic, say more than 10,
                  // we have an issue with performance. This is an unlikely case, so we'll avoid this processing in this case
                  if (!(component instanceof CompoundGraphic && ((JComponent)component).getComponentCount() > 10)) {
                      Container root = component.getFocusCycleRootAncestor();
 
                      if (root != null) {
                          FocusTraversalPolicy policy = root.getFocusTraversalPolicy();
                          Component previousFocus = policy.getComponentBefore(root, component);
                          Component nextFocus = policy.getComponentAfter(root, previousFocus == null ? component : previousFocus);
                          if (nextFocus != null) {
                              nextFocus.requestFocusInWindow();
                          }
                      }
                  }
                }

                // If an explicit focus request occurs on the next row in an array field (or an empty array field) that allows
                // append, then create a new row (that's what Forte did).  CraigM: 04/08/2008.
                if (component instanceof ArrayField &&
                    (((ArrayField)component).getRowCount() == 0 || ((ArrayField)component).getRowCount() == row) &&
                    ((ArrayField)component).isAllowsAppend()) {
                    ((ArrayField)component).appendRow(0);
                }
            }
        } else
            component.requestFocus();
    }

    /**
     * We want focus requests to be done after all other request that may be on the queue.  This can happen
     * in situations like the focus has been requests on a after focus gain event triggered by a button click
     * event.  We actually want the button click to occur before the request focus.
     * CraigM:07/07/2008.
     *
     * @param onComponent
     */
    private static void setFocus(final Component onComponent, final Focus event) {
      if (SwingUtilities.isEventDispatchThread()) {
          ActionMgr.addAction(event);
      }
      else {
          EventHandle handle = new EventHandle(onComponent, "dummy, cannot be caught");
          JFrame topLevel = UIutils.getWindowForComponent(onComponent);
          if (topLevel != null) {
            Thread windowThread = WindowManager.getOwningThread(topLevel);
            if (windowThread == null) {
              windowThread = Thread.currentThread();
            }
            handle.setForceReceiptOfEvent(windowThread);
            handle.setPriority(EventHandle.PRIORITY_EDT);
            handle.setReceiptForcedOnTopLevel(true);
            handle.setCommencementNotifier(new Runnable() {
                public void run() {
                  UIutils.waitForEDTToBeIdle();
                  ActionMgr.addAction(event);
                  UIutils.processGUIActions();
                }
            });
 
            // CraigM:11/02/2009 - If we have pending events, we can just add the event to the end.
          if (EventManager.hasPendingEvents()) {
              ClientEventManager.postEvent(handle);
          }
          // CraigM:11/02/2009 - If there are no pending events, then we may not have started the
          // event manager yet, so just add the request to the end of the EDT queue.
          // TF:07/04/2009:Note however that this will be performed on the EDT and hence ActionMgr.addAction(event)
          // would be just the same as doing event.performAction(), ie it will NOT be added to the queue of events
          // nor will the other events in the queue get processed first. Hence we MUST process GUI actions prior
          // to doing this, or actions in the queue that were added prior to now might not get executed before
          // this focus change, but executed after it. See DET-92
          else {
            UIutils.processGUIActions();
            SwingUtilities.invokeLater(new Runnable() {
              public void run() {
                      UIutils.waitForEDTToBeIdle();
                      ActionMgr.addAction(event);
              }
            });
          }
          }
      }
    }

    public static void set(Component comp) {
        Focus.setFocus(comp, new Focus(comp));
    }

    /**
     * Set the focus on the form within the passed window.
     * @param comp
     */
    public static void set(JFrame comp) {
      Focus.setFocus(comp, new Focus(UIutils.getForm(comp)));
    }
    /**
     * This version of the method is used to set the correct focus in a JTable
     * @param comp
     * @param row - zero base row of the jTable
     */
    public static void set(Component comp, int row) {
      Focus.setFocus(comp, new Focus(comp, row));
    }

    /**
     * Request the focus on a particular row on a JTable with a particular scroll policy.
     *
     * @param comp
     * @param row
     * @param policy
     * <table>
     * <th>Value</th><th>Definition</th>
     * <tr valign=top><td>AF_AUTOMATIC</td>  <td>If row is above display area, scroll to first array field display row. If row is beneath display area, scroll to last array field display row. No scrolling occurs if row is already in display area.</td></tr>
     * <tr valign=top><td>AF_BOTTOM</td>  <td>Scrolls row to bottom array field display row.</td></tr>
     * <tr valign=top><td>AF_DEFAULT</td>  <td>If row is above display area, scrolls row to top array field display row. If row is beneath display area, scrolls row to bottom array field display row. No scrolling occurs if row is already in display area.</td></tr>
     * <tr valign=top><td>AF_MIDDLE</td>  <td>Scrolls row to middle array field display row.</td></tr>
     * <tr valign=top><td>AF_TOP</td>    <td>Scrolls row to top array field display row.</td></tr>
     * </table>
     * Written by Craig Mitchell
     * @since 20/02/2008
     */
    public static void set(Component comp, int row, int policy) {
      Focus.setFocus(comp, new Focus(comp, row, policy));
    }

    public PendingAction createReverseAction() {
        return null;
    }

    public boolean isSameAction(PendingAction a) {
        return (a instanceof Focus) && (a._component == this._component);
    }

    @Override                                   //JVM 1.5
    public String toString() {
        if (this._component != null) {
            return "Focus [" + this._component.toString() + "]";
        }
        else {
            return "Focus [null]";
        }
    }

    @Override
    public PendingAction applyActionTo(Component component) {
        // TF: This probably shouldn't be a reversable action, and we certainly don't want it applied each time
        // we edit the cell, so ignore this request.
        return null;
    }
    /**
     * TF:11/10/07:We should always fire focus events, irrespective of whether the focus has changes programmatically
     * or explicitly from the user. This can be an issue with things like the array field where these changing the
     * focus into the array should fire after row entry events and that sort of thing.
     */
    @Override
    public boolean shouldFireEvents() {
        return true;
    }

    /**
     * Return the current focus owner. This will either be the last Focus action on the queue, or the
     * current focus owner. Note that there is no guarantee that the focus action will succeed if the
     * focus cannot be set to that field, so this method may return a focused item that is not, and
     * never will be, the real focused item
     * @return
     */
    public static Component get() {
        Focus action = (Focus) ActionMgr.getAction(new ActionMgr.Filter() {
            public boolean filter(PendingAction action) {
                return action instanceof Focus;
            }
        });

        if (action != null) {
            return action.getComponent();
        }
        else {
            return KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        }

    }
}
TOP

Related Classes of DisplayProject.actions.Focus

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.