Files
secondo/Javagui/viewer/chess/ChessFileExporter.java

367 lines
11 KiB
Java
Raw Normal View History

2026-01-23 17:03:45 +08:00
//This file is part of SECONDO.
//Copyright (C) 2004, University in Hagen, Department of Computer Science,
//Database Systems for New Applications.
//SECONDO 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.
//SECONDO 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 SECONDO; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package viewer.chess;
import java.io.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
/**
*This class provides functionality for exporting chess games to pgn files.
*/
public class ChessFileExporter
{
/**
* constant for the maximum characters per line
*/
public static final int MAX_LINE_LENGTH = 80;
/**
* the Game Deliverer to get a vector of the current games from
*/
private GameDeliverer gameDeliverer;
/**
* file chooser to choose the file to write the chessgames to
*/
private JFileChooser chooser;
/**
* parent component to place the dialogues on
*/
private JComponent parent;
/**
* boolean value whether a new file was created. Needed to clean up if a new file was created and the writing process is aborted in any way
*/
private boolean createdNewFile = false;
/**
*list to choose the chessgames that will be written to the pgn-file from
*/
private JList gameChooser;
/**
* box which contains everything to show the "select the chessgames you want to export"-dialogue
*/
private Box gameChooserView;
/**
* the currently shown game.
*/
private GameData currentGame;
/**
*constructor which needs a GameDeliverer to get the games which will be exported. Furthermore this needs a JComponent to locate the
*Dialogues on.
*/
public ChessFileExporter(GameDeliverer gameDeliverer, JComponent parent)
{
this.gameDeliverer = gameDeliverer;
this.parent = parent;
chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(false);
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY );
gameChooser = new JList();
gameChooser.setFixedCellWidth(300);
gameChooser.setVisibleRowCount(5);
gameChooser.setFixedCellHeight(24);
JScrollPane scroll = new JScrollPane(gameChooser);
gameChooserView = new Box(BoxLayout.Y_AXIS);
JPanel p1 = new JPanel(new FlowLayout(FlowLayout.LEFT,0,0));
JPanel p2 = new JPanel(new FlowLayout(FlowLayout.LEFT,0,0));
JPanel p3 = new JPanel(new FlowLayout(FlowLayout.LEFT,0,0));
JLabel lbl = new JLabel("Please select which chessgames you want to export.");
JLabel lbl2=new JLabel("Note: Duplicated chessgames will be saved only once.");
p1.add(lbl);
p2.add(scroll);
p3.add(lbl2);
gameChooserView.add(p1);
gameChooserView.add(p2);
gameChooserView.add(p3);
}
/**
* method to show an error. The String is the displayed error message
*/
private void showError(String errorMessage)
{
JOptionPane.showMessageDialog(parent,errorMessage,"error",JOptionPane.WARNING_MESSAGE );
}
/**
* lets the user choose a file, adds the ending ".pgn" to the filename, if neccessary and creates a new file if neccessary
*/
private File fileCreation() throws IOException, Exception
{
File file = chooser.getSelectedFile(); //file choosing
if (!file.getName().toLowerCase().endsWith(".pgn")) //test if already has the right file extension
{
String path = file.getParent();
String name = file.getName();
if(path == null)
file = new File(File.separatorChar+name+".pgn");
else
file = new File(path+File.separatorChar+name+".pgn");
}
createdNewFile = false;
createdNewFile = file.createNewFile(); //create new file if neccessary
int selection = JOptionPane.YES_OPTION;
if(!createdNewFile) // question if existing file should be overwritten
{
selection = JOptionPane.showConfirmDialog(parent,"A file called "+file.getName()+" already exists in the current Directory, do you want to overwrite?","File already exists",JOptionPane.YES_NO_OPTION);
}
if(selection != JOptionPane.YES_OPTION)
throw new Exception();
return file;
}
/**
* method to show a number of dialogues to export a chessgame. 'current' is the currently shown chessgame in the view
*/
public void showSaveDialog(GameData current)
{
this.currentGame = current;
if(chooser.showSaveDialog(parent)==JFileChooser.APPROVE_OPTION) // if the user decided which file the games will be written to
{
File file = null;
try
{
file = fileCreation(); // file is created
try
{
saveChessGames(file); // chessgames are written to the file if possible
}
catch (Exception e)
{
if(createdNewFile)
{
try
{
file.delete();
}
catch (Exception e2)
{
}
}
}
}
catch(IOException ioe) // if an io Exception occurs the file cannot be written.
{
showError("Error: Cannot write file !");
}
catch (Exception ex)
{
showSaveDialog(currentGame);
}
}
}
/** method to show a dialogue in which the user can select the chessgames which should be exported. Returns an array of objects which contains these chessgames
*/
private Object[] selectChessGames(Vector v) throws Exception
{
Object[] selectedGames;
gameChooser.setListData(v);
int selection = JOptionPane.showConfirmDialog(parent,gameChooserView, "Please select chessgames", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
if(selection == JOptionPane.CANCEL_OPTION)
{
throw new Exception();
}
selectedGames = gameChooser.getSelectedValues();
if (selectedGames.length == 0)
{
showError("No selection was made, file saving abborted.");
throw new Exception();
}
return selectedGames;
}
/**
* writes the chessgames to the file. Gets the games whih should be written and the PrintWriter which writes the files
*/
private void writeGames(Object[] selectedGames, PrintWriter p) throws Exception
{
ArrayList alreadyWritten = new ArrayList();
for(int i = 0;i<selectedGames.length;i++)
{
try
{
if(!alreadyWritten.contains(selectedGames[i])) // tries to write a file
{
writePGNtoFile(p, (GameData)selectedGames[i]);
alreadyWritten.add(selectedGames[i]);
}
}
catch (ClassCastException cce) //if class cast Exception occurs it is the special entry which says "current game"
{
if(!alreadyWritten.contains(currentGame))
{
writePGNtoFile(p, currentGame);
alreadyWritten.add(currentGame);
}
}
}
p.flush();
JOptionPane.showMessageDialog(parent, "PGN file succesfully written.","Success", JOptionPane.INFORMATION_MESSAGE);
}
/**
* manages the writing of the chessgames to the given file. Returns an Exception if writing is not possible.
*/
private void saveChessGames(File f) throws Exception
{
Vector v = gameDeliverer.getAllGames();
v.add(0,"selected Chessgame");
Object[] selectedGames = v.toArray();
if (v.size()> 1)
{
selectedGames = selectChessGames(v); // gets the games that will be selected
}
FileWriter fileWriter = null;
PrintWriter p = null;
try
{
fileWriter = new FileWriter(f, false); //creation of writers /opening file and writing the file
p = new PrintWriter(fileWriter);
writeGames(selectedGames,p);
}
catch (Exception exc)
{
showError("Error: Could not write file."); // if problems occur while writing
throw new Exception();
}
finally
{
try
{
fileWriter.close(); // closing of the writers if possible
p.close();
}
catch(Exception e){}
}
}
/**
* writes a tag pair to the file with the PrintWriter p. Key is the key of the tag pair and value the value.
*/
private void writeTag(PrintWriter p, String key, String value) throws Exception
{
if(!value.equals(""))
{
StringBuffer out = new StringBuffer();
out.append('[');
out.append(key);
out.append(' ');
out.append('"');
out.append(value);
out.append('"');
out.append(']');
p.println(out.toString());
}
}
/**
* writes all the tags of the chessgame g with the PrintWriter p to the file. This method manages writing at least the most common tags of a chessgames to the pgn file
*/
private void writeAllTags(PrintWriter p, GameData g) throws Exception
{
writeTag(p, ChessToolKit.EVENT_KEY, g.getEvent());
writeTag(p, ChessToolKit.SITE_KEY, g.getSite());
writeTag(p, ChessToolKit.DATE_KEY, g.getDate());
writeTag(p, ChessToolKit.ROUND_KEY, g.getRound());
writeTag(p, ChessToolKit.WHITE_KEY, g.getWhite());
writeTag(p, ChessToolKit.BLACK_KEY, g.getBlack());
writeTag(p, ChessToolKit.RESULT_KEY, g.getResult());
HashMap tags = g.getTags();
if(tags != null)
{
Object[] keys = g.getKeys();
for(int i=0;i<keys.length;i++)
{
writeTag(p, (String)keys[i],(String)tags.get(keys[i]));
}
}
}
/**
* this methods writes all the moves of the Game g with the PrintWriter p to the file.
* Checks all the time if the line length is not to long (<80 characters)
*/
private void writeAllMoves(PrintWriter p, GameData g) throws Exception
{
int lineLength = 0;
int movePos = 0;
int moveNumber = 1;
String pgn;
MoveData currentMove;
Object[] moves = g.getMoves();
StringBuffer out = new StringBuffer();
while(movePos < moves.length) // writing moves
{
currentMove = (MoveData)moves[movePos];
pgn = currentMove.getPgn();
if(currentMove.isWhite())
{
if((lineLength+2+((""+moveNumber).length()))>=ChessFileExporter.MAX_LINE_LENGTH)
{
p.println(out.toString());
out.delete(0,out.length());
lineLength = 0;
}
out.append(moveNumber);
out.append('.');
out.append(' ');
moveNumber++;
lineLength = lineLength+2+((""+moveNumber).length());
}
if((lineLength + pgn.length()+1) >=ChessFileExporter.MAX_LINE_LENGTH)
{
p.println(out.toString());
out.delete(0,out.length());
lineLength = 0;
}
out.append(pgn);
out.append(' ');
lineLength = lineLength+pgn.length()+1;
movePos++;
}
if(lineLength+g.getResult().length()+1 >=80) // writing game result
{
p.println(out.toString());
out.delete(0,out.length());
}
out.append(g.getResult());
p.println(out.toString());
}
/**
* method which manages writing the chessgame g with the PrintWriter p to the file.
**/
private void writePGNtoFile(PrintWriter p, GameData g) throws Exception
{
writeAllTags(p, g);
p.println();
writeAllMoves(p,g);
p.println();
}
}