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

286 lines
7.9 KiB
Java
Raw Normal View History

2026-01-23 17:03:45 +08:00
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);
}
}
}