/*
* HelloNzb -- The Binary Usenet Tool
* Copyright (C) 2010-2013 Matthias F. Brandstetter
* https://sourceforge.net/projects/hellonzb/
*
* This program 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.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package me.mabra.hellonzb.preferences;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Convenience Action to dispose of a Swing Window by using the Escape key.
* Before disposing of the window the Action will first attempt to hide
* any popups. In this case the user will need to invoke the Escape key a
* second time before the Window is disposed.
*
* @see http://tips4java.wordpress.com/2010/10/17/escape-key-and-dialog/
*/
public class EscapeAction extends AbstractAction
{
private static final String KEY_STROKE_AND_KEY = "ESCAPE";
private static final KeyStroke ESCAPE_KEY_STROKE = KeyStroke.getKeyStroke(KEY_STROKE_AND_KEY);
private HelloNzbPreferences prefMain;
public EscapeAction(HelloNzbPreferences prefMain)
{
super("Escape");
this.prefMain = prefMain;
}
/**
* Implement the Escape Action. First attempt to hide a popup menu.
* If no popups are found then dispose the window.
*/
@Override
public void actionPerformed(ActionEvent e)
{
// When a popup is visible the root pane of the Window will (generally) have focus
Component component = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
JComponent rootPane = (JComponent) component;
// In some cases a component added to a popup menu may have focus, but
// we need the root pane to check for popup menu key bindings
if(!(rootPane instanceof JRootPane))
{
rootPane = (JComponent) SwingUtilities.getAncestorOfClass(JRootPane.class, component);
}
// Hide the popup menu when an ESCAPE key binding is found, otherwise dispose the Window
ActionListener escapeAction = getEscapeAction(rootPane);
if(escapeAction != null)
{
escapeAction.actionPerformed(null);
}
else
{
prefMain.loadPreferences();
Window window = SwingUtilities.windowForComponent(component);
window.setVisible(false);
}
}
private ActionListener getEscapeAction(JComponent rootPane)
{
// Search the parent InputMap to see if a binding for the ESCAPE key
// exists. This binding is added when a popup menu is made visible
// (and removed when the popup menu is hidden).
InputMap im = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
if(im == null) return null;
im = im.getParent();
if(im == null) return null;
Object[] keys = im.keys();
if(keys == null) return null;
for(Object keyStroke : keys)
{
if(keyStroke.equals(ESCAPE_KEY_STROKE))
{
Object key = im.get(ESCAPE_KEY_STROKE);
return rootPane.getActionMap().get(key);
}
}
return null;
}
/**
* Convenience method for JDialogs to register the EscapeAction
* <p/>
* ¶m dialog the JDialog the EscapeAction is registered with
*/
public void register(JDialog dialog)
{
register(dialog.getRootPane());
}
/**
* Register the EscapeAction on the specified JRootPane
* <p/>
* ¶m rootPane the JRootPane the EscapeAction is registered with
*/
public void register(JRootPane rootPane)
{
rootPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ESCAPE_KEY_STROKE, KEY_STROKE_AND_KEY);
rootPane.getActionMap().put(KEY_STROKE_AND_KEY, this);
}
}