Package DisplayProject.events

Source Code of DisplayProject.events.ClickListener

/*
Copyright (c) 2003-2008 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.events;

import java.awt.Component;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Hashtable;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.JTree;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.tree.TreePath;

import org.apache.log4j.Logger;

import DisplayProject.ArrayFieldModel;
import DisplayProject.Constants;
import DisplayProject.DisplayNode;
import DisplayProject.FocusHelper;
import DisplayProject.JListView;
import DisplayProject.PaletteList;
import DisplayProject.TableSorter;
import DisplayProject.UIutils;
import DisplayProject.actions.WidgetState;
import DisplayProject.controls.Graphic;
import DisplayProject.controls.ListView;
import DisplayProject.controls.MultiLineTextField;
import DisplayProject.controls.OutlineField;
import DisplayProject.controls.OutlineFieldJTree;
import Framework.EventHandle;
import Framework.ParameterHolder;

// We need this for JListView
@SuppressWarnings("deprecation")

/**
* This is a generic click listener that produces the Click event
*/
public class ClickListener extends MouseAdapter implements InstallableListener, ActionListener {
    MouseEvent mousePressedEvent;

    public void install(Object o, String pEvent) {
        if (o instanceof JComponent) {
            ((JComponent)o).addMouseListener(this);
            // We also need to register for an action listener on a JButton as well for when the
            // end user hits Enter, which does the same thing as a Click event in Forte.
            if (o instanceof JButton) {
                ((JButton)o).addActionListener(this);
            }
            // CraigM:22/04/2008:Added PaletteList
            else if (o instanceof JComboBox || o instanceof PaletteList) {
                // TF:28/9/07: JComboboxes are a pain because they're comprised of sub widgets and the mouse events etc
                // do not propegate down to the children. See
                // http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=4c4e8224ced82ffffffffaf3337c3360f51e?bug_id=4144505
                // for more details.
                ChildEventHelper.installMouseEvents((JComponent)o, this);
            }
        }
    }

    /**
     * We listen for the mouse pressed event and remember the event, so when the
     * mouse released event occurs, we can still post the mouse clicked event
     * even if the user has dragged the mouse.  Java mouse clicked event will
     * not fire if the user has dragged the mouse one pixel or more.
     *
     * @see java.awt.event.MouseAdapter#mousePressed(java.awt.event.MouseEvent)
     * @since 05/02/2008
     */
    @Override
    public void mousePressed(MouseEvent pEvent) {
      // AGD 7/3/08
      // if a ListView or JTree and the component is Dragable then send a click event
      if ((pEvent.getComponent() instanceof JTree && ((JTree)pEvent.getComponent()).getDragEnabled()) ||
          (ListViewListenerHelper.isMemberOfListView(pEvent.getComponent()) && ((JTable)pEvent.getComponent()).getDragEnabled())) {
            // We post a click event if the button 1 is pressed and the click count is odd.
            if (pEvent.getButton() == MouseEvent.BUTTON1 && ((pEvent.getClickCount() & 1) == 1)) {
                // Post Event to the Target
                Object postTarget;
                if (ListViewListenerHelper.isMemberOfListView(pEvent.getComponent())) {
                    // if the target is a member of the ListView then treat it as if it were the ListView
                  postTarget = ListViewListenerHelper.findListView(pEvent.getComponent());
                } else if (pEvent.getComponent() instanceof OutlineFieldJTree) {
                    // if the target is a member of the OutlineField then treat it as if it were the OutlineField
                  postTarget = ((OutlineFieldJTree)pEvent.getComponent()).getOutlineField();
        } else {
          // default to related component
          postTarget = pEvent.getComponent();
                }
                ClientEventManager.postEvent(postTarget, "Click", ClickListener.makeParamList(pEvent));
            }
          this.mousePressedEvent = null;
    } else {
            this.mousePressedEvent = pEvent;
    }
    }

