/*
* $Id$
* This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc
*
* Copyright (c) 2000-2012 Stephane GALLAND.
* Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
* Universite de Technologie de Belfort-Montbeliard.
* Copyright (c) 2013-2016 The original authors, and other authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.arakhne.afc.ui.swing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.HierarchyBoundsListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.Point2D;
import java.lang.ref.WeakReference;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.text.Document;
/**
* This class provides a UI panel that permits to enter
* the string in a popup text field.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 4.0
* @deprecated see JavaFX API
*/
@Deprecated
public class JPopupTextField extends JPanel {
private static final long serialVersionUID = 374219507363847111L;
/** Default size of the border.
*/
protected static final int BORDER_SIZE = 3;
private final WeakReference<JComponent> component;
private Point2D preferredLocation = null;
private final EventHandler handler = new EventHandler();
private final JTextField textField = new JTextField();
/**
* @param owner is the component which is owning this popup text field.
* @param borderColor is the color of the borders of the pane.
* @param backColor is the color of the background of the pane.
*/
public JPopupTextField(JComponent owner, Color borderColor, Color backColor) {
setFocusable(true);
this.component = new WeakReference<>(owner);
Font font = this.textField.getFont();
int size = font.getSize() - 2;
Font smallFont = font.deriveFont(size);
this.textField.setFont(smallFont);
this.textField.setMinimumSize(new Dimension(2*font.getSize(), font.getSize()));
this.textField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "Cancel"); //$NON-NLS-1$
this.textField.getActionMap().put("Cancel", new AbstractAction() { //$NON-NLS-1$
private static final long serialVersionUID = -2343325366957567597L;
@Override
public void actionPerformed(ActionEvent e) {
hideInputComponent();
}
});
setLayout(new BorderLayout());
add(this.textField, BorderLayout.CENTER);
if (borderColor!=null)
setBorder(BorderFactory.createLineBorder(borderColor));
if (backColor!=null)
setBackground(backColor);
}
/** Set the preferred location of the popup text field.
*
* @param x
* @param y
*/
public void setPreferredLocation(float x, float y) {
Point2D old = this.preferredLocation;
if (old==null || old.getX()!=x || old.getY()!=y) {
this.preferredLocation = new Point2D.Float(x,y);
layoutInputComponent();
firePropertyChange("preferredLocation", old, this.preferredLocation); //$NON-NLS-1$
}
}
/** Set the preferred location of the popup text field.
*
* @param p
*/
public void setPreferredLocation(Point2D p) {
Point2D old = this.preferredLocation;
if (old!=p &&
(old==null || p==null || !p.equals(old))) {
this.preferredLocation = p;
layoutInputComponent();
firePropertyChange("preferredLocation", old, this.preferredLocation); //$NON-NLS-1$
}
}
/** Replies the preferred location of the popuptext field.
*
* @return the preferred location or <code>null</code> if none.
*/
public Point2D getPreferredLocation() {
return this.preferredLocation;
}
/** Replies the embedded text field.
*
* @return the embedded text field.
*/
protected JTextField getTextField() {
return this.textField;
}
/** Replies the document used by this puop up text field.
*
* @return the document.
*/
public Document getDocument() {
return this.textField.getDocument();
}
/** Set the document used by this puop up text field.
*
* @param doc is the the new document.
*/
public void setDocument(Document doc) {
this.textField.setDocument(doc);
}
/** Add listener on the validation action in the popup text field.
*
* @param listener
*/
public void addActionListener(ActionListener listener) {
this.listenerList.add(ActionListener.class, listener);
}
/** Remove listener on the validation action in the popup text field.
*
* @param listener
*/
public void removeActionListener(ActionListener listener) {
this.listenerList.remove(ActionListener.class, listener);
}
/**
* Fire the event that corresponds to the validation in the popup text field.
*
* @param eventSource
*/
protected void fireValidationAction(ActionEvent eventSource) {
ActionListener[] list = this.listenerList.getListeners(ActionListener.class);
for(ActionListener listener : list) {
listener.actionPerformed(eventSource);
}
}
/** Invoked when the validation action was processed.
* <p>
* By default this function does nothing.
*/
protected void onValidationAction() {
//
}
/** Simulate the "enter" key press.
*/
public void doValidation() {
ActionEvent e = new ActionEvent(this,
ActionEvent.ACTION_PERFORMED,
null,
System.currentTimeMillis(),
0);
fireValidationAction(e);
}
/** Simulate the "enter" key press.
*
* @param sourceEvent is the event that has cause the validation.
*/
public void doValidation(ActionEvent sourceEvent) {
assert(sourceEvent!=null);
ActionEvent e = sourceEvent;
if (e.getSource()!=this) {
e = new ActionEvent(this,
sourceEvent.getID(),
sourceEvent.getActionCommand(),
sourceEvent.getWhen(),
sourceEvent.getModifiers());
}
hideInputComponent();
onValidationAction();
fireValidationAction(e);
}
/** Replies the associated owner component.
*
* @return the associated owner component.
*/
public JComponent getOwner() {
return this.component.get();
}
/** Resize and move the popup text field to fit the owner bounds.
*/
protected void layoutInputComponent() {
JComponent component = getOwner();
if (component!=null && getParent()!=null) {
Dimension cdim = getPreferredSize();
if (cdim==null) cdim = new Dimension(100, 20);
setSize(cdim);
JRootPane root = component.getRootPane();
JLayeredPane lpane = root.getLayeredPane();
Rectangle r = component.getVisibleRect();
r = SwingUtilities.convertRectangle(component, r, lpane);
int x = 0;
int y = 0;
if (this.preferredLocation!=null) {
Point p = new Point();
p.setLocation(this.preferredLocation);
p = SwingUtilities.convertPoint(component, p, lpane);
x = p.x;
y = p.y;
}
if (x+cdim.width>r.width) x = r.width - cdim.width;
if (y+cdim.height>r.height) y = r.height - cdim.height;
if (x<0) x = 0;
if (y<0) y = 0;
setLocation(x, y);
revalidate();
}
}
/**
* {@inheritDoc}
*/
@Override
public void setVisible(boolean aFlag) {
if (aFlag) {
showInputComponent();
}
else {
hideInputComponent();
}
}
/** Show the popup text field.
*
* @return <code>true</code> if the component was shown,
* otherwise <code>false</code>.
*/
protected boolean showInputComponent() {
JComponent component = getOwner();
if (component!=null && getParent()==null) {
JRootPane root = component.getRootPane();
JLayeredPane lpane = root.getLayeredPane();
lpane.add(this, JLayeredPane.PALETTE_LAYER);
layoutInputComponent();
super.setVisible(true);
this.textField.requestFocusInWindow();
this.textField.addActionListener(this.handler);
this.textField.addFocusListener(this.handler);
this.textField.addHierarchyBoundsListener(this.handler);
onPopupFieldOpened();
return true;
}
return false;
}
/** Hide the popup text field.
*
* @return <code>true</code> if the component was hidden,
* otherwise <code>false</code>.
*/
protected boolean hideInputComponent() {
JComponent component = getOwner();
if (component!=null && getParent()!=null) {
this.textField.removeFocusListener(this.handler);
this.textField.removeActionListener(this.handler);
super.setVisible(false);
JRootPane root = component.getRootPane();
if (root!=null) {
JLayeredPane lpane = root.getLayeredPane();
if (lpane!=null) lpane.remove(this);
}
component.requestFocusInWindow();
onPopupFieldClosed();
return true;
}
return false;
}
/** Invoked when the popup field is closed.
*/
protected void onPopupFieldClosed() {
//
}
/** Invoked when the popup field is opened.
*/
protected void onPopupFieldOpened() {
//
}
/**
* Replies the text inside the text field.
*
* @return the text.
*/
public String getText() {
return this.textField.getText();
}
/**
* Set the text inside the field.
*
* @param text
*/
public void setText(String text) {
this.textField.setText(text);
}
/**
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 4.0
*/
private class EventHandler
implements FocusListener, ActionListener,
HierarchyBoundsListener {
/**
*/
public EventHandler() {
//
}
//--------------------------------
// FocusListener
//--------------------------------
/**
* {@inheritDoc}
*/
@Override
public void focusGained(FocusEvent e) {
//
}
/**
* {@inheritDoc}
*/
@Override
public void focusLost(FocusEvent e) {
hideInputComponent();
}
//--------------------------------
// KeyListener
//--------------------------------
/**
* {@inheritDoc}
*/
@Override
public void actionPerformed(ActionEvent e) {
doValidation(e);
}
//--------------------------------
// FocusListener
//--------------------------------
/**
* {@inheritDoc}
*/
@Override
public void ancestorMoved(HierarchyEvent e) {
//
}
/**
* {@inheritDoc}
*/
@Override
public void ancestorResized(HierarchyEvent e) {
layoutInputComponent();
}
}
}