286 lines
7.9 KiB
Java
286 lines
7.9 KiB
Java
|
|
package viewer.chess;
|
||
|
|
|
||
|
|
import javax.swing.*;
|
||
|
|
import java.awt.*;
|
||
|
|
import java.awt.event.*;
|
||
|
|
import java.util.*;
|
||
|
|
import java.io.*;
|
||
|
|
import viewer.*;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* This class provides a panel for viewing and controling the moves of a chessgame. To achieve this MoveNavigationPanel is a direct subclass of JPanel and implements the MoveWatcher Interface.
|
||
|
|
*/
|
||
|
|
public class MoveNavigationPanel extends JPanel implements MoveWatcher
|
||
|
|
{
|
||
|
|
|
||
|
|
/**
|
||
|
|
* This inner class provides functionality to switch through the moves of a chessgame in correct order automatically. ChessPlayer is a subclass of Thread.
|
||
|
|
*/
|
||
|
|
private class ChessPlayer extends Thread
|
||
|
|
{
|
||
|
|
public void run()
|
||
|
|
{
|
||
|
|
int selected = moveChooser.getSelectedIndex()+1; //get selected movenumber
|
||
|
|
while (selected < moveChooser.getItemCount() && playing) //as long as there is no interruption and there are more moves to be shown
|
||
|
|
{
|
||
|
|
moveChooser.setSelectedIndex(selected); //set move selection
|
||
|
|
selected++;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
Thread.sleep(1500);
|
||
|
|
}
|
||
|
|
catch (InterruptedException e)
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if(playing) //if there was no interruption of playing by the user
|
||
|
|
play.doClick();
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* combobox for selecting the move
|
||
|
|
*/
|
||
|
|
private JComboBox moveChooser;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* buttons for controlling the current move
|
||
|
|
*/
|
||
|
|
private JButton begin, end , fwd, back;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* button for automatically showing all moves
|
||
|
|
*/
|
||
|
|
private JToggleButton play;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* the view where the move is shown in
|
||
|
|
*/
|
||
|
|
private GameView theGameView;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* the game whose moves are shown at the moment
|
||
|
|
*/
|
||
|
|
private GameData currentGame;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* this field is checked by the ChessPlayer class and set/reset by the play button. While this is true the ChessPlayer - Thread shows the next move on a regular basis.
|
||
|
|
*/
|
||
|
|
private boolean playing;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* constructor of MoveNavigationPanel needs a GameView object where the moves have to be shown in
|
||
|
|
*/
|
||
|
|
public MoveNavigationPanel(GameView gv)
|
||
|
|
{
|
||
|
|
this.theGameView = gv;
|
||
|
|
|
||
|
|
this.moveChooser = new JComboBox(); //set up the move chooser
|
||
|
|
this.moveChooser.setMinimumSize(new Dimension(350,24));
|
||
|
|
this.moveChooser.setPreferredSize(new Dimension(350,24));
|
||
|
|
this.moveChooser.addActionListener(new ActionListener()
|
||
|
|
{
|
||
|
|
public void actionPerformed(ActionEvent e)
|
||
|
|
{
|
||
|
|
showMove();
|
||
|
|
}
|
||
|
|
|
||
|
|
});
|
||
|
|
|
||
|
|
JPanel movePanel = new JPanel();
|
||
|
|
movePanel.setLayout(new GridLayout(1,4));
|
||
|
|
|
||
|
|
|
||
|
|
this.begin = new JButton("<<"); //button to return to the first move
|
||
|
|
begin.addActionListener(new ActionListener()
|
||
|
|
{
|
||
|
|
public void actionPerformed(ActionEvent e)
|
||
|
|
{
|
||
|
|
if(moveChooser.getItemCount()>0)
|
||
|
|
moveChooser.setSelectedIndex(0);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
this.back = new JButton("<"); //button to go back one move
|
||
|
|
back.addActionListener(new ActionListener()
|
||
|
|
{
|
||
|
|
public void actionPerformed(ActionEvent e)
|
||
|
|
{
|
||
|
|
if (moveChooser.getItemCount()>0)
|
||
|
|
moveChooser.setSelectedIndex(moveChooser.getSelectedIndex()>0?moveChooser.getSelectedIndex()-1:0);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
this.end = new JButton(">>"); //button to go to the last move
|
||
|
|
end.addActionListener(new ActionListener()
|
||
|
|
{
|
||
|
|
public void actionPerformed(ActionEvent e)
|
||
|
|
{
|
||
|
|
moveChooser.setSelectedIndex(moveChooser.getItemCount()-1);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
this.fwd = new JButton(">"); //button to go to the next move
|
||
|
|
fwd.addActionListener(new ActionListener()
|
||
|
|
{
|
||
|
|
public void actionPerformed(ActionEvent e)
|
||
|
|
{
|
||
|
|
moveChooser.setSelectedIndex(moveChooser.getSelectedIndex() < (moveChooser.getItemCount()-1)?moveChooser.getSelectedIndex()+1:moveChooser.getItemCount()-1);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
this.play = new JToggleButton("play");
|
||
|
|
play.addActionListener(new ActionListener()
|
||
|
|
{
|
||
|
|
public void actionPerformed(ActionEvent e)
|
||
|
|
{
|
||
|
|
if(play.isSelected()) //if the button is selected
|
||
|
|
{
|
||
|
|
play.setText("stop"); //the text on the button is changed and all other ways of manipulating the current move are disabled
|
||
|
|
begin.setEnabled(false);
|
||
|
|
back.setEnabled(false);
|
||
|
|
end.setEnabled(false);
|
||
|
|
fwd.setEnabled(false);
|
||
|
|
moveChooser.setEnabled(false);
|
||
|
|
playing = true;
|
||
|
|
if(currentGame != null)
|
||
|
|
{
|
||
|
|
ChessPlayer cp = new ChessPlayer(); //a new Thread controls showing the moves
|
||
|
|
cp.start();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
play.setText("play"); //if not selected all other ways of manipulating the current move are enabled
|
||
|
|
begin.setEnabled(true);
|
||
|
|
back.setEnabled(true);
|
||
|
|
end.setEnabled(true);
|
||
|
|
fwd.setEnabled(true);
|
||
|
|
moveChooser.setEnabled(true);
|
||
|
|
playing = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
play.setPreferredSize(new Dimension(65,24));
|
||
|
|
movePanel.add(begin);
|
||
|
|
movePanel.add(back);
|
||
|
|
movePanel.add(play);
|
||
|
|
movePanel.add(fwd);
|
||
|
|
movePanel.add(end);
|
||
|
|
|
||
|
|
FlowLayout f = new FlowLayout(FlowLayout.LEFT, 2,2);
|
||
|
|
this.setLayout(f);
|
||
|
|
this.add(new JLabel("move: "));
|
||
|
|
this.add(moveChooser);
|
||
|
|
this.add(new JLabel(" control: "));
|
||
|
|
this.add(movePanel);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* inherited from chess.MoveWatcher, sets the current game whose moves are displayed.
|
||
|
|
*/
|
||
|
|
public void setCurrentGame(GameData g)
|
||
|
|
{
|
||
|
|
if (playing)
|
||
|
|
play.doClick(); //stop showing the current moves if necessary
|
||
|
|
if(g != null)
|
||
|
|
{
|
||
|
|
theGameView.clear(); //clear the view
|
||
|
|
int selected = g.getCurrentMoveIndex();
|
||
|
|
this.currentGame = g;
|
||
|
|
moveChooser.removeAllItems(); //remove everything
|
||
|
|
Object[] movesOfGame = g.getMoves();
|
||
|
|
MoveData initialMove = new MoveData();
|
||
|
|
moveChooser.addItem(initialMove);
|
||
|
|
for(int i = 0; i< movesOfGame.length;i++)
|
||
|
|
{
|
||
|
|
moveChooser.addItem((MoveData)movesOfGame[i]);
|
||
|
|
}
|
||
|
|
if(selected != -1) //if possible show the last move that was shown before of this game
|
||
|
|
moveChooser.setSelectedIndex(selected);
|
||
|
|
else
|
||
|
|
moveChooser.setSelectedIndex(0);
|
||
|
|
currentGame.setCurrentMoveIndex(selected);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
currentGame = g;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* add m to the movechooser
|
||
|
|
*/
|
||
|
|
public void addMove(MoveData m)
|
||
|
|
{
|
||
|
|
this.moveChooser.addItem(m);
|
||
|
|
}
|
||
|
|
|
||
|
|
/***
|
||
|
|
* set the selected move
|
||
|
|
*/
|
||
|
|
public void setSelected(MoveData m)
|
||
|
|
{
|
||
|
|
this.moveChooser.setSelectedItem(m);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* clear the MoveNavigationPanel
|
||
|
|
*/
|
||
|
|
public void clearMoves()
|
||
|
|
{
|
||
|
|
currentGame = null;
|
||
|
|
this.moveChooser.removeAllItems();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* set the GameView where the moves are shown in. This is especially useful when there is more than one chessgame attribute in a relation
|
||
|
|
*/
|
||
|
|
public void setView(GameView gv)
|
||
|
|
{
|
||
|
|
this.theGameView = gv;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* get the move which is shown at the moment
|
||
|
|
*/
|
||
|
|
public MoveData getCurrentMove()
|
||
|
|
{
|
||
|
|
return (MoveData)this.moveChooser.getItemAt(this.moveChooser.getSelectedIndex());
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* show the move in the viewer. Called when a new move is selected
|
||
|
|
*/
|
||
|
|
private void showMove()
|
||
|
|
{
|
||
|
|
if(moveChooser.getSelectedItem()!= null)
|
||
|
|
{
|
||
|
|
showMoveInView(moveChooser.getSelectedIndex());
|
||
|
|
theGameView.repaint();
|
||
|
|
moveChooser.setToolTipText(moveChooser.getSelectedItem().toString());
|
||
|
|
if(currentGame != null)
|
||
|
|
currentGame.setCurrentMoveIndex(moveChooser.getSelectedIndex()); //save the index of the current move to the chessgame
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* this method shows the move with index 'index' in the GameView.
|
||
|
|
*/
|
||
|
|
private void showMoveInView(int index)
|
||
|
|
{
|
||
|
|
//since the showMove method in the GameView class throws an IllegalArgumentException if the move is not the direct next move
|
||
|
|
try
|
||
|
|
{
|
||
|
|
//the method first tries to show the move of index
|
||
|
|
theGameView.showMove((MoveData)moveChooser.getItemAt(index), index);
|
||
|
|
}
|
||
|
|
catch (IllegalArgumentException e)
|
||
|
|
{
|
||
|
|
//if that fails the move before index is shown calling this method recursively. Hence all the moves between index and the current move will be calculated in the viewer
|
||
|
|
showMoveInView(index-1);
|
||
|
|
//now the move can be shown!
|
||
|
|
theGameView.showMove((MoveData)moveChooser.getItemAt(index), index);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|