This repository has been archived on 2021-02-18. You can view files and clone it, but cannot push or open issues or pull requests.
chess/src/main/java/dev/kske/chess/ui/MainWindow.java

256 lines
6.8 KiB
Java

package dev.kske.chess.ui;
import java.awt.Desktop;
import java.awt.Toolkit;
import java.awt.dnd.DropTarget;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
import javax.swing.*;
import dev.kske.chess.board.Board;
import dev.kske.chess.board.FENString;
import dev.kske.chess.exception.ChessException;
import dev.kske.chess.game.Game;
import dev.kske.chess.pgn.PGNDatabase;
import dev.kske.chess.pgn.PGNGame;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>MainWindow.java</strong><br>
* Created: <strong>01.07.2019</strong><br>
*
* @since Chess v0.1-alpha
* @author Kai S. K. Engelbart
*/
public class MainWindow extends JFrame {
private JTabbedPane tabbedPane = new JTabbedPane();
private static final long serialVersionUID = -3100939302567978977L;
/**
* Launch the application.
*
* @param args command line arguments are ignored
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(MainWindow::new);
}
/**
* Create the application.
*/
private MainWindow() {
super("Chess by Kai S. K. Engelbart");
// Configure frame
setResizable(false);
setBounds(100, 100, 494, 565);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setIconImage(
Toolkit.getDefaultToolkit()
.getImage(getClass().getResource("/pieces/queen_white.png"))
);
// Add tabbed pane, menu bar and drop target
getContentPane().add(tabbedPane);
setJMenuBar(new MenuBar(this));
new DropTarget(this, new GameDropTarget(this));
// Update position and dimensions
pack();
setLocationRelativeTo(null);
setVisible(true);
}
/**
* @return the currently selected {@link GamePane} component
*/
public GamePane getSelectedGamePane() {
return (GamePane) tabbedPane.getSelectedComponent();
}
/**
* Creates a new {@link GamePane}, adds it to the tabbed pane and opens it.
* The new tab has the title {@code Game n} where {@code n} is its number.
*
* @return the new {@link GamePane}
*/
public GamePane addGamePane() {
return addGamePane("Game " + (tabbedPane.getTabCount() + 1));
}
/**
* Creates a new {@link GamePane}, adds it to the tabbed pane and opens it.
*
* @param title The title of the {@link GamePane}
* @return the new {@link GamePane}
*/
public GamePane addGamePane(String title) {
GamePane gamePane = new GamePane();
tabbedPane.add(title, gamePane);
tabbedPane.setTabComponentAt(
tabbedPane.getTabCount() - 1,
new GameTabComponent(tabbedPane)
);
tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
return gamePane;
}
/**
* Creates a new {@link GamePane}, adds it to the tabbed pane and
* immediately
* displays a game configuration dialog for a new game on an existing
* {@link Board}.
*
* @param title the title of the {@link GamePane}
* @param board the {@link Board} with which the new {@link Game} is started
* @return the new {@link GamePane}
*/
public GamePane addGamePane(String title, Board board) {
GamePane gamePane = addGamePane(title);
DialogUtil.showGameConfigurationDialog(
this,
(whiteName, blackName) -> {
Game game = new Game(
gamePane.getBoardPane(),
whiteName,
blackName,
board
);
gamePane.setGame(game);
game.start();
}
);
return gamePane;
}
/**
* Removes a {@link GamePane} form the tabbed pane.
*
* @param index The index of the {@link GamePane} to remove
*/
public void removeGamePane(int index) {
tabbedPane.remove(index);
}
/**
* Loads a game file (FEN or PGN) and adds it to a new {@link GamePane}.
*
* @param files the files to load the game from
*/
public void loadFiles(List<File> files) {
files.forEach(file -> {
final String name
= file.getName().substring(0, file.getName().lastIndexOf('.'));
final String extension = file.getName()
.substring(file.getName().lastIndexOf('.'))
.toLowerCase();
try {
Board board;
switch (extension) {
case ".fen":
board = new FENString(
new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8)
).getBoard();
break;
case ".pgn":
PGNDatabase pgnDB = new PGNDatabase();
pgnDB.load(file);
if (pgnDB.getGames().size() > 0) {
String[] gameNames
= new String[pgnDB.getGames().size()];
for (int i = 0; i < gameNames.length; i++) {
final PGNGame game = pgnDB.getGames().get(i);
gameNames[i] = String.format(
"%s vs %s: %s",
game.getTag("White"),
game.getTag("Black"),
game.getTag("Result")
);
}
JComboBox<String> comboBox
= new JComboBox<>(gameNames);
JOptionPane.showMessageDialog(
this,
comboBox,
"Select a game",
JOptionPane.QUESTION_MESSAGE
);
board = pgnDB.getGames()
.get(comboBox.getSelectedIndex())
.getBoard();
} else
throw new ChessException(
"The PGN database '" + name + "' is empty!"
);
break;
default:
throw new ChessException(
"The file extension '" + extension
+ "' is not supported!"
);
}
addGamePane(name, board);
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(
this,
"Failed to load the file " + file.getName() + ": "
+ e.toString(),
"File loading error",
JOptionPane.ERROR_MESSAGE
);
}
});
}
/**
* Saves the current {@link Game} as a file in {@code PGN} or {@code FEN}
* format.
*
* @param file the file in which to save the current {@link Game}
*/
public void saveFile(File file) {
final int dotIndex = file.getName().lastIndexOf('.');
final String extension
= file.getName().substring(dotIndex).toLowerCase();
if (extension.equals(".pgn"))
try {
PGNGame pgnGame
= new PGNGame(getSelectedGamePane().getGame().getBoard());
pgnGame.setTag(
"Event",
tabbedPane.getTitleAt(tabbedPane.getSelectedIndex())
);
pgnGame.setTag("Result", "*");
PGNDatabase pgnDB = new PGNDatabase();
pgnDB.getGames().add(pgnGame);
pgnDB.save(file);
if (
JOptionPane.showConfirmDialog(
this,
"Game export finished. Do you want to view the created file?",
"Game export finished",
JOptionPane.YES_NO_OPTION
) == JOptionPane.YES_OPTION
)
Desktop.getDesktop().open(file);
} catch (IOException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(
this,
"Failed to save the file " + file.getName() + ": " + e,
"File saving error",
JOptionPane.ERROR_MESSAGE
);
}
}
}