/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.smart.dataui;
import java.awt.Component;
import java.awt.Point;
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.io.Serializable;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
import com.servoy.j2db.persistence.Field;
import com.servoy.j2db.ui.BaseEventExecutor;
import com.servoy.j2db.ui.IComponent;
import com.servoy.j2db.ui.IEventExecutor;
import com.servoy.j2db.ui.IFieldComponent;
import com.servoy.j2db.ui.IFormUI;
import com.servoy.j2db.util.Utils;
/**
* The event executor for the swing (smart) client.
*
* @author jcompagner
*/
public class EventExecutor extends BaseEventExecutor implements MouseListener, FocusListener, Serializable, KeyListener
{
public static final int PREVENT_MULTIPLE_GAIN = 1;
public static final int PREVENT_MULTIPLE_LOST = 2;
private final Component component;
private Component enclosedComponent;
private boolean didAddFocusListener;
private boolean selectAllLater = false;
public EventExecutor(Component comp)
{
this(comp, comp);
}
public EventExecutor(Component comp, Component enclosedcomp)
{
component = comp;
enclosedComponent = enclosedcomp;
}
public void setEnclosedComponent(Component enclosed)
{
if (didAddFocusListener)
{
enclosedComponent.removeFocusListener(this);
enclosed.addFocusListener(this);
}
enclosedComponent = enclosed;
}
public void mouseReleased(MouseEvent e)
{
if (enclosedComponent instanceof JTextComponent && !((JTextComponent)enclosedComponent).isEditable() && SwingUtilities.isLeftMouseButton(e))
{
actionPerformed(e.getModifiers(), e.getPoint());
}
}
private boolean enterKeyPressed = false;
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ENTER)
{
enterKeyPressed = true;
}
}
public void keyReleased(KeyEvent e)
{
//for the moment it's hard-coded (in future, define different methods for different keys
if (e.getKeyCode() == KeyEvent.VK_ENTER && enterKeyPressed)
{
enterKeyPressed = false;
if (enclosedComponent instanceof JTextArea && !((JTextArea)enclosedComponent).isEditable())
{
actionPerformed(e.getModifiers());
}
}
else if (rightClickCommand != null && (e.getKeyCode() == KeyEvent.VK_CONTEXT_MENU || (e.getKeyCode() == KeyEvent.VK_F10 && e.isShiftDown())))
{
Component fieldComponent = enclosedComponent;
if (!(fieldComponent instanceof IComponent))
{
if (fieldComponent.getParent() instanceof IFieldComponent)
{
fieldComponent = fieldComponent.getParent();
}
else if (fieldComponent.getParent() != null && fieldComponent.getParent().getParent() instanceof IFieldComponent)
{
fieldComponent = fieldComponent.getParent().getParent();
}
}
fireRightclickCommand(true, fieldComponent, e.getModifiers(), null);
e.consume();
}
}
public void keyTyped(KeyEvent e)
{
}
public void mouseClicked(MouseEvent e)
{
if (selectAllLater && getSelectOnEnter() && enclosedComponent instanceof JTextComponent)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
selectAllLater = false;
((JTextComponent)enclosedComponent).selectAll();
}
});
}
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
public void mousePressed(MouseEvent e)
{
}
@Override
public void setEnterCmds(String[] enterCommands, Object[][] args)
{
super.setEnterCmds(enterCommands, args);
if (hasEnterCmds() && !didAddFocusListener)
{
enclosedComponent.addFocusListener(this);
didAddFocusListener = true;
}
}
@Override
public void setLeaveCmds(String[] leaveCommands, Object[][] args)
{
super.setLeaveCmds(leaveCommands, args);
if (hasLeaveCmds() && !didAddFocusListener)
{
enclosedComponent.addFocusListener(this);
didAddFocusListener = true;
}
}
@Override
public void setSelectOnEnter(boolean selectOnEnter)
{
super.setSelectOnEnter(selectOnEnter);
if (selectOnEnter && !didAddFocusListener)
{
enclosedComponent.addFocusListener(this);
didAddFocusListener = true;
}
}
/*
* _____________________________________________________________ Methods for handling AWT action event
*/
public void actionPerformed(int modifiers)
{
actionPerformed(modifiers, null);
}
public void actionPerformed(int modifiers, Point mouseLocation)
{
if (hasActionCmd())
{
actionListener.setLastKeyModifiers(modifiers);
fireActionCommand(true, component, modifiers, mouseLocation);
}
}
/*
* _____________________________________________________________ Methods for handling AWT focus events
*/
//safety boolean for extra check in stopEditing (in a listview or table)
private boolean skipFireFocusLostCommand = false;
private boolean skipFireFocusGainedCommandDialogTest = false;
private boolean skipSelectOnEnter = false;
public void skipSelectOnEnter()
{
skipSelectOnEnter = true;
}
public void focusGained(FocusEvent e)
{
selectOnEnter();
skipSelectOnEnter = false;
skipFireFocusLostCommand = false;
if (skipFireFocusGainedCommand)
{
skipFireFocusGainedCommand = false;
skipFireFocusGainedCommandDialogTest = false;
return;
}
if (skipFireFocusGainedCommandDialogTest)
{
skipFireFocusGainedCommandDialogTest = false;
return;
}
if (component instanceof DataChoice)
{
if (e.getOppositeComponent() != null && e.getOppositeComponent().getParent() == null &&
(((DataChoice)component).getChoiceType() == Field.LIST_BOX || ((DataChoice)component).getChoiceType() == Field.MULTISELECT_LISTBOX))
{
// for listbox only trigger if we really entered the field
return;
}
}
fireEnterCommands(true, component, MODIFIERS_UNSPECIFIED);
// only if the component still has focus set the skip on true.
// if a action command did display a dialog the focus is already gone again.
if (e.getComponent().hasFocus())
{
skipFireFocusGainedCommandDialogTest = true;
}
}
/**
*
*/
public void selectOnEnter()
{
if (getSelectOnEnter() && !skipSelectOnEnter)
{
if (enclosedComponent instanceof JTextComponent)
{
if (Utils.isAppleMacOS())
{
// aqua caret will modify caret position on mouse click
selectAllLater = true;
}
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
((JTextComponent)enclosedComponent).selectAll();
}
});
}
}
}
public void focusLost(FocusEvent e)
{
skipFireFocusGainedCommandDialogTest = false;
if (skipFireFocusLostCommand)
{
skipFireFocusLostCommand = false;
return;
}
skipFireFocusLostCommand = true;
if (component instanceof DataChoice)
{
if (e.getOppositeComponent() != null && e.getOppositeComponent().getParent() == null &&
(((DataChoice)component).getChoiceType() == Field.LIST_BOX || ((DataChoice)component).getChoiceType() == Field.MULTISELECT_LISTBOX))
{
// for listbox only trigger if we really left the field
return;
}
}
fireLeaveCommands(component, true, IEventExecutor.MODIFIERS_UNSPECIFIED);
}
public boolean mustFireFocusGainedCommand()
{
return !skipFireFocusGainedCommand && !skipFireFocusGainedCommandDialogTest;
}
public boolean mustFireFocusLostCommand()
{
return !skipFireFocusLostCommand;
}
public void skipNextFocusLost()
{
skipFireFocusLostCommand = true;
}
public void resetFireFocusGainedCommand()
{
skipFireFocusGainedCommandDialogTest = false;
skipFireFocusGainedCommand = false;
}
@Override
protected String getFormName()
{
return getFormName(component);
}
@Override
protected String getFormName(Object display)
{
for (Component container = (Component)display; container != null; container = container.getParent())
{
if (container instanceof IFormUI)
{
return ((IFormUI)container).getController().getName();
}
}
return super.getFormNameInternal();
}
}