/*
* $Id$
*
* Copyright (c) 2005 by Rodney Kinney, Brent Easton
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License (LGPL) as published by the Free Software Foundation.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, copies are available
* at http://www.opensource.org.
*/
package VASSAL.build.module.turn;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingConstants;
import VASSAL.build.AutoConfigurable;
import VASSAL.build.Buildable;
import VASSAL.build.GameModule;
import VASSAL.build.module.Chatter;
import VASSAL.build.module.GameComponent;
import VASSAL.build.module.GlobalOptions;
import VASSAL.build.module.documentation.HelpFile;
import VASSAL.build.module.properties.MutablePropertiesContainer;
import VASSAL.build.module.properties.MutableProperty;
import VASSAL.command.Command;
import VASSAL.command.CommandEncoder;
import VASSAL.configure.BooleanConfigurer;
import VASSAL.configure.Configurer;
import VASSAL.configure.ConfigurerFactory;
import VASSAL.configure.FormattedStringConfigurer;
import VASSAL.configure.IconConfigurer;
import VASSAL.configure.IntConfigurer;
import VASSAL.configure.NamedHotKeyConfigurer;
import VASSAL.configure.PlayerIdFormattedStringConfigurer;
import VASSAL.configure.StringEnum;
import VASSAL.configure.StringEnumConfigurer;
import VASSAL.configure.VisibilityCondition;
import VASSAL.i18n.Resources;
import VASSAL.i18n.TranslatableConfigurerFactory;
import VASSAL.tools.FormattedString;
import VASSAL.tools.IconButton;
import VASSAL.tools.LaunchButton;
import VASSAL.tools.NamedKeyStroke;
import VASSAL.tools.NamedKeyStrokeListener;
import VASSAL.tools.SequenceEncoder;
import VASSAL.tools.UniqueIdManager;
/**
* Generic Turn Counter
*/
public class TurnTracker extends TurnComponent implements CommandEncoder, GameComponent, ActionListener, UniqueIdManager.Identifyable {
protected static UniqueIdManager idMgr = new UniqueIdManager("TurnTracker"); //$NON-NLS-1$
protected static final String COMMAND_PREFIX = "TURN"; //$NON-NLS-1$
public static final String NAME = "name"; //$NON-NLS-1$
public static final String HOT_KEY = "hotkey"; //$NON-NLS-1$
public static final String NEXT_HOT_KEY = "nexthotkey"; //$NON-NLS-1$
public static final String PREV_HOT_KEY = "prevhotkey"; //$NON-NLS-1$
public static final String ICON = "icon"; //$NON-NLS-1$
public static final String BUTTON_TEXT = "buttonText"; //$NON-NLS-1$
public static final String BUTTON_TOOLTIP = "buttonTooltip"; //$NON-NLS-1$
public static final String TURN_FORMAT = "turnFormat"; //$NON-NLS-1$
public static final String REPORT_FORMAT = "reportFormat"; //$NON-NLS-1$
public static final String TOOLTIP = "tooltip"; //$NON-NLS-1$
public static final String LENGTH = "length"; //$NON-NLS-1$
public static final String LENGTH_STYLE = "lengthStyle"; //$NON-NLS-1$
protected static final String FONT_SIZE = "turnFontSize"; //$NON-NLS-1$
protected static final String FONT_BOLD = "turnFontBold"; //$NON-NLS-1$
protected static final String DOCKED = "turnDocked"; //$NON-NLS-1$
/** Variable name for reporting format */
protected static final String OLD_TURN = "oldTurn"; //$NON-NLS-1$
protected static final String NEW_TURN = "newTurn"; //$NON-NLS-1$
protected static final String LEVEL = "level"; //$NON-NLS-1$
protected static final String TURN_FONT = "Dialog";
protected static String SET_COMMAND;
protected static String DOCK_COMMAND;
protected static String UNDOCK_COMMAND;
protected static final String NEXT = "Next";
protected static final String PREV = "Prev";
protected static final String SET = "Set";
protected static final String PROP_VALUE = "_value"; //$NON-NLS-1$
protected static final String PROP_COMMAND = "_command"; //$NON-NLS-1$
protected static final String[] FONT_FAMILYS = new String[] { "Dialog", "DialogInput", "Monospaced", "SanSerif", "Serif"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
protected static final String LENGTH_VARIABLE = "Variable";
protected static final String LENGTH_MAXIMUM = "Maximum";
protected static final String LENGTH_FIXED = "Fixed";
protected FormattedString turnFormat = new FormattedString("$"+LEVEL+"1$ $"+LEVEL+"2$ $"+LEVEL+"3$ $"+LEVEL+"4$"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
protected FormattedString reportFormat = new FormattedString("* <$" + GlobalOptions.PLAYER_ID //$NON-NLS-1$
+ "$> Turn Updated from $"+OLD_TURN+"$ to $"+NEW_TURN+"$"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
protected TurnWindow turnWindow;
protected TurnWidget turnWidget;
protected JPanel launchWidget;
protected SetDialog setDialog;
protected LaunchButton launch;
protected NamedKeyStrokeListener nextListener;
protected NamedKeyStrokeListener prevListener;
protected String savedState = ""; //$NON-NLS-1$
protected String savedSetState = ""; //$NON-NLS-1$
protected String savedTurn = ""; //$NON-NLS-1$
protected JPopupMenu popup;
protected int currentLevel = 0;
protected String id;
protected int width = -1;
protected String lengthStyle = LENGTH_MAXIMUM;
protected MutableProperty.Impl lastCommand = new MutableProperty.Impl(SET,this);
protected MutableProperty.Impl lastTurn = new MutableProperty.Impl("",this);
public TurnTracker() {
ActionListener al = new ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
if (!isDocked()) {
turnWindow.setControls();
turnWindow.setVisible(!turnWindow.isShowing());
turnWindow.setFocusable(true);
}
}
};
setConfigureName(Resources.getString("TurnTracker.turn")); //$NON-NLS-1$
launch = new LaunchButton(Resources.getString("TurnTracker.turn"), BUTTON_TOOLTIP, BUTTON_TEXT, HOT_KEY, ICON, al); //$NON-NLS-1$
launch.setToolTipText(Resources.getString("TurnTracker.turn_tracker")); //$NON-NLS-1$
SET_COMMAND = Resources.getString("TurnTracker.set_turn"); //$NON-NLS-1$
DOCK_COMMAND = Resources.getString("General.dock"); //$NON-NLS-1$
UNDOCK_COMMAND = Resources.getString("General.undock"); //$NON-NLS-1$
// Create preferences
final IntConfigurer size = new IntConfigurer(FONT_SIZE, Resources.getString("TurnTracker.size_pref"), 14); //$NON-NLS-1$
final BooleanConfigurer bold = new BooleanConfigurer(FONT_BOLD, Resources.getString("TurnTracker.bold_pref"), Boolean.FALSE); //$NON-NLS-1$
final BooleanConfigurer docked = new BooleanConfigurer(DOCKED, Resources.getString("TurnTracker.docked_pref"), Boolean.FALSE); //$NON-NLS-1$
String prefTab = Resources.getString("TurnTracker.turn_counter"); //$NON-NLS-1$
GameModule.getGameModule().getPrefs().addOption(prefTab, size);
GameModule.getGameModule().getPrefs().addOption(prefTab, bold);
GameModule.getGameModule().getPrefs().addOption(prefTab, docked);
size.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
setDisplayFont();
}});
bold.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
setDisplayFont();
}});
docked.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
setDocked(isDocked());
}});
// Set up listeners for prev/next hotkeys
nextListener = new NamedKeyStrokeListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
turnWidget.doNext();
}
});
GameModule.getGameModule().addKeyStrokeListener(nextListener);
prevListener = new NamedKeyStrokeListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
turnWidget.doPrev();
}
});
GameModule.getGameModule().addKeyStrokeListener(prevListener);
// Create the displayable widget
turnWidget = new TurnWidget();
}
public String getState() {
final SequenceEncoder se = new SequenceEncoder('|');
se.append(currentLevel);
final Iterator<TurnLevel> i = getTurnLevels();
while (i.hasNext()) {
final TurnLevel level = i.next();
se.append(level.getState());
}
return se.getValue();
}
public void setState(String newState) {
final SequenceEncoder.Decoder sd =
new SequenceEncoder.Decoder(newState, '|');
currentLevel = sd.nextInt(0);
final Iterator<TurnLevel> i = getTurnLevels();
while (i.hasNext()) {
final TurnLevel level = i.next();
level.setState(sd.nextToken("")); //$NON-NLS-1$
}
setLaunchToolTip();
updateTurnDisplay(SET);
}
protected void setLaunchToolTip() {
launch.setToolTipText(getTurnString());
}
/*
* Module level Configuration stuff
*/
public String[] getAttributeNames() {
return new String[] { NAME, BUTTON_TEXT, ICON, BUTTON_TOOLTIP, HOT_KEY, NEXT_HOT_KEY, PREV_HOT_KEY, TURN_FORMAT, REPORT_FORMAT, TOOLTIP, LENGTH_STYLE, LENGTH };
}
public void setAttribute(String key, Object value) {
if (NAME.equals(key)) {
clearGlobalProperties();
setConfigureName((String) value);
lastCommand.setPropertyName(getConfigureName()+PROP_COMMAND);
lastTurn.setPropertyName(getConfigureName()+PROP_VALUE);
}
else if (REPORT_FORMAT.equals(key)) {
reportFormat.setFormat((String) value);
}
else if (TURN_FORMAT.equals(key)) {
turnFormat.setFormat((String) value);
}
else if (TOOLTIP.equals(key)) {
turnWidget.setLabelToolTipText((String) value);
}
else if (LENGTH.equals(key)) {
if (value instanceof String) {
value = Integer.valueOf((String) value);
}
width = ((Integer) value).intValue();
}
else if (LENGTH_STYLE.equals(key)) {
lengthStyle = (String) value;
if (LENGTH_VARIABLE.equals(lengthStyle)) {
width = 0;
}
else if (LENGTH_MAXIMUM.equals(lengthStyle)) {
width = -1;
}
}
else if (NEXT_HOT_KEY.equals(key)) {
if (value instanceof String) {
value = NamedHotKeyConfigurer.decode((String) value);
}
nextListener.setKeyStroke((NamedKeyStroke) value);
turnWidget.setNextStroke((NamedKeyStroke) value);
}
else if (PREV_HOT_KEY.equals(key)) {
if (value instanceof String) {
value = NamedHotKeyConfigurer.decode((String) value);
}
prevListener.setKeyStroke((NamedKeyStroke) value);
turnWidget.setPrevStroke((NamedKeyStroke) value);
}
else {
launch.setAttribute(key, value);
}
}
protected void setWidgetWidth() {
if (LENGTH_FIXED.equals(lengthStyle)) {
turnWidget.setWidth(width);
}
else if (LENGTH_MAXIMUM.equals(lengthStyle)) {
turnWidget.setWidth(getMaximumWidth());
}
else {
turnWidget.setWidth(0);
}
}
/**
* Calculate the maximum width for the turnWidget to display
* any item.
*
* First calculate the maximum string that can be displayed, then
* convert this to a width based on the display font.
*
* @return Maximum Width
*/
protected int getMaximumWidth() {
String maxString = getMaximumTurnString();
int max = turnWidget.getWidth(maxString);
return max+2;
}
protected void setDisplayFont() {
turnWidget.setLabelFont(getDisplayFont());
if (!isDocked() && turnWindow != null) {
turnWindow.pack();
}
}
protected Font getDisplayFont() {
int style = getFontStyle();
int size = getFontSize();
return new Font(TURN_FONT, style, size);
}
protected void setFontSize() {
setDisplayFont();
}
protected int getFontSize() {
return ((Integer) GameModule.getGameModule().getPrefs().getValue(FONT_SIZE)).intValue();
}
protected int getFontStyle() {
return ((Boolean) GameModule.getGameModule().getPrefs().getValue(FONT_BOLD)).booleanValue() ? 1 : 0;
}
protected boolean isDocked() {
return ((Boolean) GameModule.getGameModule().getPrefs().getValue(DOCKED)).booleanValue();
}
protected void setDocked(boolean dock) {
final GameModule g = GameModule.getGameModule();
g.getPrefs().setValue(DOCKED, Boolean.valueOf(dock));
launch.setVisible(
!dock && (
getAttributeValueString(BUTTON_TEXT).length() > 0 ||
getAttributeValueString(ICON).length() > 0
)
);
if (dock) {
turnWindow.setWidget(null);
turnWindow.setVisible(false);
launchWidget.add(turnWidget, BorderLayout.CENTER);
launchWidget.setVisible(g.getGameState().isGameStarted());
}
else {
launchWidget.setVisible(false);
launchWidget.remove(turnWidget);
turnWindow.setWidget(turnWidget);
turnWindow.setVisible(g.getGameState().isGameStarted());
turnWindow.setFocusable(true);
}
}
public String getAttributeValueString(String key) {
if (NAME.equals(key)) {
return getConfigureName() + ""; //$NON-NLS-1$
}
else if (REPORT_FORMAT.equals(key)) {
return reportFormat.getFormat();
}
else if (TURN_FORMAT.equals(key)) {
return turnFormat.getFormat();
}
else if (TOOLTIP.equals(key)) {
return turnWidget.getLabelToolTipText();
}
else if (LENGTH.equals(key)) {
return String.valueOf(width);
}
else if (LENGTH_STYLE.equals(key)) {
return lengthStyle;
}
else if (NEXT_HOT_KEY.equals(key)) {
return NamedHotKeyConfigurer.encode(nextListener.getNamedKeyStroke());
}
else if (PREV_HOT_KEY.equals(key)) {
return NamedHotKeyConfigurer.encode(prevListener.getNamedKeyStroke());
}
else {
return launch.getAttributeValueString(key);
}
}
public String[] getAttributeDescriptions() {
return new String[] {
"Name: ",
"Button text: ",
"Button Icon: ",
"Button Tooltip: ",
"Show/hide Hotkey: ",
"Next Turn Hotkey: ",
"Previous Turn Hotkey: ",
"Turn Name Format: ",
"Report Format: ",
"Turn Label Tooltip Text: ",
"Turn Label Length: ",
"Turn label Display length: "
};
}
public Class<?>[] getAttributeTypes() {
return new Class<?>[] {
String.class,
String.class,
IconConfig.class,
String.class,
NamedKeyStroke.class,
NamedKeyStroke.class,
NamedKeyStroke.class,
TurnFormatConfig.class,
ReportFormatConfig.class,
String.class,
LengthStyleConfig.class,
Integer.class
};
}
public static class IconConfig implements ConfigurerFactory {
public Configurer getConfigurer(AutoConfigurable c, String key, String name) {
return new IconConfigurer(key, name, ((TurnTracker) c).launch.getAttributeValueString(ICON));
}
}
public static class TurnFormatConfig implements TranslatableConfigurerFactory {
public Configurer getConfigurer(AutoConfigurable c, String key, String name) {
TurnTracker t = (TurnTracker) c;
String s[] = new String[t.getLevelCount()];
for (int i = 0; i < s.length; i++) {
s[i] = LEVEL+(i+1);
}
return new FormattedStringConfigurer(key, name, s);
}
}
public static class ReportFormatConfig implements TranslatableConfigurerFactory {
public Configurer getConfigurer(AutoConfigurable c, String key, String name) {
return new PlayerIdFormattedStringConfigurer(key, name, new String[] {OLD_TURN, NEW_TURN } );
}
}
public static class LengthStyleConfig extends StringEnum {
public String[] getValidValues(AutoConfigurable target) {
return new String[]{LENGTH_VARIABLE, LENGTH_FIXED, LENGTH_MAXIMUM};
}
}
public VisibilityCondition getAttributeVisibility(String name) {
if (LENGTH.equals(name)) {
return new VisibilityCondition() {
public boolean shouldBeVisible() {
return LENGTH_FIXED.equals(lengthStyle);
}
};
}
else {
return null;
}
}
public Class<?>[] getAllowableConfigureComponents() {
return new Class<?>[] {
CounterTurnLevel.class, ListTurnLevel.class, TurnGlobalHotkey.class
};
}
public static String getConfigureTypeName() {
return "Turn Counter";
}
public void addTo(Buildable b) {
//Create the turn window
turnWindow = new TurnWindow();
turnWindow.pack();
turnWindow.setVisible(false);
launchWidget = new JPanel();
launchWidget.setLayout(new BorderLayout());
launchWidget.setBorder(BorderFactory.createEtchedBorder());
GameModule.getGameModule().getToolBar().add(launchWidget);
launchWidget.setAlignmentY(0.0F);
launchWidget.setVisible(false);
GameModule.getGameModule().getToolBar().add(launch);
launch.setAlignmentY(0.0F);
launch.setEnabled(false);
setDocked(isDocked());
GameModule.getGameModule().addCommandEncoder(this);
GameModule.getGameModule().getGameState().addGameComponent(this);
idMgr.add(this);
//Global Property support
lastCommand.addTo((MutablePropertiesContainer) b);
lastTurn.addTo((MutablePropertiesContainer) b);
}
public void removeFrom(Buildable b) {
GameModule.getGameModule().getToolBar().remove(launch);
GameModule.getGameModule().getToolBar().remove(launchWidget);
GameModule.getGameModule().removeCommandEncoder(this);
GameModule.getGameModule().getGameState().removeGameComponent(this);
lastCommand.removeFromContainer();
lastTurn.removeFromContainer();
clearGlobalProperties();
}
public HelpFile getHelpFile() {
return HelpFile.getReferenceManualPage("TurnTracker.htm"); //$NON-NLS-1$ //$NON-NLS-2$
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
protected void captureState() {
savedState = getState();
savedTurn = getTurnString();
}
protected void save() {
if (!savedState.equals(getState())) {
reportFormat.setProperty(OLD_TURN, savedTurn);
reportFormat.setProperty(NEW_TURN, getTurnString());
String s = updateString(reportFormat.getText(), new String[] { "\\n", "\\t" }, new String[] { " - ", " " }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
Command c = new Chatter.DisplayText(GameModule.getGameModule().getChatter(), "* "+s);
c.execute();
c.append(new SetTurn(this, savedState));
GameModule.getGameModule().sendAndLog(c);
setLaunchToolTip();
}
captureState();
}
/**
* Calculate the maximum sized turn string that can be generated
* by any turn combination.
*
* @return maximum turn string
*/
protected String getMaximumTurnString() {
List<String> levels = new ArrayList<String>();
for (Buildable b : getBuildables()) {
if (b instanceof TurnLevel) {
((TurnLevel) b).findMaximumStrings(levels, 0);
}
}
turnFormat.clearProperties();
for (int i = 0; i < levels.size(); i++) {
turnFormat.setProperty(LEVEL+(i+1), levels.get(i));
}
return turnFormat.getText(GameModule.getGameModule());
}
/**
* Build the turn string to be displayed from the currently
* active Child TurnLevel's
* @return Turn String
*/
protected String getTurnString() {
turnFormat.clearProperties();
List<TurnLevel> turnDesc = getActiveChildLevels();
for (int i = 0; i < 15; i++) {
turnFormat.setProperty(LEVEL+(i+1), i < turnDesc.size() ? turnDesc.get(i).getTurnString() : "");
}
return turnFormat.getText(GameModule.getGameModule());
}
/**
* A list of all active TurnLevels within the TurnTracker
* @return
*/
protected List<TurnLevel> getActiveChildLevels() {
ArrayList<TurnLevel> levels = new ArrayList<TurnLevel>();
TurnLevel level = getTurnLevel(currentLevel);
if (level != null) {
levels.add(level);
levels.addAll(level.getActiveChildLevels());
}
return levels;
}
protected int getLevelCount() {
return getActiveChildLevels().size();
}
protected void next() {
if (getTurnLevelCount() == 0) {
return;
}
TurnLevel level = getTurnLevel(currentLevel);
level.advance();
if (level.hasRolledOver()) {
currentLevel++;
if (currentLevel >= getTurnLevelCount()) {
currentLevel = 0;
}
getTurnLevel(currentLevel).setLow();
}
updateTurnDisplay(NEXT);
doGlobalkeys();
}
protected void prev() {
if (getTurnLevelCount() == 0) {
return;
}
TurnLevel level = getTurnLevel(currentLevel);
level.retreat();
if (level.hasRolledOver()) {
currentLevel--;
if (currentLevel < 0) {
currentLevel = getTurnLevelCount()-1;
}
getTurnLevel(currentLevel).setHigh();
}
updateTurnDisplay(PREV);
doGlobalkeys();
}
protected void doGlobalkeys() {
for (TurnGlobalHotkey key : getComponentsOf(TurnGlobalHotkey.class)) {
key.apply();
}
}
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals(SET_COMMAND)) {
set();
}
else if (command.equals(DOCK_COMMAND)) {
setDocked(true);
}
else if (command.equals(UNDOCK_COMMAND)) {
setDocked(false);
}
}
protected void set() {
savedSetState = getState();
if (setDialog == null) {
setDialog = new SetDialog();
setDialog.setTitle(Resources.getString("TurnTracker.set_turn2", getConfigureName())); //$NON-NLS-1$
}
setDialog.setControls(this);
setDialog.setVisible(true);
}
protected void updateTurnDisplay(String command) {
lastCommand.setPropertyValue(command);
lastTurn.setPropertyValue(getTurnString());
turnWidget.setControls();
turnWidget.repaint();
turnWindow.pack();
turnWindow.setFocusable(true);
turnWindow.requestFocus();
}
protected void clearGlobalProperties() {
lastCommand.setPropertyValue(null);
lastTurn.setPropertyValue(null);
}
public Command decode(String command) {
Command comm = null;
if (command.startsWith(COMMAND_PREFIX+getId())) {
SequenceEncoder.Decoder sd = new SequenceEncoder.Decoder(command, '\t');
sd.nextToken(""); //$NON-NLS-1$
comm = new SetTurn(sd.nextToken(""), this); //$NON-NLS-1$
}
return comm;
}
public String encode(Command c) {
String s = null;
if (c instanceof SetTurn) {
SetTurn com = (SetTurn) c;
SequenceEncoder se = new SequenceEncoder('\t');
se.append(COMMAND_PREFIX + com.getTurn().getId());
se.append(com.newState);
return se.getValue();
}
return s;
}
public void setup(boolean gameStarting) {
launch.setEnabled(gameStarting);
turnWindow.setVisible(false);
launchWidget.setVisible(isDocked() && gameStarting);
if (gameStarting) {
lastCommand.setPropertyValue(SET);
lastTurn.setPropertyValue("");
turnWidget.setControls();
setWidgetWidth();
}
else {
reset();
}
}
protected void reset() {
for (int i = 0; i < getTurnLevelCount(); i++) {
(getTurnLevel(i)).reset();
}
currentLevel = 0;
setLaunchToolTip();
clearGlobalProperties();
}
public String updateString(String str, String[] from, String[] to) {
final StringBuilder s = new StringBuilder(str);
for (int i = 0; i < from.length; i++) {
replace(s, from[i], to[i]);
}
return s.toString();
}
public void replace(StringBuilder s, String from, String to) {
int i = s.indexOf(from);
while (i >= 0) {
s = s.replace(i, i+2, to);
i = s.indexOf(from);
}
}
/** @deprecated Use {@link #replace(StringBuilder,String,String)} instead. */
@Deprecated
public void replace(StringBuffer s, String from, String to) {
int i = s.indexOf(from);
while (i >= 0) {
s = s.replace(i, i+2, to);
i = s.indexOf(from);
}
}
public Command getRestoreCommand() {
return new SetTurn(getState(), this);
}
protected class TurnWindow extends JDialog {
private static final long serialVersionUID = 1L;
protected TurnWidget widget;
protected TurnWindow() {
super(GameModule.getGameModule().getFrame());
setTitle(getConfigureName());
pack();
setLocation(100, 100);
setFocusable(true);
}
protected void setWidget(TurnWidget t) {
if (t == null) {
if (widget != null) {
remove(widget);
}
}
else {
add(t);
}
pack();
}
protected void setControls() {
if (widget != null) {
widget.setControls();
}
pack();
}
}
protected class TurnWidget extends JPanel implements MouseListener {
private static final long serialVersionUID = 1L;
private IconButton nextButton;
private IconButton prevButton;
protected final int BUTTON_SIZE = 22;
protected JLabel turnLabel = new JLabel();
protected TurnWidget() {
super();
initComponents();
}
public void setLabelFont(Font displayFont) {
turnLabel.setFont(displayFont);
}
public void setWidth(int length) {
if (length > 0) {
turnLabel.setMinimumSize(new Dimension(length, BUTTON_SIZE));
turnLabel.setPreferredSize(new Dimension(length, BUTTON_SIZE));
}
else {
turnLabel.setMinimumSize(null);
turnLabel.setPreferredSize(null);
}
}
public void setLabelToolTipText(String tooltip) {
turnLabel.setToolTipText(tooltip);
}
public String getLabelToolTipText() {
return turnLabel.getToolTipText();
}
public Color getColor() {
return turnLabel.getBackground();
}
public int getWidth(String text) {
return turnLabel.getGraphics().getFontMetrics().stringWidth(text);
}
protected void doNext() {
captureState();
next();
save();
}
protected void doPrev() {
captureState();
prev();
save();
}
protected void initComponents() {
setLayout(new BorderLayout(5, 5));
nextButton = new IconButton(IconButton.PLUS_ICON, BUTTON_SIZE);
setNextStroke(nextListener.getNamedKeyStroke());
nextButton.setAlignmentY(Component.TOP_ALIGNMENT);
nextButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
doNext();
}});
prevButton = new IconButton(IconButton.MINUS_ICON, BUTTON_SIZE);
setPrevStroke(prevListener.getNamedKeyStroke());
prevButton.setAlignmentY(Component.TOP_ALIGNMENT);
prevButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
doPrev();
}});
// Next, the Label containing the Turn Text
turnLabel.setFont(getDisplayFont());
turnLabel.setFocusable(false);
turnLabel.setHorizontalTextPosition(JLabel.CENTER);
turnLabel.setHorizontalAlignment(SwingConstants.CENTER);
turnLabel.addMouseListener(this);
turnLabel.setBackground(Color.WHITE);
turnLabel.setToolTipText(Resources.getString("TurnTracker.click_to_configure")); //$NON-NLS-1$
add(prevButton, BorderLayout.LINE_START);
add(turnLabel, BorderLayout.CENTER);
add(nextButton, BorderLayout.LINE_END);
addMouseListener(this);
}
public void setNextStroke(NamedKeyStroke key) {
final String tooltip = Resources.getString("TurnTracker.next_turn") +
(key == null ? "" : " " + NamedHotKeyConfigurer.getFancyString(key));
nextButton.setToolTipText(tooltip);
}
public void setPrevStroke(NamedKeyStroke key) {
final String tooltip = Resources.getString("TurnTracker.prev_turn") + //$NON-NLS-1$
(key == null ? "" : " " + NamedHotKeyConfigurer.getFancyString(key)); //$NON-NLS-1$ //$NON-NLS-2$
prevButton.setToolTipText(tooltip);
}
public void setControls() {
String s = updateString(getTurnString(), new String[] { "\\n", "\\t" }, new String[] { "\n", " " }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
turnLabel.setText(s);
}
public void mouseClicked(MouseEvent e) {
if (e.isMetaDown()) {
doPopup(e.getPoint());
}
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void doPopup(Point p) {
buildPopup();
if (isShowing()) {
popup.show(this, p.x, p.y);
}
}
}
protected void buildPopup() {
popup = new JPopupMenu();
popup.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
turnWidget.repaint();
}
public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {
turnWidget.repaint();
}
public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
}
});
JMenuItem item;
// Dock/Undock
if (isDocked()) {
item = new JMenuItem(UNDOCK_COMMAND);
}
else {
item = new JMenuItem(DOCK_COMMAND);
}
item.addActionListener(this);
popup.add(item);
// Set Current Turn directly
item = new JMenuItem(SET_COMMAND);
item.addActionListener(this);
popup.add(item);
// Configure List Items
JMenu config = new JMenu(Resources.getString("TurnTracker.configure")); //$NON-NLS-1$
for (int i = 0; i < getTurnLevelCount(); i++) {
getTurnLevel(i).buildConfigMenu(config);
}
if (config.getItemCount() > 0) {
popup.add(config);
}
}
protected void addItem(JMenu menu, String command) {
JMenuItem item = new JMenuItem(command);
item.addActionListener(this);
menu.add(item);
}
private static final Dimension FILLER = new Dimension(0, 3);
protected class SetDialog extends JDialog {
private static final long serialVersionUID = 1L;
protected JPanel panel;
protected JPanel controls = null;
protected JPanel levelControls = null;
protected Component childControls = null;
protected TurnTracker turn;
protected JDialog me;
protected SetDialog() {
super(GameModule.getGameModule().getFrame());
initComponents();
setLocation(100, 100);
me = this;
}
protected void initComponents() {
setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
cancelSet();
setVisible(false);
}
});
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
add(panel);
JPanel p = new JPanel();
JButton saveButton = new JButton(Resources.getString(Resources.SAVE));
saveButton.setToolTipText(Resources.getString("TurnTracker.save_changes")); //$NON-NLS-1$
p.add(saveButton);
saveButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
saveSet();
setVisible(false);
}
});
JButton cancelButton = new JButton(Resources.getString(Resources.CANCEL));
cancelButton.setToolTipText(Resources.getString("TurnTracker.discard_changes")); //$NON-NLS-1$
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cancelSet();
setVisible(false);
}
});
p.add(cancelButton);
add(p);
}
public void setControls(TurnTracker turn) {
this.turn = turn;
if (controls != null) {
panel.remove(controls);
}
controls = new JPanel();
controls.setLayout(new BoxLayout(controls, BoxLayout.Y_AXIS));
levelControls = new JPanel();
levelControls.setLayout(new BoxLayout(levelControls, BoxLayout.Y_AXIS));
if (getTurnLevelCount() > 1) {
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
p.setBorder(BorderFactory.createLineBorder(Color.black));
String s[] = new String[getTurnLevelCount()];
for (int i = 0; i < s.length; i++) {
s[i] = getTurnLevel(i).getConfigureName();
}
StringEnumConfigurer e = new StringEnumConfigurer(null, Resources.getString("TurnTracker.select"), s); //$NON-NLS-1$
e.setValue(getTurnLevel(currentLevel).getConfigureName());
e.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
String option = ((StringEnumConfigurer) e.getSource()).getValueString();
for (int i = 0; i < getTurnLevelCount(); i++) {
if (option.equals(getTurnLevel(i).getConfigureName())) {
currentLevel = i;
updateTurnDisplay(SET);
addChildControls();
}
}
}});
p.add(Box.createRigidArea(FILLER));
p.add(e.getControls());
p.add(Box.createRigidArea(FILLER));
levelControls.add(p);
levelControls.add(Box.createRigidArea(FILLER));
}
addChildControls();
controls.add(levelControls);
panel.add(controls);
pack();
}
protected void addChildControls () {
if (childControls != null) {
levelControls.remove(childControls);
}
childControls = getTurnLevel(currentLevel).getSetControls(me, turn);
levelControls.add(childControls);
pack();
}
}
protected void cancelSet() {
setState(savedSetState);
turnWindow.setVisible(true);
turnWindow.setFocusable(true);
}
protected void saveSet() {
save();
updateTurnDisplay(SET);
doGlobalkeys();
}
public static class SetTurn extends Command {
private String oldState;
private String newState;
private TurnTracker turn;
public SetTurn(String newState, TurnTracker t) {
this.newState = newState;
oldState = t.getState();
turn = t;
}
public SetTurn(TurnTracker t, String oldState) {
newState = t.getState();
this.oldState = oldState;
turn = t;
}
public TurnTracker getTurn() {
return turn;
}
protected void executeCommand() {
turn.setState(newState);
}
protected Command myUndoCommand() {
return new SetTurn(oldState, turn);
}
}
}