    /**
     * Process the click action on the component from the mouse. This is not as simple
     * as it could be because not all components in Forte can post double clicks. See the
     * method #canFireDoubleClickEvents for more details
     */
    public void mouseReleased(MouseEvent pEvent) {
      // AGD 7/3/08
      // Check for null because the event may have already been posted by mouse pressed
      if (this.mousePressedEvent != null) {
          MouseEvent e = ChildEventHelper.fixMouseEvent(this.mousePressedEvent);

            if (e.getComponent() instanceof Graphic || e.getComponent().isEnabled()) {

                // Check if the mouse release occurred in the same component.  CraigM: 05/02/2008
                if (this.mousePressedEvent.getComponent() != null) {

                    // If they released the mouse off the component, don't fire the click event
                    if (this.mousePressedEvent.getComponent().contains(pEvent.getX(), pEvent.getY()) == false) {
                        return;
                    }
                }
               
                // This request focus was stopping drop lists from keeping themselves dropped down when
                // they were contained in an ArrayField, and the ArrayField was listening for a click
                // event.  CraigM: 02/04/2008
                // e.getComponent().requestFocus();
               
                // TF:28/9/07:Limited the posting by WidgetState
                // TF:04/12/2009:DET-139:Corrected this to be the true widget state, ie the worst state out of this widget and its parents
                switch (WidgetState.getWorstState(e.getComponent())) {
                    case Constants.FS_DRAG:
                    case Constants.FS_UPDATE:
                    case Constants.FS_VIEWONLY:
                    case Constants.FS_SELECTONLY:
                        // These are the only states we can post this event in, ignore the rest
                        break;
                    default:
                        return;
                }
                // We post a click event if the button 1 is pressed, and either this control cannot
                // fire double clicks, or it can fire double clicks but the click count is odd.
                boolean canDoubleClick = ClickListener.canFireDoubleClickEvents(e.getComponent());
                if (e.getButton() == MouseEvent.BUTTON1 && (!canDoubleClick || ((e.getClickCount() & 1) == 1))) {
                    // Post Event to the Target
                    Object postTarget;
                    if (ListViewListenerHelper.isMemberOfListView(pEvent.getComponent())) {
                        // if the target is a member of the ListView then treat it as if it were the ListView
                      postTarget = ListViewListenerHelper.findListView(pEvent.getComponent());
                    } else if (pEvent.getComponent() instanceof OutlineFieldJTree) {
                        // if the target is a member of the OutlineField then treat it as if it were the OutlineField
                      postTarget = ((OutlineFieldJTree)pEvent.getComponent()).getOutlineField();
            } else {
              // default to related component
              postTarget = e.getComponent();
                    }
                    ClientEventManager.postEvent(postTarget, "Click", ClickListener.makeParamList(e));
                }
            }
    }
    }

    /**
     * Process the click action on the button control, but only for non-mouse events. This
     * ensures that the order of events is correct for mouse events. This action is called
     * when the keyboard triggers the event
     */
    public void actionPerformed(ActionEvent e) {
        if (((JComponent)e.getSource()).isEnabled() &&
                (e.getModifiers() & ActionEvent.MOUSE_EVENT_MASK) == 0) {

            FocusHelper.buttonClick((JButton)e.getSource(), new EventHandle(e.getSource(), "Click", makeParamList(e)));
//            ClientEventManager.postEvent( e.getSource(), "Click", makeParamList(e) );
        }
    }

    static Hashtable<String, Object> makeParamList(ActionEvent e) {
        return makeParamList(0, 0, e.getModifiers(), (JComponent)e.getSource(), false);
    }

    public static Hashtable<String, Object> makeParamList(MouseEvent e) {
        if (ListViewListenerHelper.isMemberOfListView(e.getComponent())) {
            return makeParamList(e.getX(), e.getY(), e.getModifiers(), ListViewListenerHelper.findListView(e.getComponent()), false);
        }
        else if (e.getComponent() instanceof OutlineFieldJTree) {
            return makeParamList(e.getX(), e.getY(), e.getModifiers(), ((OutlineFieldJTree)e.getComponent()).getOutlineField(), false);
        } else {
            return makeParamList(e.getX(), e.getY(), e.getModifiers(), (JComponent)e.getComponent(), false);
        }
    }

    static Hashtable<String, Object> makeParamList(ActionEvent e, boolean pIsChildEvent) {
        return makeParamList(0, 0, e.getModifiers(), (JComponent)e.getSource(), pIsChildEvent);
    }

    // Added: CraigM: 09/08/2007
    public static Hashtable<String, Object> makeParamList(KeyEvent e) {
        return makeParamList(0, 0, e.getModifiers(), (JComponent)e.getSource(), false);
    }

    public static Hashtable<String, Object> makeParamList(MouseEvent e, boolean pIsChildEvent) {
        return makeParamList(e.getX(), e.getY(), e.getModifiers(), (JComponent)e.getComponent(), pIsChildEvent);
    }

