/**
* Copyright (C) 2002-2012 The FreeCol Team
*
* This file is part of FreeCol.
*
* FreeCol 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 2 of the License, or
* (at your option) any later version.
*
* FreeCol 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 FreeCol. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.freecol.client.gui.action;
import java.util.logging.Logger;
import net.sf.freecol.client.FreeColClient;
import net.sf.freecol.client.gui.GUI;
import net.sf.freecol.client.gui.i18n.Messages;
import net.sf.freecol.common.option.Option;
import net.sf.freecol.common.resources.ResourceManager;
import org.freecolandroid.repackaged.java.awt.Image;
import org.freecolandroid.repackaged.java.awt.event.ActionEvent;
import org.freecolandroid.repackaged.javax.swing.AbstractAction;
import org.freecolandroid.repackaged.javax.swing.Action;
import org.freecolandroid.repackaged.javax.swing.ImageIcon;
import org.freecolandroid.repackaged.javax.swing.KeyStroke;
import org.freecolandroid.repackaged.javax.swing.event.MenuKeyEvent;
import org.freecolandroid.repackaged.javax.swing.event.MenuKeyListener;
import org.freecolandroid.xml.stream.XMLStreamException;
import org.freecolandroid.xml.stream.XMLStreamReader;
import org.freecolandroid.xml.stream.XMLStreamWriter;
/**
* The super class of all actions in FreeCol. Subclasses of this object is
* stored in an {@link ActionManager}.
*/
public abstract class FreeColAction extends AbstractAction implements Option<FreeColAction> {
private static final Logger logger = Logger.getLogger(FreeColAction.class.getName());
public static final String ACTION_ID = "ACTION_ID";
public static final String BUTTON_IMAGE = "BUTTON_IMAGE";
public static final String BUTTON_ROLLOVER_IMAGE = "BUTTON_ROLLOVER_IMAGE";
public static final String BUTTON_PRESSED_IMAGE = "BUTTON_PRESSED_IMAGE";
public static final String BUTTON_DISABLED_IMAGE = "BUTTON_DISABLED_IMAGE";
public static final Integer NO_MNEMONIC = null;
protected final FreeColClient freeColClient;
private int orderButtonImageCount = 0;
protected GUI gui;
/**
* Creates a new <code>FreeColAction</code>.
*
* @param freeColClient The main controller object for the client.
* @param id a <code>String</code> value
*/
protected FreeColAction(FreeColClient freeColClient, GUI gui, String id) {
super(Messages.message(id + ".name"));
this.freeColClient = freeColClient;
this.gui = gui;
putValue(ACTION_ID, id);
String descriptionKey = id + ".shortDescription";
String shortDescription = Messages.message(descriptionKey);
if (!shortDescription.equals(descriptionKey)) {
putValue(SHORT_DESCRIPTION, shortDescription);
}
String acceleratorKey = id + ".accelerator";
String accelerator = Messages.message(acceleratorKey);
if (!accelerator.equals(acceleratorKey)) {
setAccelerator(KeyStroke.getKeyStroke(accelerator));
}
}
/**
* Don't use this method.
*/
public FreeColAction clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("FreeColAction can not be cloned.");
}
/**
* Gets the mnemonic to be used for selecting this action
*
* @return The mnemonic of the action
*/
public Integer getMnemonic() {
return (Integer) getValue(MNEMONIC_KEY);
}
/**
* Describe <code>setMnemonic</code> method here.
*
* @param mnemonic an <code>int</code> value
*/
public void setMnemonic(int mnemonic) {
putValue(MNEMONIC_KEY, mnemonic);
}
/**
* Gets the main controller object for the client.
*
* @return The main controller object for the client.
*/
protected FreeColClient getFreeColClient() {
return freeColClient;
}
/**
* Are all the order button images present?
*
* @return True if all the order button images are present.
*/
public boolean hasOrderButtons() {
return orderButtonImageCount == 4;
}
/**
* Adds icons for the order buttons.
*
* @param key The id of the action.
*/
protected void addImageIcons(String key) {
Image normal = ResourceManager.getImage("orderButton.normal." + key);
Image highlighted = ResourceManager.getImage("orderButton.highlighted." + key);
Image pressed = ResourceManager.getImage("orderButton.pressed." + key);
Image disabled = ResourceManager.getImage("orderButton.disabled." + key);
orderButtonImageCount = ((normal == null) ? 0 : 1)
+ ((highlighted == null) ? 0 : 1)
+ ((pressed == null) ? 0 : 1)
+ ((disabled == null) ? 0 : 1);
if (hasOrderButtons()) {
putValue(BUTTON_IMAGE, new ImageIcon(normal));
putValue(BUTTON_ROLLOVER_IMAGE, new ImageIcon(highlighted));
putValue(BUTTON_PRESSED_IMAGE, new ImageIcon(pressed));
putValue(BUTTON_DISABLED_IMAGE, new ImageIcon(disabled));
} else {
logger.warning("Missing " + (4-orderButtonImageCount)
+ " orderButton images for " + getId());
}
}
/**
* Updates the "enabled"-status with the value returned by
* {@link #shouldBeEnabled}.
*/
public void update() {
boolean b = shouldBeEnabled();
if (isEnabled() != b) {
setEnabled(b);
}
}
/**
* Checks if this action should be enabled.
*
* @return <code>false</code> if the
* {@link net.sf.freecol.client.gui.panel.ClientOptionsDialog} is
* visible and <code>true</code> otherwise. This method should be
* extended by subclasses if the action should be disabled in other
* cases.
*/
protected boolean shouldBeEnabled() {
return gui.isClientOptionsDialogShowing();
}
/**
* Sets a keyboard accelerator.
*
* @param accelerator The <code>KeyStroke</code>. Using <code>null</code>
* is the same as disabling the keyboard accelerator.
*/
public void setAccelerator(KeyStroke accelerator) {
putValue(ACCELERATOR_KEY, accelerator);
}
/**
* Gets the keyboard accelerator for this option.
*
* @return The <code>KeyStroke</code> or <code>null</code> if the
* keyboard accelerator is disabled.
*/
public KeyStroke getAccelerator() {
return (KeyStroke) getValue(ACCELERATOR_KEY);
}
/**
* Gives a short description of this <code>Option</code>. Can for
* instance be used as a tooltip text.
*
* @return A short description of this action.
*/
public String getShortDescription() {
return (String) getValue(SHORT_DESCRIPTION);
}
/**
* Returns a textual representation of this object.
*
* @return The name of this <code>Option</code>.
* @see #getName
*/
@Override
public String toString() {
return getName();
}
/**
* Returns the id of this <code>Option</code>.
*
* @return An unique identifier for this action.
*/
public String getId() {
return (String) getValue(ACTION_ID);
}
/**
* Returns the name of this <code>Option</code>.
*
* @return The name as provided in the constructor.
*/
public String getName() {
return (String) getValue(NAME);
}
/**
* Creates a <code>String</code> that keeps the attributes given
* <code>KeyStroke</code>. This <code>String</code> can be used to
* store the key stroke in an XML-file.
*
* @param keyStroke The <code>KeyStroke</code>.
* @return A <code>String</code> that produces a key stroke equal to the
* given <code>KeyStroke</code> if passed as a parameter to
* <code>getAWTKeyStroke(String)</code>.
*/
public static String getKeyStrokeText(KeyStroke keyStroke) {
if (keyStroke == null) {
return "";
} else
return keyStroke.toString();
}
/**
* Returns the action itself. TODO: at the moment, this is only
* necessary in order to implement Option.
*
* @return an <code>FreeColAction</code> value
*/
public FreeColAction getValue() {
return this;
}
/**
* Does nothing except log a warning. TODO: at the moment, this is
* only necessary in order to implement Option.
*
* @param value a <code>FreeColAction</code> value
*/
public void setValue(FreeColAction value) {
logger.warning("Calling unsupported method setValue.");
}
/**
* This method writes an XML-representation of this object to the given
* stream.
*
* @param out The target stream.
* @throws XMLStreamException if there are any problems writing to the
* stream.
*/
protected void toXMLImpl(XMLStreamWriter out) throws XMLStreamException {
// Start element:
out.writeStartElement(getXMLElementTagName());
out.writeAttribute("id", getId());
out.writeAttribute("accelerator", getKeyStrokeText(getAccelerator()));
out.writeEndElement();
}
/**
* Initialize this object from an XML-representation of this object.
*
* @param in The input stream with the XML.
* @throws XMLStreamException if a problem was encountered during parsing.
*/
protected void readFromXMLImpl(XMLStreamReader in) throws XMLStreamException {
String id = in.getAttributeValue(null, "id");
String acc = in.getAttributeValue(null, "accelerator");
if (id == null){
// Old syntax
id = in.getLocalName();
}
if (!acc.equals("")) {
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(acc));
} else {
putValue(ACCELERATOR_KEY, null);
}
in.nextTag();
}
/**
* This method writes an XML-representation of this object to the given
* stream.
*
* @param out The target stream.
* @throws XMLStreamException if there are any problems writing to the
* stream.
*/
public void toXML(XMLStreamWriter out) throws XMLStreamException {
toXMLImpl(out);
}
/**
* Initialize this object from an XML-representation of this object.
*
* @param in The input stream with the XML.
* @throws XMLStreamException if a problem was encountered during parsing.
*/
public void readFromXML(XMLStreamReader in) throws XMLStreamException {
readFromXMLImpl(in);
}
public MenuKeyListener getMenuKeyListener() {
return new InnerMenuKeyListener();
}
/**
* A class used by Actions which have a mnemonic. Those Actions should
* assign this listener to the JMenuItem they are a part of. This captures
* the mnemonic key press and keeps other menus from processing keys meant
* for other actions.
*
* @author johnathanj
*/
public class InnerMenuKeyListener implements MenuKeyListener {
int mnemonic;
public InnerMenuKeyListener() {
mnemonic = ((Integer) getValue(MNEMONIC_KEY)).intValue();
}
public void menuKeyPressed(MenuKeyEvent e) {
if (e.getKeyCode() == mnemonic) {
ActionEvent ae = new ActionEvent(e.getSource(), e.getID(), (String) getValue(Action.NAME),
e.getModifiers());
actionPerformed(ae);
e.consume();
}
}
public void menuKeyReleased(MenuKeyEvent e) {
// do nothing
}
public void menuKeyTyped(MenuKeyEvent e) {
// do nothing
}
}
/**
* Gets the tag name of the root element representing this object.
* @return "integerOption".
*/
public static String getXMLElementTagName() {
return "action";
}
}