/* JChessBoard -- a chess game
* Copyright (C) 2000-2004 Claus Divossen <claus.divossen@gmx.de>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* $Id: JChessBoard.java 7 2009-11-15 18:58:42Z cdivossen $ */
package jchessboard;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
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.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.List;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
/**
* JChessBoard is the main class. It does the following things:
* - manage the gui
* - create the other class instances: AI, VirtualBoard (the main baord)
* VisualBoard, BoardConnector, ConnectionIndicator, ConnectionListener
* - dispatch the moves and other events to the appropriate recipients
* All communication between the other classes will be done through
* JChessBoard, or using its public methods and attributes.
* @see AI
* @see VirtualBoard
* @see VisualBoard
* @see ConnectionListener
* @see BoardConnector
* @see Protocol
* @see ConnectionIndicator
* @see Move
* @see PGN
* @see GameTable
* @see GameNode
* @see Notation
* @see History
* @see InfoPanel
* @see Chat
* @see BoardEditor
* @see ChessClock
* @see Settings
* */
public class JChessBoard extends JFrame {
static final String TITLE = "JChessBoard v1.5.1";
static final String COPYRIGHT_MESSAGE =
"JChessBoard -- a chess game\n"
+ "Copyright (C) 2000 Claus Divossen <claus.divossen\u0040gmx.de>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation; either version 2 of the License, or\n"
+ "(at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n";
static final int MIN_WIDTH = 350;
static final int MIN_HEIGHT = 471;
final static String HUMAN = "Human";
final static String COMPUTER = "Computer";
final static String PEER = "Peer";
final static String UNKNOWN = "-----";
VisualBoard visualBoard;
ConnectionIndicator connectionIndicator;
BoardConnector boardConnector;
AI ai;
ChessClock chessClock;
Chat chat;
String whitePlayer = HUMAN;
String blackPlayer = COMPUTER;
History history;
static java.util.List windowList = new Vector();
// Menu items that need to be known:
private JMenuItem menuItemNewGame;
private JMenuItem menuItemLoadFile;
private JMenuItem menuItemSave;
private JMenuItem menuItemSaveAs;
private JMenuItem menuItemUploadGame;
private JMenuItem menuItemOfferDraw;
private JMenuItem menuItemResign;
private JMenuItem menuItemSwitchSides;
private JMenuItem menuItemConnect;
private JMenuItem menuItemCloseConnection;
private JMenuItem about;
private JMenuItem help;
private JCheckBoxMenuItem clockCheckbox;
private JCheckBoxMenuItem enableBeep;
private JCheckBoxMenuItem reverseBoard;
private JCheckBoxMenuItem showPossibleMoves;
// private JCheckBoxMenuItem whiteIsAI;
// private JCheckBoxMenuItem blackIsAI;
private JMenuItem undoMove;
// ConnectionListener is the connection server
private static ConnectionListener connectionListener;
private String otherHostname = "";
private static String fileChooserDir;
private String fileName = "";
private boolean fileIsChanged = false;
private final static String settingsFileName = "JChessBoard.conf";
Settings settings;
private JPanel buttonPanel;
private JButton buttonPrevious, buttonNext, buttonStart, buttonEnd;
private boolean gameIsFinished = false;
// Reguired for the timeout selector:
JSlider whiteSlider, blackSlider;
long newWhiteTime, newBlackTime;
JLabel whiteTimeoutLabel, blackTimeoutLabel;
boolean coupleSliders;
JCheckBox coupleSlidersCheckBox;
Protocol protocol = new Protocol(this);
GameTable gameTable = null;
int currentGameIndex = 0;
private InfoPanel infoPanel;
private JTabbedPane tabbedPane;
private Notation notation;
public static String getVersion() {
return "$Id: JChessBoard.java 7 2009-11-15 18:58:42Z cdivossen $";
}
static class PGNFileFilter extends javax.swing.filechooser.FileFilter {
public String getDescription() {
return "PGN Files (*.pgn)";
}
public boolean accept(java.io.File file) {
return file.exists() && file.canRead() && (file.getName().endsWith(".pgn") || file.isDirectory());
}
}
/**
* @return
*/
public BoardConnector getBoardConnector() {
return boardConnector;
}
/**
* @param connector
*/
public void setBoardConnector(BoardConnector connector) {
boardConnector = connector;
}
/**
* Test whether this board is currently connected.
*/
public boolean isConnected() {
return (protocol.isConnected() && (boardConnector != null));
}
public void setEnableClock(boolean enable) {
clockCheckbox.setSelected(enable);
chessClock.setEnabled(enable);
settings.enableClock = enable;
}
public boolean getEnableClock() {
return clockCheckbox.isSelected();
}
public void connectionClosed() {
// Protocol stuff
protocol.connectionClosed();
// Visual stuff
chessClock.stopClock();
connectionIndicator.setNoConnection();
showMessage("Connection closed.");
gameTable.setEnabled(true);
setEnableClock(false);
gameTable.setNetworkGameIndex(-1);
if (fileName != null && fileName.length() > 0)
setTitle(TITLE + " - " + fileName);
else
setTitle(TITLE);
beep();
whitePlayer = HUMAN;
blackPlayer = HUMAN;
boardConnector = null;
prepareMove();
// --JAM: Switch the board around. If Black is disconnected at the
// beginning of the game, the board is still oriented for Black.
// It's disconcerting.
}
/**
* Performs all the steps necessary to begin playing a connected game.
* This includes setting the chess clocks, clearing the connection
* indicator, starting a new game, resetting the title, and setting
* variables to allow the first mover to be White.
*/
public void connectionEstablished() {
protocol.connectionEstablished();
connectionIndicator.setReady();
setEnableClock(true);
settings.whiteTime = 600000;
settings.blackTime = 600000;
newGame();
gameTable.setNetworkGameIndex(gameTable.getCurrentGameIndex());
protocol.sendPlayerName(settings.userName);
if (fileName != null && fileName.length() > 0)
setTitle(TITLE + " - Connected with \"" + otherHostname + "\" - " + fileName);
else
setTitle(TITLE + " - Connected with \"" + otherHostname + "\"");
beep();
showMessage("Connected.");
showMessage("Your are now playing with \"" + otherHostname + "\".");
showMessage("Either player can make a move. The first move decides who plays which side.");
showMessage("You can set your chat name with /name <your name>");
prepareMove();
}
public void updateNavigationButtons() {
// Activate/deactivate navigation buttons:
boolean hasPrev;
if (history.getPreviousGameNode() == history.getCurrentGameNode()) {
buttonStart.setEnabled(false);
buttonPrevious.setEnabled(false);
hasPrev = false;
} else {
buttonStart.setEnabled(true);
buttonPrevious.setEnabled(true);
hasPrev = true;
}
if (history.getNextGameNode() == history.getCurrentGameNode()) {
buttonNext.setEnabled(false);
buttonEnd.setEnabled(false);
} else {
buttonNext.setEnabled(true);
buttonEnd.setEnabled(true);
}
}
public VirtualBoard getCurrentVirtualBoard() {
return history.getCurrentBoard();
}
public boolean isWhiteTurn() {
return history.getCurrentBoard().isWhiteTurn();
}
/**
* Executes the move your opponent has done.
* This is an interface method used by Protocol.
*/
public void makePeersMove(Move move) {
chessClock.stopClock();
beep();
gotoGame(gameTable.getNetworkGameIndex());
history.gotoLast();
// The first move decides!
if (whitePlayer.equals(UNKNOWN) || blackPlayer == UNKNOWN) {
if (isWhiteTurn()) {
whitePlayer = PEER;
blackPlayer = HUMAN;
visualBoard.setReverseBoard(true);
reverseBoard.setSelected(true);
} else {
whitePlayer = HUMAN;
blackPlayer = PEER;
}
}
updateSTR();
VirtualBoard virtualBoard = getCurrentVirtualBoard().clonedBoard();
String algMove = virtualBoard.algebraic(move);
if (isConnected())
showMessage("Opponents move: " + algMove);
try {
virtualBoard.makeMove(move);
history.addMove(algMove, virtualBoard);
visualBoard.showMove(move, 1000);
chessClock.startClock();
checkFinish();
} catch (VirtualBoard.ImpossibleMoveException e) {
showMessage("Error parsing opponents move: " + move);
protocol.sendError("Error parsing move: " + move);
}
prepareMove();
}
public void makeBatchMove(Move move) {
VirtualBoard virtualBoard = getCurrentVirtualBoard().clonedBoard();
String algMove = virtualBoard.algebraic(move);
try {
virtualBoard.makeMove(move);
} catch (VirtualBoard.ImpossibleMoveException e) {
showMessage("Error parsing batch move: " + move);
}
history.addMove(algMove, virtualBoard);
}
/**
* Executes the move of the AI.
* This is an interface method for the AI.
*/
public void makeAIsMove(Move move) {
chessClock.stopClock();
VirtualBoard virtualBoard = getCurrentVirtualBoard().clonedBoard();
String algMove = virtualBoard.algebraic(move);
showMessage("AI's move: " + algMove);
try {
virtualBoard.makeMove(move);
history.addMove(algMove, virtualBoard);
visualBoard.showMove(move, 1000);
chessClock.startClock();
triggerAI();
checkFinish();
} catch (VirtualBoard.ImpossibleMoveException e) {
}
}
/**
* Executes the users move.
* This is an interface method for VisualBoard.
*/
public void makeUsersMove(Move move) {
chessClock.stopClock();
VirtualBoard virtualBoard = getCurrentVirtualBoard().clonedBoard();
String algMove = virtualBoard.algebraic(move);
if (isConnected())
showMessage("Your move: " + algMove);
try {
virtualBoard.makeMove(move);
} catch (VirtualBoard.ImpossibleMoveException e) {
}
history.addMove(algMove, virtualBoard);
if (isConnected() && gameTable.getCurrentGameIndex() == gameTable.getNetworkGameIndex()) {
protocol.sendMove(move);
// The first move decides!
if (whitePlayer.equals(UNKNOWN) || blackPlayer == UNKNOWN) {
if (isWhiteTurn()) {
whitePlayer = PEER;
blackPlayer = HUMAN;
visualBoard.setReverseBoard(true);
reverseBoard.setSelected(true);
} else {
whitePlayer = HUMAN;
blackPlayer = PEER;
}
}
updateSTR();
if (getEnableClock()) {
if (virtualBoard.isWhiteTurn())
protocol.sendPlayersTime(chessClock.getBlackTime());
else
protocol.sendPlayersTime(chessClock.getWhiteTime());
}
}
chessClock.startClock();
triggerAI();
checkFinish();
}
public void triggerAI() {
if (!(whitePlayer == COMPUTER) && !(blackPlayer == COMPUTER))
return;
if (((whitePlayer == COMPUTER) || (blackPlayer == COMPUTER)) && ai == null) {
ai = new AI(this);
}
if (ai != null && !(whitePlayer == COMPUTER) && !(blackPlayer == COMPUTER)) {
ai.shutdown();
ai = null;
return;
}
if (isWhiteTurn()) {
if (whitePlayer == COMPUTER) {
long timeout;
if (clockCheckbox.isSelected()) {
if (history.getFullMoveNumber() < 40)
timeout = chessClock.getWhiteTime() / ((long) (60 - history.getFullMoveNumber()));
else
timeout = chessClock.getWhiteTime() / 20L;
if (timeout < 500) // Minimum time: 500ms.
timeout = 500;
} else
timeout = 5000; // Fixed time, 5 sec.
ai.prepareMove(timeout);
}
} else {
if (blackPlayer == COMPUTER) {
long timeout;
if (clockCheckbox.isSelected()) {
if (history.getFullMoveNumber() < 40)
timeout = chessClock.getBlackTime() / ((long) (60 - history.getFullMoveNumber()));
else
timeout = chessClock.getBlackTime() / 20;
if (timeout < 500) // Minimum time: 500ms.
timeout = 500;
} else
timeout = 5000; // Fixed time, 5 sec.
ai.prepareMove(timeout);
}
}
}
/**
* Pepares some settings for the next move.
* Mainly, it starts and stops the chess clocks.
*/
public void prepareMove() {
// Create the appropiate setting to receive the next move.
// Lock/Unlock the visualBoard:
// if (gameIsFinished)
// visualBoard.setLocked(true);
// else
visualBoard.setLocked(false);
if (isConnected() && history.getNextGameNode() != history.getCurrentGameNode())
visualBoard.setLocked(true);
if (isConnected() && (gameTable.getCurrentGameIndex() != gameTable.getNetworkGameIndex()))
visualBoard.setLocked(true);
if (isWhiteTurn() && ((whitePlayer == PEER) || (whitePlayer == COMPUTER)))
visualBoard.setLocked(true);
if (!isWhiteTurn() && ((blackPlayer == PEER) || (blackPlayer == COMPUTER)))
visualBoard.setLocked(true);
updateMenu();
chessClock.updatePlayerSelectors();
}
public void switchSides() {
String tmp = whitePlayer;
whitePlayer = blackPlayer;
blackPlayer = tmp;
reverseBoard.setSelected(!reverseBoard.isSelected());
visualBoard.setReverseBoard(reverseBoard.isSelected());
updateSTR();
showMessage("Sides switched.");
prepareMove();
}
public void updateSTR() {
PGN.STR str = gameTable.getSTR(gameTable.getCurrentGameIndex());
str.setTag("White", "?");
str.setTag("Black", "?");
if (whitePlayer.equals(PEER))
str.setTag("White", protocol.getOtherPlayersName());
if (whitePlayer.equals(HUMAN))
str.setTag("White", settings.userName);
if (whitePlayer.equals(COMPUTER))
str.setTag("White", TITLE);
if (blackPlayer.equals(PEER))
str.setTag("Black", protocol.getOtherPlayersName());
if (blackPlayer.equals(HUMAN))
str.setTag("Black", settings.userName);
if (blackPlayer.equals(COMPUTER))
str.setTag("Black", TITLE);
infoPanel.repaint();
gameTable.repaint();
}
/*
* Stops the game and creates the appropriate message if the game comes out
* to be finished.
*/
public void checkFinish() {
VirtualBoard virtualBoard = history.getCurrentBoard();
if (virtualBoard.gameIsFinished()) {
if (virtualBoard.onlyKingsLeft()) {
showMessage("Draw!");
} else if (virtualBoard.isWhiteTurn()) {
if (virtualBoard.isAttackedByBlack(virtualBoard.getWhiteKingPos())) {
Object[] options = { "Accept", "Reject" };
showMessage("Black wins!");
JOptionPane.showMessageDialog(null, "Black wins!");
} else {
showMessage("Draw (stalemate)!");
JOptionPane.showMessageDialog(null, "Draw!");
}
} else {
if (virtualBoard.isAttackedByWhite(virtualBoard.getBlackKingPos())) {
showMessage("White wins!");
JOptionPane.showMessageDialog(null, "White wins!");
} else {
showMessage("Draw (stalemate)!");
JOptionPane.showMessageDialog(null, "Draw!");
}
}
chessClock.stopClock();
} else if (clockCheckbox.isSelected() && (chessClock.getWhiteTime() <= 0 || chessClock.getBlackTime() <= 0)) {
chessClock.stopClock();
if (chessClock.getWhiteTime() <= 0) {
showMessage("Black wins (time forfeit)!");
JOptionPane.showMessageDialog(null, "Black wins!");
} else {
showMessage("White wins (time forfeit)!");
JOptionPane.showMessageDialog(null, "White wins!");
}
showMessage(
"White: "
+ chessClock.formatTime(chessClock.getWhiteTime())
+ ", Black: "
+ chessClock.formatTime(chessClock.getBlackTime()));
setEnableClock(false);
showMessage("The clocks have been disabled, you can continue playing, if you want to.");
} else
prepareMove();
}
public void newGame() {
PGN.STR str = new PGN.STR();
gotoGame(gameTable.addGame("", str));
visualBoard.setReverseBoard(false);
if (isConnected()) {
whitePlayer = UNKNOWN;
blackPlayer = UNKNOWN;
gameTable.setNetworkGameIndex(gameTable.getCurrentGameIndex());
} else {
whitePlayer = HUMAN;
blackPlayer = COMPUTER;
}
Calendar cal = Calendar.getInstance();
str.setTag(
"Date",
cal.get(Calendar.YEAR) + "." + (cal.get(Calendar.MONTH) + 1) + "." + cal.get(Calendar.DAY_OF_MONTH));
chessClock.updatePlayerSelectors();
updateSTR();
if (ai != null)
ai.newGame();
chessClock.stopClock();
chessClock.resetClocks();
prepareMove();
// history.setResult("*");
gameIsFinished = false;
fileIsChanged = true;
}
public void newGame(VirtualBoard vb) {
newGame();
history.setBoard(vb.clonedBoard());
PGN.STR str = gameTable.getSTR(gameTable.getCurrentGameIndex());
str.setTag("SetUp", "1");
str.setTag("FEN", vb.getFEN());
update();
}
/**
* Removes this window and whats used by it and calls System.exit() if
* there is no window left.
*/
public void exit() {
if (isConnected()) {
int choice =
JOptionPane.showConfirmDialog(null, "Are you sure?", "Close connection?", JOptionPane.YES_NO_OPTION);
if (choice == JOptionPane.YES_OPTION) {
boardConnector.closeConnection();
connectionClosed();
} else
return;
}
if (isFileChanged())
askForSaving();
if (ai != null)
ai.shutdown();
try {
dispose();
finalize();
} catch (Throwable t) {
System.out.println(t);
}
System.gc();
windowList.remove(this);
if (windowList.size() == 0) {
System.exit(0);
}
}
/**
* Enables/disables certain menu entries depending on the
* current connection state. The checkbox menu items are
* also updated.
*/
public void updateMenu() {
reverseBoard.setSelected(visualBoard.reverseBoard());
if (isConnected()) {
menuItemOfferDraw.setEnabled(true);
menuItemResign.setEnabled(true);
menuItemSwitchSides.setEnabled(true);
menuItemUploadGame.setEnabled(true);
menuItemCloseConnection.setEnabled(true);
menuItemConnect.setEnabled(false);
} else {
menuItemUploadGame.setEnabled(false);
menuItemOfferDraw.setEnabled(false);
menuItemResign.setEnabled(false);
menuItemSwitchSides.setEnabled(false);
menuItemCloseConnection.setEnabled(false);
menuItemConnect.setEnabled(true);
}
}
/**
* Takes back the last move. (What did you expect?)
*/
public void undoMove() {
history.removeLastMove();
showMessage("Last move reversed.");
// Take back two moves if playing against AI:
if (((!isWhiteTurn() && blackPlayer == COMPUTER) || (isWhiteTurn() && whitePlayer == COMPUTER))
&& history.getFullMoveNumber() > 0) {
history.removeLastMove();
}
gameIsFinished = false;
prepareMove();
}
/**
* Makes a beep, if enableBeep.isSelected().
*/
public void beep() {
if (enableBeep.isSelected()) {
getToolkit().beep();
}
}
public void showMessage(String message) {
chat.showMessage(message);
}
public void showMessage(String message, String style) {
chat.showMessage(message, style);
}
public void showReplaceableMessage(String message) {
chat.showReplaceableMessage(message);
}
public void showReplaceableMessage(String message, String style) {
chat.showReplaceableMessage(message, style);
}
public void timeForfeit() {
if (isConnected() && whitePlayer == HUMAN)
protocol.sendPlayersTime(chessClock.getWhiteTime());
if (isConnected() && blackPlayer == HUMAN)
protocol.sendPlayersTime(chessClock.getBlackTime());
checkFinish();
}
/**
* Creates a requester that allows to select time each player has to make moves.
* If the board is connected, a confirmation request for this is send via the
* BoardConnector. In that case, the clock will not yet be changed when this
* method returns.
*/
public void showTimeoutSelector() {
Object message[] = new Object[6];
message[0] = "Select the time each player has to make his moves:";
newWhiteTime = settings.whiteTime;
newBlackTime = settings.blackTime;
coupleSlidersCheckBox = new JCheckBox("Couple sliders");
coupleSlidersCheckBox.setSelected(settings.whiteTime == settings.blackTime);
whiteTimeoutLabel = new JLabel("White: " + newWhiteTime / 60000 + " min.");
whiteSlider = new JSlider(1, 60, (int) (newWhiteTime / 60000));
whiteSlider.setPreferredSize(new Dimension(300, 40));
whiteSlider.setPaintTicks(true);
whiteSlider.setMajorTickSpacing(10);
whiteSlider.setMinorTickSpacing(5);
whiteSlider.setPaintLabels(false);
whiteSlider.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent e) {
newWhiteTime = whiteSlider.getValue() * 60000L;
whiteTimeoutLabel.setText("White: " + newWhiteTime / 60000 + " min.");
if (coupleSlidersCheckBox.isSelected()) {
newBlackTime = newWhiteTime;
blackSlider.setValue((int) newBlackTime / 60000);
blackTimeoutLabel.setText("Black: " + newBlackTime / 60000 + " min.");
}
}
});
blackTimeoutLabel = new JLabel("Black: " + newBlackTime / 60000 + " min.");
blackSlider = new JSlider(1, 60, (int) (newBlackTime / 60000));
blackSlider.setPreferredSize(new Dimension(300, 40));
blackSlider.setPaintTicks(true);
blackSlider.setMajorTickSpacing(10);
blackSlider.setMinorTickSpacing(5);
blackSlider.setPaintLabels(false);
blackSlider.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent e) {
newBlackTime = blackSlider.getValue() * 60000L;
blackTimeoutLabel.setText("Black: " + newBlackTime / 60000 + " min.");
if (coupleSlidersCheckBox.isSelected()) {
newWhiteTime = newBlackTime;
whiteSlider.setValue((int) newWhiteTime / 60000);
whiteTimeoutLabel.setText("White: " + newWhiteTime / 60000 + " min.");
}
}
});
message[1] = whiteSlider;
message[2] = whiteTimeoutLabel;
message[3] = blackSlider;
message[4] = blackTimeoutLabel;
message[5] = coupleSlidersCheckBox;
Object options[] = { "OK", "Cancel" };
int result =
JOptionPane.showOptionDialog(
null,
message,
"Set game time",
0,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
if (result == 0) {
if (isConnected()) {
showMessage("Requesting clock change...");
protocol.requestClockChange(newWhiteTime, newBlackTime);
} else {
settings.whiteTime = newWhiteTime;
settings.blackTime = newBlackTime;
chessClock.resetClocks();
prepareMove();
}
}
}
public void setClocks(long whiteTime, long blackTime) {
settings.whiteTime = whiteTime;
settings.blackTime = blackTime;
chessClock.resetClocks();
showMessage("Game time was changed.");
prepareMove();
}
public void gotoGame(int newGameIndex) {
if (currentGameIndex != -1 && history.isChanged()) {
// Save the current game back to the list first.
gameTable.setPGN(currentGameIndex, history.getPGNBody());
fileIsChanged = true;
}
if (newGameIndex >= gameTable.getGameCount())
newGameIndex = gameTable.getGameCount() - 1;
int lastIndex = currentGameIndex;
currentGameIndex = newGameIndex;
gameTable.setSelectedIndex(currentGameIndex);
gameTable.setCurrentGameIndex(currentGameIndex);
gameTable.updateRow(lastIndex);
try {
history.loadGame(gameTable.getPGN(currentGameIndex), gameTable.getSTR(currentGameIndex));
} catch (VirtualBoard.ImpossibleMoveException e) {
showMessage(e.toString());
}
infoPanel.setSTR(gameTable.getSTR(currentGameIndex));
history.gotoLast();
update();
prepareMove();
}
public void update() {
visualBoard.update();
gameTable.repaint();
updateMenu();
updateNavigationButtons();
notation.update();
chessClock.updatePlayerSelectors();
}
public boolean isFileChanged() {
if (fileName == null || fileName.length() == 0)
return false;
if (fileIsChanged)
return true;
if (currentGameIndex != -1 && history.isChanged()) {
fileIsChanged = true;
return true;
}
return false;
}
public void loadFile(java.io.File file) {
fileChooserDir = file.getPath();
String netPGN = null;
PGN.STR netSTR = null;
if (isConnected()) {
netPGN = gameTable.getPGN(gameTable.getNetworkGameIndex());
netSTR = gameTable.getSTR(gameTable.getNetworkGameIndex());
}
history.clear();
gameTable.clear();
PGN.loadPGN(file, JChessBoard.this);
if (isConnected()) {
gameTable.setNetworkGameIndex(gameTable.addGame(netPGN, netSTR));
}
chessClock.resetClocks();
chessClock.stopClock();
whitePlayer = HUMAN;
blackPlayer = HUMAN;
}
public void askForSaving() {
int choice =
JOptionPane.showConfirmDialog(
null,
fileName + " was changed. Save file?",
"Save?",
JOptionPane.YES_NO_OPTION);
if (choice == JOptionPane.YES_OPTION) {
save(fileName, false);
}
}
public void save(String fileName, boolean append) {
if (currentGameIndex != -1 && history.isChanged()) {
gameTable.setPGN(currentGameIndex, history.getPGNBody());
}
try {
PGN.writePGN(new File(fileName), gameTable, append);
showMessage("Game(s) saved to " + fileName + ".");
fileIsChanged = false;
} catch (IOException o) {
showMessage("IOException: " + o);
}
}
public void saveAs() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new java.io.File(fileChooserDir));
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.resetChoosableFileFilters();
fileChooser.addChoosableFileFilter(new PGNFileFilter());
int choice = fileChooser.showSaveDialog(null);
if (choice == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
fileChooserDir = file.getPath();
fileName = file.getName();
if (!fileName.endsWith(".pgn")) {
fileName += ".pgn";
file = new File(fileName);
}
setTitle(TITLE + " - " + fileName);
if (file.exists()) {
Object[] option = new Object[3];
option[0] = "Append";
option[1] = "Overwrite";
option[2] = "Cancel";
choice =
JOptionPane.showOptionDialog(
null,
"File \"" + file.getName() + "\" exists.",
"File exists",
0,
JOptionPane.QUESTION_MESSAGE,
null,
option,
option[0]);
}
if (choice == 0) { // Append
save(file.getName(), true);
fileIsChanged = false;
showMessage("Reloading complete file...");
loadFile(file);
} else if (choice == 1) { // Overwrite
save(file.getName(), false);
} else // Cancel
return;
}
}
public void uploadGame() {
history.gotoLast();
List allBoards = history.getAllBoards();
protocol.startUpload();
PGN.STR str = gameTable.getSTR(gameTable.getCurrentGameIndex());
if (str.hasTag("SetUp"))
protocol.initFromFEN(str.getTag("FEN"));
if (allBoards.size() > 0) {
for (int n = allBoards.size() - 1; n >= 0; n--) {
Move move = ((VirtualBoard) allBoards.get(n)).getLastMove();
if (move != null)
protocol.sendBatchMove(move);
}
}
protocol.uploadDone();
whitePlayer = UNKNOWN;
blackPlayer = UNKNOWN;
showMessage("Upload finished");
gameTable.setNetworkGameIndex(gameTable.getCurrentGameIndex());
chessClock.stopClock();
chessClock.resetClocks();
update();
prepareMove();
}
/**
* The JChessBoard constructor.
* @param title The title of the created JFrame.
*/
public JChessBoard(String title) {
super(title);
settings = new Settings(settingsFileName);
boolean settingsHaveBeenLoaded = settings.read();
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
windowList.add(this);
JSplitPane splitPane;
splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
splitPane.setOneTouchExpandable(true);
splitPane.setDividerLocation(150);
//
// GameTable
//
gameTable = new GameTable();
// gameTable.addGame("", new PGN.STR());
final JPopupMenu gameTableContextMenu = new JPopupMenu();
JMenuItem removeGameItem = new JMenuItem("Remove game(s)");
removeGameItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
gotoGame(gameTable.removeSelectedGames());
fileIsChanged = true;
}
});
gameTableContextMenu.add(removeGameItem);
gameTable.getJTable().addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
int index = gameTable.getSelectedIndex();
gotoGame(index);
}
}
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()) {
gameTableContextMenu.show((Component) e.getSource(), e.getX(), e.getY());
}
}
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
gameTableContextMenu.show((Component) e.getSource(), e.getX(), e.getY());
}
}
});
KeyStroke enter = KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ENTER, 0);
gameTable.getJTable().unregisterKeyboardAction(enter);
gameTable.getJTable().registerKeyboardAction(new ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
synchronized (this) {
gotoGame(gameTable.getSelectedIndex());
}
}
}, enter, JComponent.WHEN_FOCUSED);
KeyStroke del = KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_DELETE, 0);
gameTable.getJTable().unregisterKeyboardAction(del);
gameTable.getJTable().registerKeyboardAction(new ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
gotoGame(gameTable.removeSelectedGames());
fileIsChanged = true;
}
}, del, JComponent.WHEN_FOCUSED);
splitPane.setTopComponent(gameTable);
tabbedPane = new JTabbedPane();
history = new History(this);
infoPanel = new InfoPanel();
notation = new Notation(history);
tabbedPane.add("Notation", notation);
tabbedPane.add("Tree", history);
tabbedPane.add("Info", infoPanel);
splitPane.setBottomComponent(tabbedPane);
visualBoard = new VisualBoard(this);
connectionIndicator = new ConnectionIndicator();
chat = new Chat(this);
boardConnector = null;
if (connectionListener == null)
connectionListener = new ConnectionListener();
connectionListener.setPort(settings.networkPort);
connectionListener.setEnabled(settings.enableServer);
ai = null; // Because of memory consumption, the AI
// will be started on demand.
chessClock = new ChessClock(this);
chessClock.setEnabled(settings.enableClock);
fileChooserDir = System.getProperty("user.dir");
// Button pane:
buttonPanel = new JPanel(new GridLayout(1, 5));
java.net.URL url = JChessBoard.class.getResource("/images/start.gif");
ImageIcon icon = url != null ? new ImageIcon(url) : new ImageIcon("null");
buttonStart = new JButton(icon);
buttonStart.setContentAreaFilled(false);
buttonStart.setMargin(new Insets(2, 2, 2, 2));
buttonStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
history.gotoFirst();
}
});
buttonPanel.add(buttonStart);
url = JChessBoard.class.getResource("/images/prev.gif");
icon = url != null ? new ImageIcon(url) : new ImageIcon("null");
buttonPrevious = new JButton(icon);
buttonPrevious.setContentAreaFilled(false);
buttonPrevious.setMargin(new Insets(2, 2, 2, 2));
buttonPrevious.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
history.prev();
}
});
buttonPanel.add(buttonPrevious);
url = JChessBoard.class.getResource("/images/next.gif");
icon = url != null ? new ImageIcon(url) : new ImageIcon("null");
buttonNext = new JButton(icon);
buttonNext.setContentAreaFilled(false);
buttonNext.setMargin(new Insets(2, 2, 2, 2));
buttonNext.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
history.next();
}
});
buttonPanel.add(buttonNext);
url = JChessBoard.class.getResource("/images/end.gif");
icon = url != null ? new ImageIcon(url) : new ImageIcon("null");
buttonEnd = new JButton(icon);
buttonEnd.setContentAreaFilled(false);
buttonEnd.setMargin(new Insets(2, 2, 2, 2));
buttonEnd.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
history.gotoLast();
}
});
buttonPanel.add(buttonEnd);
Container contentPane = getContentPane();
GridBagLayout gridBag = new GridBagLayout();
contentPane.setLayout(gridBag);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.gridwidth = 1;
c.gridheight = 1;
c.weightx = 0;
c.weighty = 0;
c.fill = GridBagConstraints.HORIZONTAL;
gridBag.setConstraints(chessClock, c);
contentPane.add(chessClock);
c.gridx = 0;
c.gridy = 1;
c.gridwidth = 1;
c.gridheight = 1;
c.weightx = 0;
c.weighty = 0;
c.fill = GridBagConstraints.NONE;
gridBag.setConstraints(visualBoard, c);
contentPane.add(visualBoard);
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 1;
c.gridheight = 1;
c.weightx = 0;
c.weighty = 0;
c.fill = GridBagConstraints.HORIZONTAL;
gridBag.setConstraints(buttonPanel, c);
contentPane.add(buttonPanel);
c.gridx = 1;
c.gridy = 0;
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridheight = 3;
c.weightx = 1;
c.weighty = 0;
c.fill = GridBagConstraints.BOTH;
gridBag.setConstraints(splitPane, c);
splitPane.setPreferredSize(new Dimension(210, 1));
splitPane.setMinimumSize(new Dimension(210, 1));
contentPane.add(splitPane);
c.gridx = 0;
c.gridy = 3;
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridheight = GridBagConstraints.REMAINDER;
c.weightx = 0;
c.weighty = 1.0;
c.fill = GridBagConstraints.BOTH;
gridBag.setConstraints(chat, c);
contentPane.add(chat);
showMessage("Welcome to " + TITLE + "!");
chat.showMessagePart("Enter ");
chat.showActionMessagePart("/help", "/help");
chat.showMessagePart(" for a list of available commands.\n");
if (settingsHaveBeenLoaded)
showMessage("Settings have been loaded from " + settingsFileName + ".");
//
// Create the menus:
//
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu gameMenu = new JMenu("Game");
JMenu moveMenu = new JMenu("Move");
JMenu settingsMenu = new JMenu("Settings");
JMenu aboutMenu = new JMenu("About");
menuBar.add(gameMenu);
menuBar.add(moveMenu);
menuBar.add(settingsMenu);
menuBar.add(aboutMenu);
JMenuItem menuItemNewWindow = new JMenuItem("New window");
menuItemNewWindow.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
JChessBoard jcb = new JChessBoard(TITLE);
}
});
gameMenu.add(menuItemNewWindow);
menuItemNewGame = new JMenuItem("New game");
menuItemNewGame.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if (isConnected()) {
showMessage("Requesting new game...");
protocol.requestNewGame();
} else {
newGame();
showMessage("New game.");
}
}
});
gameMenu.add(menuItemNewGame);
menuItemLoadFile = new JMenuItem("Load file...");
menuItemLoadFile.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if (isFileChanged())
askForSaving();
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new java.io.File(fileChooserDir));
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.resetChoosableFileFilters();
fileChooser.addChoosableFileFilter(new PGNFileFilter());
int choice = fileChooser.showOpenDialog(null);
if (choice == JFileChooser.APPROVE_OPTION) {
loadFile(fileChooser.getSelectedFile());
fileName = fileChooser.getSelectedFile().getName();
setTitle(TITLE + " - " + fileName);
fileIsChanged = false;
}
}
});
gameMenu.add(menuItemLoadFile);
menuItemSave = new JMenuItem("Save");
menuItemSave.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if (fileName != null && fileName.length() > 0) {
save(fileName, false);
} else {
saveAs();
}
}
});
gameMenu.add(menuItemSave);
menuItemSaveAs = new JMenuItem("Save as...");
menuItemSaveAs.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
saveAs();
}
});
gameMenu.add(menuItemSaveAs);
JMenuItem menuItemOpenBoardEditor = new JMenuItem("Open board editor...");
menuItemOpenBoardEditor.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
new BoardEditor(JChessBoard.this);
}
});
gameMenu.add(menuItemOpenBoardEditor);
gameMenu.addSeparator();
menuItemConnect = new JMenuItem("Connect...");
menuItemConnect.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
Object message[] = new Object[4];
message[0] = "Hostname: ";
JTextField hostField = new JTextField(otherHostname, 30);
message[1] = hostField;
message[2] = "Port: ";
JTextField portField = new JTextField("" + settings.networkPort, 5);
message[3] = portField;
Object options[] = { "OK", "Cancel" };
int choice =
JOptionPane.showOptionDialog(
null,
message,
"Connect...",
0,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
if (choice == 0) {
try {
otherHostname = hostField.getText();
int tmpPort = Integer.parseInt(portField.getText());
if (tmpPort > 65535)
throw (new NumberFormatException());
settings.networkPort = tmpPort;
boardConnector = new BoardConnector(JChessBoard.this, otherHostname, settings.networkPort);
whitePlayer = UNKNOWN;
blackPlayer = UNKNOWN;
protocol.connecting();
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(
null,
"Illegal port: " + portField.getText(),
"Illegal port",
JOptionPane.ERROR_MESSAGE);
}
}
updateMenu();
}
});
gameMenu.add(menuItemConnect);
menuItemCloseConnection = new JMenuItem("Close connection");
menuItemCloseConnection.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
int choice =
JOptionPane.showConfirmDialog(
null,
"Are you sure?",
"Close connection?",
JOptionPane.YES_NO_OPTION);
if (choice == JOptionPane.YES_OPTION) {
boardConnector.closeConnection();
connectionClosed();
}
}
});
gameMenu.add(menuItemCloseConnection);
menuItemCloseConnection.setEnabled(false);
menuItemOfferDraw = new JMenuItem("Offer draw");
menuItemOfferDraw.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if (isConnected()) {
int choice =
JOptionPane.showConfirmDialog(null, "Are you sure?", "Offer draw?", JOptionPane.YES_NO_OPTION);
if (choice == JOptionPane.YES_OPTION) {
showMessage("Offering draw...");
protocol.offerDraw();
}
}
}
});
gameMenu.add(menuItemOfferDraw);
menuItemOfferDraw.setEnabled(false);
menuItemResign = new JMenuItem("Resign");
menuItemResign.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if (isConnected()) {
int choice =
JOptionPane.showConfirmDialog(null, "Are you sure?", "Resign?", JOptionPane.YES_NO_OPTION);
if (choice == JOptionPane.YES_OPTION) {
showMessage("Resigned.");
// stopGame();
protocol.resigned();
if (whitePlayer == HUMAN)
history.setResult("0-1");
else if (blackPlayer == HUMAN)
history.setResult("1-0");
}
}
}
});
gameMenu.add(menuItemResign);
menuItemResign.setEnabled(false);
menuItemSwitchSides = new JMenuItem("Switch sides");
menuItemSwitchSides.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if (isConnected()) {
int choice =
JOptionPane.showConfirmDialog(
null,
"Are you sure?",
"Switch sides?",
JOptionPane.YES_NO_OPTION);
if (choice == JOptionPane.YES_OPTION) {
showMessage("Requesting side switch...");
protocol.requestSideSwitch();
}
}
}
});
gameMenu.add(menuItemSwitchSides);
menuItemUploadGame = new JMenuItem("Upload this game to peer");
menuItemUploadGame.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if (isConnected()) {
showMessage("Asking opponent...");
protocol.requestUpload();
}
}
});
gameMenu.add(menuItemUploadGame);
gameMenu.addSeparator();
JMenuItem item2 = new JMenuItem("Exit");
item2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
exit();
}
});
gameMenu.add(item2);
undoMove = new JMenuItem("Take back last move");
undoMove.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if (isConnected()) {
showMessage("Requesting undo...");
protocol.requestUndo();
} else
undoMove();
}
});
moveMenu.add(undoMove);
JMenuItem editComment = new JMenuItem("Edit comment");
editComment.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
history.editComment();
JChessBoard.this.update();
}
});
moveMenu.add(editComment);
clockCheckbox = new JCheckBoxMenuItem("Clock");
clockCheckbox.setSelected(settings.enableClock);
clockCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if (isConnected()) {
clockCheckbox.setSelected(!clockCheckbox.isSelected());
// Reverse what Swing has done until accepted by peer.
showMessage("Asking opponent...");
protocol.requestToggleClock();
} else {
setEnableClock(clockCheckbox.isSelected());
}
}
});
settingsMenu.add(clockCheckbox);
JMenuItem gameTimeItem = new JMenuItem("Set time...");
gameTimeItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showTimeoutSelector();
}
});
settingsMenu.add(gameTimeItem);
settingsMenu.addSeparator();
enableBeep = new JCheckBoxMenuItem("Beep");
enableBeep.setSelected(settings.enableBeep);
enableBeep.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
settings.enableBeep = enableBeep.isSelected();
}
});
settingsMenu.add(enableBeep);
reverseBoard = new JCheckBoxMenuItem("Reverse board");
reverseBoard.setSelected(false);
reverseBoard.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
visualBoard.setReverseBoard(reverseBoard.isSelected());
}
});
settingsMenu.add(reverseBoard);
showPossibleMoves = new JCheckBoxMenuItem("Show possible moves");
showPossibleMoves.setSelected(settings.showPossibleMoves);
showPossibleMoves.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
settings.showPossibleMoves = showPossibleMoves.isSelected();
}
});
settingsMenu.add(showPossibleMoves);
settingsMenu.addSeparator();
final JMenuItem aiLevelEasy = new JRadioButtonMenuItem("AI level: Easy");
final JMenuItem aiLevelMedium = new JRadioButtonMenuItem("AI level: Medium");
final JMenuItem aiLevelBest = new JRadioButtonMenuItem("AI level: Best");
aiLevelEasy.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
settings.aiLevel=AI.EASY;
ai.setLevel(settings.aiLevel);
aiLevelEasy.setSelected(true);
aiLevelMedium.setSelected(false);
aiLevelBest.setSelected(false);
}
});
aiLevelMedium.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
settings.aiLevel=AI.MEDIUM;
ai.setLevel(settings.aiLevel);
aiLevelEasy.setSelected(false);
aiLevelMedium.setSelected(true);
aiLevelBest.setSelected(false);
}
});
aiLevelBest.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
settings.aiLevel=AI.BEST;
ai.setLevel(settings.aiLevel);
aiLevelEasy.setSelected(false);
aiLevelMedium.setSelected(false);
aiLevelBest.setSelected(true);
}
});
settingsMenu.add(aiLevelEasy);
settingsMenu.add(aiLevelMedium);
settingsMenu.add(aiLevelBest);
aiLevelEasy.setSelected(settings.aiLevel==AI.EASY);
aiLevelMedium.setSelected(settings.aiLevel==AI.MEDIUM);
aiLevelBest.setSelected(settings.aiLevel==AI.BEST);
settingsMenu.addSeparator();
JMenuItem serverSettingsItem = new JMenuItem("Server settings...");
serverSettingsItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
connectionListener.showSettingsPane();
settings.enableServer = connectionListener.isEnabled();
settings.networkPort = connectionListener.getPort();
}
});
settingsMenu.add(serverSettingsItem);
settingsMenu.addSeparator();
JMenuItem saveSettingsItem = new JMenuItem("Save settings");
saveSettingsItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
Dimension size = JChessBoard.this.getSize();
settings.windowWidth = (int) size.getWidth();
settings.windowHeight = (int) size.getHeight();
try {
settings.save();
showMessage("Settings saved to " + settingsFileName + ".");
} catch (IOException e) {
showMessage("IOException saving settings: " + e);
}
}
});
settingsMenu.add(saveSettingsItem);
JMenuItem licensingItem = new JMenuItem("Licensing");
licensingItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
JOptionPane.showMessageDialog(null, COPYRIGHT_MESSAGE, "About", JOptionPane.INFORMATION_MESSAGE);
}
});
aboutMenu.add(licensingItem);
JMenuItem versionsItem = new JMenuItem("Versions");
versionsItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
JOptionPane.showMessageDialog(
null,
AI.getVersion()
+ "\n"
+ BoardConnector.getVersion()
+ "\n"
+ Chat.getVersion()
+ "\n"
+ ChessClock.getVersion()
+ "\n"
+ ConnectionListener.getVersion()
+ "\n"
+ ConnectionIndicator.getVersion()
+ "\n"
+ History.getVersion()
+ "\n"
+ JChessBoard.getVersion()
+ "\n"
+ Move.getVersion()
+ "\n"
+ PGN.getVersion()
+ "\n"
+ VirtualBoard.getVersion()
+ "\n"
+ VisualBoard.getVersion(),
"Version Information",
JOptionPane.INFORMATION_MESSAGE);
}
});
aboutMenu.add(versionsItem);
updateMenu();
updateNavigationButtons();
pack();
setSize(settings.windowWidth, settings.windowHeight);
// setResizable(false);
setVisible(true);
addComponentListener(new ComponentListener() {
public void componentResized(ComponentEvent e) {
int width = getWidth();
int height = getHeight();
if (width < MIN_WIDTH || height < MIN_HEIGHT) {
width = (width < MIN_WIDTH) ? MIN_WIDTH : width;
height = (height < MIN_HEIGHT) ? MIN_HEIGHT : height;
JChessBoard.this.setSize(width, height);
}
}
public void componentMoved(ComponentEvent e) {
}
public void componentShown(ComponentEvent e) {
}
public void componentHidden(ComponentEvent e) {
}
});
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
exit();
}
});
fileIsChanged = false;
newGame();
ai=new AI(JChessBoard.this);
ai.setLevel(settings.aiLevel);
}
// main
public static void main(final String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JChessBoard jcb = new JChessBoard(TITLE);
if (args.length > 0) {
jcb.loadFile(new java.io.File(args[0]));
}
}
});
}
}