import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.undo.*;
import javax.swing.event.*;

import Composants.*;
public class FireSupportApp {
		public static void main(String[] args) {
				JFrame f = new JFrame("Undo/Redo Demo");
				f.addWindowListener(new Fermeur());
				f.setContentPane(new FireUndo());
				f.setSize(400,300);
				f.setVisible(true);
		}
}

class FireUndo extends JPanel {
  protected Vector formes = new Vector();
  protected PaintCanvas canvas = new PaintCanvas(formes);
  protected UndoManager manager = new UndoManager();
  protected JButton undoButton = new JButton("Undo");
  protected JButton redoButton = new JButton("Redo");

  public FireUndo() { 
    undoButton.setEnabled(false);
    redoButton.setEnabled(false);
    JPanel buttonPanel = new JPanel(new GridLayout());
    buttonPanel.add(undoButton);
    buttonPanel.add(redoButton);
		setLayout(new BorderLayout());
    add(buttonPanel, BorderLayout.NORTH);
    add(canvas, BorderLayout.CENTER);

    canvas.addMouseListener(new AjouterForme());
    undoButton.addActionListener(new UndoIt());
    redoButton.addActionListener(new RedoIt());
    canvas.addUndoableEditListener(manager); 
  }
	class AjouterForme extends MouseAdapter {
	  protected int width = 50; 
    protected int height = 50;

    public void mousePressed(MouseEvent e) {
      Shape shape;
			UndoableEdit edit;
			if (e.isShiftDown()) {
				shape = new Ellipse2D.Double(e.getX(), e.getY(), width, height);
				edit = new CercleEdit(shape, formes);
			}
			else {
				shape = new Rectangle2D.Double(e.getX(), e.getY(), width, height);
				edit = new CarreEdit(shape, formes);
			}
			formes.addElement(shape);
			canvas.postEdit(edit);			
			canvas.repaint();
			updateButtons();
		}
	}	
	class UndoIt implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      try { manager.undo(); }
			catch (CannotRedoException cre) { cre.printStackTrace(); }
			canvas.repaint();
			updateButtons();
		}
	}
	class RedoIt implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      try { manager.redo(); }
			catch (CannotRedoException cre) { cre.printStackTrace(); }
			canvas.repaint();
			updateButtons();
		}
	}
	private void updateButtons() {
    undoButton.setText(manager.getUndoPresentationName());
		redoButton.setText(manager.getRedoPresentationName());
		undoButton.setEnabled(manager.canUndo());
		redoButton.setEnabled(manager.canRedo());
	}
}

class PaintCanvas extends JPanel
{
  Vector formes;
	UndoableEditSupport support = new UndoableEditSupport();

  public PaintCanvas(Vector formes) {
    super();
    this.formes = formes;
    setOpaque(true);
    setBackground(Color.white);
  }

  public void paintComponent(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
    super.paintComponent(g2);
    g2.setColor(Color.black);
    Enumeration enum = formes.elements();
    while(enum.hasMoreElements()) {
      Shape shape = (Shape) enum.nextElement();
      g2.draw(shape);
    }
  }
	public void addUndoableEditListener(UndoableEditListener listener) {
	  support.addUndoableEditListener(listener);
	}

  public void removeUndoableEditListener(UndoableEditListener listener) {
	  support.removeUndoableEditListener(listener);
  }

  public void postEdit(UndoableEdit e) {
		support.postEdit(e);
	}
}

class FormeEdit extends AbstractUndoableEdit  {
  protected Vector formes;
  protected Shape shape;

  public FormeEdit(Shape shape, Vector formes) {
    this.formes = formes;
    this.shape = shape;
  }   
  public void undo() {
    super.undo();
    formes.remove(shape);
  }

  public void redo() {
    super.redo();
    formes.add(shape);
  }
}

class CarreEdit extends FormeEdit {
	public CarreEdit(Shape shape, Vector formes) {
	  super(shape, formes);
	}
  public String getPresentationName() {
    return "carré";
  }
}

class CercleEdit extends FormeEdit {
	public CercleEdit(Shape shape, Vector formes) {
	  super(shape, formes);
	}
  public String getPresentationName() {
    return "cercle";
  }
}