  static Hashtable<String, Object> makeParamList(int X, int Y, int mod, JComponent pControl, boolean pIsChildEvent){
        Hashtable<String, Object> params = new Hashtable<String, Object>();
        if (pIsChildEvent) {
            params.put("child", new ParameterHolder(pControl));
        }
        params.put( "x", new ParameterHolder(UIutils.pixelsToMils(X)));
        params.put( "y", new ParameterHolder(UIutils.pixelsToMils(Y)));
        int modifiers = 0;
        if ((mod & ActionEvent.CTRL_MASK) > 0)
            modifiers = modifiers | Constants.KM_CTRL;
        if ((mod & ActionEvent.SHIFT_MASK) > 0)
            modifiers = modifiers | Constants.KM_SHIFT;
        if ((mod & ActionEvent.ALT_MASK) > 0)
            modifiers = modifiers | Constants.KM_ALT_OPTION;
        if ((mod & ActionEvent.META_MASK) > 0)
            modifiers = modifiers | Constants.KM_CMD;
        params.put( "modifier", new ParameterHolder(modifiers) );

        // Set nodes and rows and columns on relevant controls

        if (pControl != null && pControl instanceof OutlineFieldJTree) {
            OutlineFieldJTree tree = (OutlineFieldJTree)pControl;
            OutlineField control = (OutlineField)tree.getOutlineField();

            // TF:27/9/07:Made the row and column 1-based indexes instead of 0-based and used Craig's new method. We need to translate
            // the X-offset by the amount the tree is indented.
            params.put("column", new ParameterHolder(control.getColumnIndex(X + OutlineField.cHEADER_MARGIN_LEFT) + 1));
            params.put( "node", new ParameterHolder(((OutlineFieldJTree)pControl).getLastSelectedPathComponent()) );
            params.put( "row", new ParameterHolder(((OutlineFieldJTree)pControl).getRowForLocation(X, Y)+1) ); //CONV_REM: dc - added row parameter

        }
        else if (pControl != null && pControl instanceof JListView) {
            params.put( "node", new ParameterHolder(((JListView)pControl).getCurrentNode()) );
            params.put( "row", new ParameterHolder(0) );
            params.put( "column", new ParameterHolder(0) );
        }
        else if (pControl != null && pControl instanceof ListView) {
            ListView list = (ListView)pControl;
            params.put( "node", new ParameterHolder(((ListView)pControl).getCurrentNode()) );
            // TF:27/9/07:Made the row and column 1-based indexes instead of 0-based
            // TF:26/3/08:getSelectedRow has changed to be 1-based itself, so we need to change this back to remove the +1
            params.put( "row", new ParameterHolder(list.getSelectedRow()));
//            qq_Params.put( "column", new ParameterHolder(0) );
            params.put( "column", new ParameterHolder(list.getTable().getSelectedColumn()+1) );//CONV_REM:dq Need the column that was selected, not a 0.
        }
        else if (pControl != null && pControl instanceof JTable)
        {
            JTable table = (JTable)pControl;
            if (table.getModel() instanceof TableSorter) {
                DisplayNode dn = ((DisplayNode)((ArrayFieldModel)((TableSorter)table.getModel()).getTableModel()).getData().get(table.getSelectedRow()));
                params.put( "node", new ParameterHolder(dn) );
            }
            else {
                params.put( "node", new ParameterHolder(null) );
            }
            // TF:23/9/07:We need to return the X and Y coordinates with respect to the cell, not the table. Also, we need
            // to change the child to the renderer or editor for that cell.
            Point loc = new Point(X, Y);
            int row = table.rowAtPoint(loc);
            int column = table.columnAtPoint(loc);
            // TF:27/9/07:Made the row and column 1-based indexes instead of 0-based
            params.put( "row", new ParameterHolder(row+1) );
            params.put( "column", new ParameterHolder(column+1) );

            // make sure we have a valid cell, just in case they click outside the table, eg in the empty scroll pane.
            if (row >= 0 && column >= 0) {
                Rectangle cellBounds = table.getCellRect(row, column, false);
                X -= cellBounds.x;
                Y -= cellBounds.y;

                TableCellRenderer renderer = table.getCellRenderer(row, column);
                if (renderer != null) {
                    Component c = renderer.getTableCellRendererComponent(table, table.getValueAt(row, column), false, false, row, column);
                    params.put("child", new ParameterHolder(c));
                }
            }
        }
        else if (pControl != null && pControl instanceof JTree)
        {
          JTree tree = (JTree) pControl;
            int currentRow = getRowForLocation(Y, tree);
            // TF:27/9/07:Made the row and column 1-based indexes instead of 0-based
            params.put( "row", new ParameterHolder(currentRow+1) );
            TreePath path = tree.getPathForRow(currentRow);
            if (path != null) {
              params.put("node", new ParameterHolder(path.getLastPathComponent()));
            }
            else {
              params.put("node", new ParameterHolder(null));
            }
        }
        else if (pControl instanceof OutlineField) {
          OutlineField outlineField = (OutlineField) pControl;
            int currentRow = getRowForLocation(Y, outlineField.getTree());
            TreePath path = outlineField.getTree().getPathForRow(currentRow);
            if (path != null) {
              params.put("node", new ParameterHolder(path.getLastPathComponent()));
            }
            else {
              params.put("node", new ParameterHolder(null));
            }
            // TF:27/9/07:Made the row and column 1-based indexes instead of 0-based, plus used Craig's new method
            params.put("row", new ParameterHolder(currentRow+1));
            params.put("column", new ParameterHolder(outlineField.getColumnIndex(X + OutlineField.cCOLUMN_SPACING)+1));
            params.put("sizes", new ParameterHolder(outlineField.getColumnSizes()));
            params.put("spacing", new ParameterHolder(OutlineField.cCOLUMN_SPACING));
        }
        else if (pControl instanceof MultiLineTextField){
            MultiLineTextField field = (MultiLineTextField)pControl;
            try {
                int offset = field.getCaretPosition()-1;
                int lRow = field.getLineOfOffset(offset);
                int lCol = offset - field.getLineStartOffset(lRow);
                params.put("row", new ParameterHolder(lRow));
                params.put("column", new ParameterHolder(lCol));
            }
            catch (BadLocationException ble) {
                Logger.getLogger(ClickListener.class).error("Bad location for text field", ble);
                params.put("row", new ParameterHolder(0));
                params.put("column", new ParameterHolder(0));
            }
        }
        // Handle a PaletteList.  CraigM: 22/04/2008
        else if (pControl instanceof PaletteList) {
          PaletteList pl = (PaletteList)pControl;
          Component comp = pl.getComponentAt(X, Y);
          if (comp instanceof JToggleButton) {
                params.put( "row", new ParameterHolder(pl.getIndexValue((JToggleButton)comp)));
          }
          else {
                params.put( "row", new ParameterHolder(0) );
          }
            params.put( "column", new ParameterHolder(0) );
            params.put( "node", new ParameterHolder(null) );
        }
        else
        {
            params.put( "row", new ParameterHolder(0) );
            params.put( "column", new ParameterHolder(0) );
            params.put( "node", new ParameterHolder(null) );
        }

        return params;
    }

