/*
* JFLAP - Formal Languages and Automata Package
*
*
* Susan H. Rodger
* Computer Science Department
* Duke University
* August 27, 2009
* Copyright (c) 2002-2009
* All rights reserved.
* JFLAP is open source software. Please see the LICENSE for terms.
*
*/
package gui.pumping;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.text.JTextComponent;
import pumping.*;
/**
* A PumpingLemmaInputPane
is a JPanel
that
* provides the user with an interface to work with regular or
* context-free pumping lemmas where either the user or the computer
* go first.
*
* @author Jinghui Lim & Chris Morgan
* @see pumping.PumpingLemma
*
*/
public abstract class PumpingLemmaInputPane extends JPanel
{
/**
* The maximum size of the window. It should fit onto most
* screens.
*/
protected static Dimension MAX_SIZE = new Dimension(640, 580);
/**
* The instruction that prompts the user to view the animation.
*/
private static String PROMPT_ANIM = "Click \"Step\" in Box 5 to step the animation.";
/**
* The instruction that prompts the user to view the animation or add the case.
*/
private static String PROMPT_CASE = "Click \"Step\" in Box 5 to step the animation or " +
"\"Add\" in the right panel to add this case.";
/**
* The PumpingLemma
that we are demonstrating.
*/
protected PumpingLemma myLemma;
/**
* The text component where m is displayed and/or entered, depending on the subclass.
*/
protected JTextComponent myMDisplay;
/**
* The text component where w is displayed and/or entered, depending on the subclass.
*/
protected JTextComponent myWDisplay;
/**
* The text component where i is displayed and/or entered, depending on the subclass.
*/
protected JTextComponent myIDisplay;
/**
* The text area that the program displays the pumped string in.
*/
protected JTextArea myPumpedStringDisplay;
/**
* The Canvas
the animation takes place in.
*/
protected Canvas myCanvas;
/**
* The button that restarts the animation.
*/
protected JButton myStartAnimation;
/**
* The button that steps the animation.
*/
protected JButton myStepAnimation;
/**
* The HTML text area that provides a short explanation of the animation.
*/
protected JEditorPane myLastWord;
/**
* The HTML text area where the explanation is displayed, the attempts are listed,
* and the "File Loaded." message appears.
*/
private JTextPane myTopTextPane;
/**
* The CasePanel
that manages the cases of this pumping lemma.
*/
protected CasePanel myCases;
/**
* The panel where most things occur, all except the case display in myCases.
*/
protected JPanel leftPanel;
/**
* The subpanels of leftPanel. There is one "stage" each for the top display,
* m panel, w panel, decomposition panel, i panel, and canvas
* panel.
*/
protected JPanel[] stages;
/**
* The labels associated with the stages. Most are in the lower left of the
* associated stage panels. The label for stage[0] isn't explicitly added onto
* the screen, but the text is always added to the JTextPane
at the top.
*/
protected JLabel[] stageMessages;
/**
* Creates a user interface for a PumpingLemma
with the stated
* title. The title can contain HTML tags to display superscripts or
* subscripts.
myShowAll.setToolTipText("
*
* @param l the pumping lemma we are working with
* @param title the title of the lemma
*/
public PumpingLemmaInputPane(PumpingLemma l, String title)
{
this.setLayout(new BorderLayout());
myLemma = l;
JPanel p = new JPanel(new BorderLayout());
JEditorPane ep = new JEditorPane("text/html", "
" +
title + "");
ep.setBackground(this.getBackground());
ep.setDisabledTextColor(Color.BLACK);
ep.setEnabled(false);
p.add(ep, BorderLayout.NORTH);
/*
* If there is only one case, do not set up the split pane.
*
* Otherwise, set up the split pane with the case panel on the right.
*/
leftPanel = new JPanel();
leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS));
initLeftPanel();
if(myLemma.numCasesTotal() <= 1 || this instanceof ComputerFirstPane)
{
leftPanel.setPreferredSize(MAX_SIZE);
leftPanel.setMaximumSize(MAX_SIZE);
p.add(leftPanel, BorderLayout.CENTER);
}
else
{
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
leftPanel.revalidate();
leftPanel.setPreferredSize(new Dimension(400, 300));
leftPanel.setMaximumSize(MAX_SIZE);
splitPane.setLeftComponent(leftPanel);
JComponent rightPanel = initRightPanel();
rightPanel.setPreferredSize(new Dimension(400, 300));
rightPanel.setMaximumSize(MAX_SIZE);
splitPane.setRightComponent(rightPanel);
p.add(splitPane, BorderLayout.CENTER);
}
JScrollPane scrollPane = new JScrollPane(p);
add(scrollPane, BorderLayout.CENTER);
this.setMaximumSize(MAX_SIZE);
this.setPreferredSize(MAX_SIZE);
}
/**
* Initializes the left panel, or, if the pumping lemma
* has only one case, the only panel. This function also sets the initial
* visibility of the various stages.
*/
private void initLeftPanel()
{
stages = new JPanel[6];
stageMessages = new JLabel[6];
for (int i=0; iCasePanel that manages user interaction for the
* different cases of the pumping lemma
*/
private JComponent initRightPanel()
{
myCases = new CasePanel((ContextFreePumpingLemma)myLemma, this);
return new JScrollPane(myCases);
}
/**
* Initializes and returns the the top stage and its JPanel.
*
* @return the initialized top JPanel
*/
private JPanel initTop()
{
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
JButton clear, explain;
clear = new JButton("Clear All");
explain = new JButton("Explain");
myTopTextPane = new JTextPane();
JScrollPane sp = new JScrollPane(myTopTextPane);
myTopTextPane.setContentType("text/html");
myTopTextPane.setEditable(false);
explain.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
updateTopPane(true);
}
});
String objectiveText = addTopGameFeatures(clear);
p.add(clear);
p.add(explain);
p.add(sp);
p.setBorder(BorderFactory.createTitledBorder("Objective: "+objectiveText));
p.setMaximumSize(new Dimension(MAX_SIZE.width, MAX_SIZE.height/10));
p.setPreferredSize(new Dimension(MAX_SIZE.width, MAX_SIZE.height/10));
return p;
}
/**
* Initializes and returns the m stage and its JPanel.
*
* @return the initialized m JPanel
*/
private JPanel initM()
{
JPanel p = new JPanel(new BorderLayout());
String message = addMGameFeatures();
JPanel q = new JPanel(new BorderLayout());
q.add(myMDisplay, BorderLayout.NORTH);
q.setBorder(BorderFactory.createTitledBorder("1. " + message));
q.add(stageMessages[1], BorderLayout.SOUTH);
p.add(q, BorderLayout.CENTER);
JPanel s = new JPanel();
s.setLayout(new BoxLayout(s, BoxLayout.X_AXIS));
p.setMaximumSize(new Dimension(MAX_SIZE.width, MAX_SIZE.height/10));
p.setPreferredSize(new Dimension(MAX_SIZE.width, MAX_SIZE.height/10));
return p;
}
/**
* Initializes and returns the w stage and its JPanel.
*
* @return the initialized w JPanel
*/
private JPanel initW()
{
JPanel p = new JPanel(new BorderLayout());
String message = addWGameFeatures();
p.setBorder(BorderFactory.createTitledBorder("2. " + message));
p.add(myWDisplay, BorderLayout.NORTH);
p.add(stageMessages[2], BorderLayout.SOUTH);
p.setMaximumSize(new Dimension(MAX_SIZE.width, MAX_SIZE.height/10));
p.setPreferredSize(new Dimension(MAX_SIZE.width, MAX_SIZE.height/10));
return p;
}
/**
* Initializes and returns the decomposition stage and its JPanel. Specified by
* subclasses.
*
* @return the initialized decomposition JPanel
*/
protected abstract JPanel initDecompPanel();
/**
* Initializes and returns the i stage and its JPanel.
*
* @return the initialized i JPanel
*/
private JPanel initI()
{
JPanel o = new JPanel(new BorderLayout());
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
p.add(new JLabel("i: "));
String message = addIGameFeatures();
p.add(myIDisplay);
p.add(new JLabel(" pumped string: "));
myPumpedStringDisplay = new JTextArea(1, 30);
myPumpedStringDisplay.setEditable(false);
p.add(myPumpedStringDisplay);
o.setBorder(BorderFactory.createTitledBorder("4. " + message));
o.add(p, BorderLayout.NORTH);
o.add(p.add(stageMessages[4]), BorderLayout.SOUTH);
o.setMaximumSize(new Dimension(MAX_SIZE.width, MAX_SIZE.height/10));
o.setPreferredSize(new Dimension(MAX_SIZE.width, MAX_SIZE.height/10));
return o;
}
/**
* Initializes and returns the animation canvas.
*
* @return the animation canvas
*/
private JPanel initCanvas()
{
JPanel p = new JPanel(new BorderLayout());
myCanvas = new Canvas();
p.add(myCanvas, BorderLayout.CENTER);
myLastWord = new JEditorPane("text/html", "");
myLastWord.setBackground(this.getBackground());
myLastWord.setDisabledTextColor(Color.BLACK);
myLastWord.setEnabled(false);
JPanel q = new JPanel();
q.setLayout(new BoxLayout(q, BoxLayout.X_AXIS));
q.add(myLastWord);
myStepAnimation = new JButton("Step");
myStepAnimation.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
stepAnimation();
myCanvas.start();
}
});
myStepAnimation.setEnabled(false);
q.add(myStepAnimation);
myCanvas.setStepButton(myStepAnimation);
myStartAnimation = new JButton("Restart");
myStartAnimation.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
setCanvas();
myCanvas.stop();
repaint();
}
});
myStartAnimation.setEnabled(false);
q.add(myStartAnimation);
myCanvas.setRestartButton(myStartAnimation);
p.add(stageMessages[5], BorderLayout.NORTH);
p.add(q, BorderLayout.SOUTH);
p.setBorder(BorderFactory.createTitledBorder("5. Animation"));
p.setMaximumSize(new Dimension(MAX_SIZE.width, 35*MAX_SIZE.height/100));
p.setPreferredSize(new Dimension(MAX_SIZE.width, 35*MAX_SIZE.height/100));
return p;
}
/**
* This method sets the visibility of the parameter stage and all
* stages after it to the given value.
*
* @param minStage the minimum stage whose visibility will be the given value.
* @param visibility whether or not the stages will be visible.
*/
protected void setVisibilityStages(int minStage, boolean visibility)
{
for (int i=minStage; i 0)
output = output + "" + stageMessages[0].getText() +"
";
for (int i=myLemma.getAttempts().size()-1; i>=0; i--) {
a = (String) myLemma.getAttempts().get(i);
s = s + "
" + (i+1) + ": " + a;
}
if (printExplanation) {
String result;
if (myLemma.getPartitionValidity())
result = "A valid partition of w exists!
";
else
result = "Unfortunately no valid partition of w exists.
";
if (myLemma.getAttempts().size() > 0)
output = output + result + myLemma.getExplanation() + "
";
else
output = output + result + myLemma.getExplanation();
}
if (myLemma.getAttempts().size() > 0)
output = output + s;
output = output + "