/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.swing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FocusTraversalPolicy;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.IllegalComponentStateException;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.EventObject;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.FocusManager;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.openflexo.icon.UtilsIconLibrary;
import org.openflexo.toolbox.ToolBox;
/**
* Abstract widget allowing to edit a complex object with a popup
*
* @author sguerin
*
*/
public abstract class CustomPopup<T> extends JPanel implements ActionListener, MouseListener {
protected static final Logger logger = Logger.getLogger(CustomPopup.class.getPackage().getName());
public static final CustomPopupConfiguration configuration = new CustomPopupConfiguration();
private static final int BULLETS = 3;
private static final int BULLET_SPACING = 2;
private static final int BULLET_SIZE = 3;
public T _editedObject;
protected JButton _downButton;
public JComponent _frontComponent;
private List<ApplyCancelListener> applyCancelListener;
private int posX;
private int posY;
public CustomJPopupMenu _popup;
private ResizablePanel _customPanel;
public interface ApplyCancelListener {
public void fireApplyPerformed();
public void fireCancelPerformed();
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (!enabled && popupIsShown()) {
closePopup();
}
if (_frontComponent != null) {
_frontComponent.setEnabled(enabled);
}
if (_downButton != null) {
_downButton.setEnabled(enabled);
}
}
protected abstract JComponent buildFrontComponent();
public CustomPopup(T editedObject) {
super(new BorderLayout());
_editedObject = editedObject;
if (ToolBox.getPLATFORM() != ToolBox.MACOS) {
_downButton = new ImageButton(UtilsIconLibrary.CUSTOM_POPUP_BUTTON);
} else {
_downButton = new ImageButton(UtilsIconLibrary.CUSTOM_POPUP_DOWN);
_downButton.setDisabledIcon(UtilsIconLibrary.CUSTOM_POPUP_DOWN_DISABLED);
}
_downButton.addActionListener(this);
add(_downButton, BorderLayout.WEST);
/*Border border = getDownButtonBorder();
if (border != null) {
_downButton.setBorder(border);
}*/
setOpaque(false);
if (ToolBox.getPLATFORM() != ToolBox.MACOS) {
setBorder(BorderFactory.createEmptyBorder(3, 5, 3, 5));
}
_frontComponent = buildFrontComponent();
add(_frontComponent, BorderLayout.CENTER);
applyCancelListener = new Vector<ApplyCancelListener>();
setFocusTraversalPolicy(new FocusTraversalPolicy() {
@Override
public Component getComponentAfter(Container arg0, Component arg1) {
return null;
}
@Override
public Component getComponentBefore(Container arg0, Component arg1) {
return null;
}
@Override
public Component getDefaultComponent(Container arg0) {
return _frontComponent;
}
@Override
public Component getFirstComponent(Container arg0) {
return _frontComponent;
}
@Override
public Component getLastComponent(Container arg0) {
return _frontComponent;
}
});
}
@Override
public void setBackground(Color bg) {
super.setBackground(bg);
if (_frontComponent != null) {
_frontComponent.setBackground(bg);
}
}
@Override
public void setForeground(Color fg) {
super.setForeground(fg);
if (_frontComponent != null) {
_frontComponent.setForeground(fg);
}
}
public JComponent getFrontComponent() {
return _frontComponent;
}
@Override
public void setFont(Font aFont) {
super.setFont(aFont);
if (_frontComponent != null) {
_frontComponent.setFont(aFont);
}
}
public static abstract class ResizablePanel extends JPanel {
public abstract Dimension getDefaultSize();
}
protected void deleteCustomPanel() {
_customPanel = null;
}
public JComponent getDownButton() {
return _downButton;
}
public ResizablePanel getCustomPanel() {
if (_customPanel == null) {
try {
_customPanel = createCustomPanel(getEditedObject());
} catch (ClassCastException e) {
_customPanel = createCustomPanel(null);
}
_customPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
}
return _customPanel;
}
protected abstract ResizablePanel createCustomPanel(T editedObject);
private void makePopup() {
if (logger.isLoggable(Level.FINE)) {
logger.fine("makePopup()");
}
Point p = new Point();
try {
p = this.getLocationOnScreen();
} catch (IllegalComponentStateException e) {
e.printStackTrace();
p = getLocation();
}
// Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
// Avoid popup behind dock
// dim.height = dim.height - 50;
posX = p.x;/* +getWidth()-getCustomPanel().getWidth(); */
posY = p.y + getHeight() - 1;
int newWidth = getCustomPanel().getDefaultSize().width;
int newHeight = getCustomPanel().getDefaultSize().height;
/*
* if (posX + getCustomPanel().getDefaultSize().width > dim.width) { posX = dim.width - getCustomPanel().getDefaultSize().width -
* 20; } if (posY + getCustomPanel().getDefaultSize().height > dim.height) { newHeight = dim.height - posY; }
*/
getCustomPanel().setPreferredSize(new Dimension(newWidth, newHeight));
// _customPopup = popupFactory.getPopup(this, getCustomPanel(), posX,
// posY);
_popup = new CustomJPopupMenu(this);
Rectangle popupRectangle = new Rectangle(posX, posY, newWidth, newHeight);
Rectangle thisRectangle = new Rectangle();
thisRectangle.setLocation(p);
thisRectangle.setSize(getSize());
Rectangle union = thisRectangle.union(popupRectangle);
popupLiveArea = union;
}
protected class CustomJPopupMenu extends JDialog {
protected class ParentPopupMoveListener implements ComponentListener {
private Point parentPosition;
public ParentPopupMoveListener() {
if (CustomJPopupMenu.this.getOwner() != null && CustomJPopupMenu.this.getOwner().isVisible()) {
parentPosition = CustomJPopupMenu.this.getOwner().getLocationOnScreen();
}
}
@Override
public void componentHidden(ComponentEvent e) {
}
@Override
public void componentMoved(ComponentEvent e) {
updatePopupLocation();
}
@Override
public void componentResized(ComponentEvent e) {
updatePopupLocation();
}
@Override
public void componentShown(ComponentEvent e) {
parentPosition = CustomJPopupMenu.this.getOwner().getLocationOnScreen();
}
private void updatePopupLocation() {
Point newPosition = getLocation();
newPosition.x += CustomJPopupMenu.this.getOwner().getLocationOnScreen().x - parentPosition.x;
newPosition.y += CustomJPopupMenu.this.getOwner().getLocationOnScreen().y - parentPosition.y;
CustomJPopupMenu.this.setLocation(newPosition);
parentPosition = CustomJPopupMenu.this.getOwner().getLocationOnScreen();
}
}
protected List<CustomJPopupMenu> _childs;
protected boolean _popupIsShown = false;
private ParentPopupMoveListener parentListener;
public CustomJPopupMenu(CustomPopup<?> invoker) {
super((Window) SwingUtilities.getAncestorOfClass(Window.class, invoker));
_childs = new Vector<CustomJPopupMenu>();
parentListener = new ParentPopupMoveListener();
setUndecorated(true);
getRootPane().setBorder(BorderFactory.createLineBorder(Color.BLACK));
getContentPane().add(invoker.getCustomPanel());
CustomJPopupMenu parentPopupMenu = getParentPopupMenu();
if (parentPopupMenu != null) {
parentPopupMenu._childs.add(this);
}
if (logger.isLoggable(Level.FINE)) {
logger.fine("This popup is " + this.hashCode() + " Parent popup is "
+ (parentPopupMenu == null ? "null" : parentPopupMenu.hashCode()));
// logger.info("Made new popup: "+Integer.toHexString(hashCode())+(getParentPopupMenu()!=null?" with parent: "+Integer.toHexString(getParentPopupMenu().hashCode()):""));
}
}
private void registerParentListener() {
if (getOwner() != null) {
getOwner().addComponentListener(parentListener);
}
}
private void unregisterParentListener() {
if (getOwner() != null) {
getOwner().removeComponentListener(parentListener);
}
}
protected CustomPopup<?> getCustomPopup() {
return CustomPopup.this;
}
public boolean isChildOf(Window w) {
return w instanceof CustomPopup.CustomJPopupMenu && ((CustomPopup.CustomJPopupMenu) w).isParentOf(this);
}
public boolean isParentOf(Window w) {
return w != null && (w.getOwner() == this || isParentOf(w.getOwner()));
}
@Override
public void paint(Graphics g) {
super.paint(g);
int y = getSize().height - BULLET_SPACING - 5;
for (int i = 0; i < 3; i++) {
for (int j = i; j < 3; j++) {
int x = getSize().width - BULLETS * BULLET_SIZE - (BULLETS - 1) * BULLET_SPACING + j * (BULLET_SIZE + BULLET_SPACING)
- 5;
g.setColor(Color.LIGHT_GRAY);
g.fillRect(x, y, BULLET_SIZE, BULLET_SIZE);
}
y -= BULLET_SIZE + BULLET_SPACING;
}
}
@Override
public void setVisible(boolean aBoolean) {
// logger.info((aBoolean?"Show popup":"Hide popup")+" "+Integer.toHexString(hashCode()));
if (logger.isLoggable(Level.FINE)) {
logger.fine("setVisible " + aBoolean + " for " + this.hashCode());
}
if (aBoolean) {
_requestVisibility = true;
} else {
for (CustomJPopupMenu child : _childs) {
child.setVisible(false);
}
for (CustomJPopupMenu child : _childs) {
if (child.requestVisibility()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("setVisible " + aBoolean + " forget it");
}
return;
}
}
}
super.setVisible(aBoolean);
_popupIsShown = aBoolean;
if (aBoolean) {
registerParentListener();
_requestVisibility = false;
} else {
unregisterParentListener();
}
}
private boolean _requestVisibility;
public boolean requestVisibility() {
return _requestVisibility;
}
public CustomJPopupMenu getParentPopupMenu() {
if (getOwner() instanceof CustomPopup.CustomJPopupMenu) {
return (CustomJPopupMenu) getOwner();
}
return null;
}
}
private Rectangle popupLiveArea;
// This actionListener handles the next/prev month buttons.
@Override
public void actionPerformed(ActionEvent e) {
onEvent(e);
}
private void onEvent(EventObject e) {
if (e.getSource() == _downButton) {
if (!popupIsShown()) {
openPopup();
} else {
closePopup();
}
} else {
additionalActions();
}
}
private boolean closersAdded = false;
// Override this to add functionality on down button click
public void additionalActions() {
}
private MyWindowAdapter inspectorWindowListener;
private class MyWindowAdapter extends WindowAdapter {
private final Window parentWindow;
public MyWindowAdapter(Window parent) {
this.parentWindow = parent;
}
@Override
public void windowDeactivated(final WindowEvent e) {
// If this window is deactivated, it means that another window has been activated
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (_popup == null) {
return;
}
Window oppositeWindow = e.getOppositeWindow();
if (!(oppositeWindow instanceof CustomPopup.CustomJPopupMenu) && oppositeWindow != null
&& oppositeWindow.getOwner() instanceof CustomPopup.CustomJPopupMenu) {
oppositeWindow = oppositeWindow.getOwner();
}
if (oppositeWindow != _popup) {
if (_popup.isChildOf(oppositeWindow)) {
CustomPopup.CustomJPopupMenu w = _popup;
while (w != null && w != oppositeWindow) {
w.getCustomPopup().pointerLeavesPopup();
w = w.getParentPopupMenu();
}
} else if (oppositeWindow != parentWindow || FocusManager.getCurrentManager().getFocusOwner() != null
&& !_frontComponent.hasFocus()) {
// This test is used to detect the case of the lost of focus is performed
// Because a child popup gained the focus: in this case, nothing should be performed
if (!(oppositeWindow instanceof CustomPopup.CustomJPopupMenu)
|| !((CustomPopup.CustomJPopupMenu) oppositeWindow).isChildOf(_popup)) {
pointerLeavesPopup();
}
}
}
}
});
}
public void startListening() {
_popup.addWindowListener(this);
parentWindow.addWindowListener(this);
}
public void stopListening() {
_popup.removeWindowListener(this);
parentWindow.removeWindowListener(this);
}
}
/**
* Add mouse listeners to each component of the root container c, except this button, and the calendar popup, because mouse clicks in
* them are not supposed to close the popup.
*
* @param c
* the root container
*/
private void addPopupClosers(Container c) {
if (c == getWindow(this) && c != null) {
if (logger.isLoggable(Level.FINE)) {
logger.finer("addPopupClosers");
}
inspectorWindowListener = new MyWindowAdapter((Window) c);
// inspectorWindowListener.startListening();
}
if (c != this && c != _customPanel && c != null) {
c.addMouseListener(this);
for (int i = 0; i < c.getComponents().length; i++) {
addPopupClosers((Container) c.getComponents()[i]);
}
}
}
/**
* Removes mouse listeners to each component of the root container c, except this button, and the calendar popup, because mouse clicks
* in them are not supposed to close the popup.
*
* @param c
* the root container
*/
private void removePopupClosers(Container c) {
if (c == getWindow(this)) {
if (logger.isLoggable(Level.FINE)) {
logger.finer("removePopupClosers");
}
if (inspectorWindowListener != null) {
inspectorWindowListener.stopListening();
}
inspectorWindowListener = null;
}
if (c != this && c != _customPanel && c != null) {
c.removeMouseListener(this);
for (int i = 0; i < c.getComponents().length; i++) {
removePopupClosers((Container) c.getComponents()[i]);
}
}
}
/**
* Copied directly from BasicPopupMenuUI - PK 06-08-04
*
* @param c
* componenet of which we want to find the owning window
* @return the window that is contins after plenty of leves the component c
*/
private Window getWindow(Component c) {
return SwingUtilities.getWindowAncestor(c);
}
public void delete() {
closePopup();
deletePopup(); // just to be sure
setEditedObject(null);
setRevertValue(null);
applyCancelListener = null;
}
protected void deletePopup() {
// _customPopup = null;
_popup = null;
_customPanel = null;
}
public boolean popupIsShown() {
if (_popup != null) {
return _popup._popupIsShown;
}
return false;
}
protected void openPopup() {
if (logger.isLoggable(Level.FINE)) {
logger.fine("openPopup()");
}
makePopup();
if (!closersAdded) // only do this once.
{
if (logger.isLoggable(Level.FINE)) {
logger.fine("CALLED addPopupClosers on " + getWindow(this));
}
addPopupClosers(getWindow(this));
closersAdded = true;
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (!_frontComponent.hasFocus()) {
_frontComponent.grabFocus();
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (inspectorWindowListener != null) {
inspectorWindowListener.startListening();
}
}
});
}
});
if (isShowing()) {
Point p = _downButton.getLocationOnScreen(); // This can have negative x or y if the secondary screen is on the right ir or on
// top of the main screen.
GraphicsConfiguration graphicsConfiguration = _downButton.getGraphicsConfiguration();
if (!graphicsConfiguration.getBounds().contains(p)) {
// Sometimes, if the CustomPopup is across two screens, the graphics configuration returned is not the one containing the
// _downButton.
// We can then perform a look-up to find the actual screen where the button is located and show the CustomPopup on that
// screen
// it feels a lot more natural.
for (GraphicsDevice gd : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
if (gd.getDefaultConfiguration().getBounds().contains(p)) {
graphicsConfiguration = gd.getDefaultConfiguration();
break;
}
}
}
Rectangle screenBounds = graphicsConfiguration.getBounds();
Dimension screenSize = screenBounds.getSize();
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(graphicsConfiguration);
// screen insets reflect the possible Dock/Task bar size and possibly the menu on MacOS.
Point position = new Point(p.x, p.y + _downButton.getHeight());
if (position.x + getCustomPanel().getDefaultSize().width > screenBounds.x + screenSize.width) {
// If we are too close to the right edged of the screen, we offset the location
position.x = screenBounds.x + screenSize.width - getCustomPanel().getDefaultSize().width - screenInsets.right;
}
if (position.y + getCustomPanel().getDefaultSize().height > screenBounds.y + screenSize.height) {
position.y = screenBounds.y + screenSize.height - getCustomPanel().getDefaultSize().height - screenInsets.bottom;
}
position.x = Math.max(position.x, screenBounds.x + screenInsets.left);
position.y = Math.max(position.y, screenBounds.y + screenInsets.top);
_popup.setLocation(position);
_popup.pack();
_popup.setVisible(true);
if (ToolBox.getPLATFORM() != ToolBox.MACOS) {
_downButton.setIcon(UtilsIconLibrary.CUSTOM_POPUP_OPEN_BUTTON);
}
MouseAdapter mouseListener = new MouseAdapter() {
private Point previous;
@Override
public void mousePressed(MouseEvent e) {
if (getResizeRectangle().contains(e.getPoint())) {
previous = e.getLocationOnScreen();
}
}
@Override
public void mouseDragged(MouseEvent e) {
if (previous != null) {
Dimension size = getCustomPanel().getSize();
Dimension aDimension = new Dimension(size.width + e.getLocationOnScreen().x - previous.x, size.height
+ e.getLocationOnScreen().y - previous.y);
getCustomPanel().setPreferredSize(aDimension);
_popup.pack();
previous = e.getLocationOnScreen();
}
}
@Override
public void mouseMoved(MouseEvent e) {
if (_popup == null) {
return;
}
if (getResizeRectangle().contains(e.getPoint())) {
_popup.setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
} else {
_popup.setCursor(Cursor.getDefaultCursor());
}
}
@Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
previous = null;
}
public Rectangle getResizeRectangle() {
if (_popup == null) {
return new Rectangle();
}
Rectangle r = _popup.getBounds();
int size = 3 * (BULLET_SIZE + BULLET_SPACING);
r.x = r.width - size;
r.y = r.height - size;
r.width = size;
r.height = size;
return r;
}
};
_popup.addMouseListener(mouseListener);
_popup.addMouseMotionListener(mouseListener);
} else {
logger.warning("Illegal component state: component is not showing on screen");
// _popup.show(this, 0, 0);
}
// _customPopup.show();
// _popupIsShown = true;
}
public void closePopup(boolean notifyObjectChanged) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("closePopup()");
}
if (_popup == null) {
return;
}
_popup.setVisible(false);
if (ToolBox.getPLATFORM() != ToolBox.MACOS) {
_downButton.setIcon(UtilsIconLibrary.CUSTOM_POPUP_BUTTON);
}
if (notifyObjectChanged) {
fireEditedObjectChanged();
}
if (closersAdded) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("CALLED removePopupClosers on " + getWindow(this));
}
removePopupClosers(getWindow(this));
closersAdded = false;
}
}
public void closePopup() {
closePopup(true);
}
public T getEditedObject() {
return _editedObject;
}
private boolean requireChange(T value) {
T currentValue = _editedObject;
if (value == null) {
return currentValue != null;
} else {
if (useEqualsLookup()) {
return !value.equals(currentValue);
} else {
return value != currentValue;
}
}
}
/**
* Return a flag indicating if equals() method should be used to determine equality.<br>
* If this method return false (should be overriden), equality lookup is performed using references (pointer equality) Default behaviour
* is to use equals() lookup method, please override this method (and return false) whenever a CustomPopup is used to edit a value and
* not only choose a value
*
* @return true
*/
protected boolean useEqualsLookup() {
return true;
}
/**
* Sets edited object<br>
* Before to set edited object, an equality test is performed to determine if setting is required. When not, just return.<br>
* Default behaviour is to use the equals(Object) method to see if a change is required or not. Therefore, if the edited object type
* overrides the equals method, some objects that are different may not be swapped and cause very unpredictable behaviour. A workaround
* for this is to clone the value when setting on the model. See bug 1004363. An other workaround is to override useEqualsLookup()
* method with false value, to use pointer comparison.
*
* @param object
*/
public void setEditedObject(T object) {
if (requireChange(object)) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("CustomPopup setEditedObject: " + object);
}
_editedObject = object;
fireEditedObjectChanged();
}
}
public void setRevertValue(T oldValue) {
// Not implemented here, implement in sub-classes
}
public void fireEditedObjectChanged() {
try {
updateCustomPanel(getEditedObject());
} catch (ClassCastException e) {
updateCustomPanel(null);
}
}
public abstract void updateCustomPanel(T editedObject);
@Override
public void mouseEntered(MouseEvent e) {
if (e.getSource() instanceof Component && configuration.getCloseWhenPointerLeavesPopup()) {
Component leftComponent = (Component) e.getSource();
while (leftComponent != null) {
if (leftComponent == CustomPopup.this) {
return;
}
leftComponent = leftComponent.getParent();
}
leftComponent = (Component) e.getSource();
Point p = new Point(e.getPoint());
SwingUtilities.convertPointToScreen(p, leftComponent);
if (_customPanel != null) {
if (!getCustomPanel().isAncestorOf(leftComponent) && !popupLiveArea.contains(p)) {
pointerLeavesPopup();
}
}
}
}
@Override
public void mouseClicked(MouseEvent e) {
if (e.getSource() instanceof Component && !configuration.getCloseWhenPointerLeavesPopup()) {
Component leftComponent = (Component) e.getSource();
while (leftComponent != null) {
if (leftComponent == CustomPopup.this) {
return;
}
leftComponent = leftComponent.getParent();
}
leftComponent = (Component) e.getSource();
Point p = new Point(e.getPoint());
SwingUtilities.convertPointToScreen(p, leftComponent);
if (_customPanel != null) {
if (!getCustomPanel().isAncestorOf(leftComponent) && !popupLiveArea.contains(p)) {
pointerLeavesPopup();
}
}
}
onEvent(e);
}
@Override
public void mousePressed(MouseEvent e) {
// interface
}
@Override
public void mouseReleased(MouseEvent e) {
// interface
}
@Override
public void mouseExited(MouseEvent e) {
// interface
}
protected void pointerLeavesPopup() {
closePopup();
}
public void addApplyCancelListener(ApplyCancelListener l) {
applyCancelListener.add(l);
}
public void removeApplyCancelListener(ApplyCancelListener l) {
applyCancelListener.remove(l);
}
public void apply() {
if (logger.isLoggable(Level.FINE)) {
logger.fine("apply()");
}
notifyApplyPerformed();
}
public void notifyApplyPerformed() {
for (ApplyCancelListener l : applyCancelListener) {
l.fireApplyPerformed();
}
}
public void cancel() {
for (ApplyCancelListener l : applyCancelListener) {
l.fireCancelPerformed();
}
}
public static class CustomPopupConfiguration {
private boolean closeWhenPointerLeavesPopup = false;
public boolean getCloseWhenPointerLeavesPopup() {
return closeWhenPointerLeavesPopup;
}
public void setCloseWhenPointerLeavesPopup(boolean closeWhenPointerLeavesPopup) {
this.closeWhenPointerLeavesPopup = closeWhenPointerLeavesPopup;
}
}
public String localizedForKey(String aKey) {
return aKey;
}
}