    /**
     * Method to return the row for of a tree based only on the y coordinate.
     * This is a work around to post similar events to Forte. Forte posts node
     * even if you don't directly click on it, as long as it is on the same x axis
     * @param y
     * @param tree
     * @return the row number. Returns -1 if the row is not found
     */
    private static int getRowForLocation(int y, JTree tree) {
     
      final int maxScreenWidth = 1024;
      int row = -1;
      // for performance reasons only check every second pixel
    for (int x = 0; x < maxScreenWidth; x = x + 2) {
      row = tree.getRowForLocation(x, y);
      if (row != -1) {
        // row found
        break;
      }
    }
    return row;
  }

  /**
     * In forte, not all events can fire double-clicks. For example, a PushButton cannot fire
     * them because the behaviour would be confusing to the end user. Accoring to the Forte
     * help, double clicks can be fired for CompoundField and subclasses, Graphic and subclasses,
     * OutlineField, PictureField, ScrollList, RadioList, PaletteList and CharacterField. The
     * appropriate java classes are returned as true if they can fire double clicks
     * @param pComponent The component to test to see if it can fire double clicks
     * @return True if the component can fire double clicks, false otherwise.
     */
  public static boolean canFireDoubleClickEvents(Component pComponent) {
        return ((pComponent instanceof JPanel) ||
                (pComponent instanceof JTable) ||
                (pComponent instanceof JListView) ||
                (pComponent instanceof ListView) ||
                (pComponent instanceof JTree) ||
                (pComponent instanceof JLabel) ||
                (pComponent instanceof JList) ||
                (pComponent instanceof JRadioButton) ||
                (pComponent instanceof Graphic) ||
                (pComponent instanceof JTextComponent) ||
                (pComponent instanceof OutlineField));
    }
}
TOP

Related Classes of DisplayProject.events.ClickListener

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.