Memento pattern in Java
/* The Design Patterns Java Companion Copyright (C) 1998, by James W. Cooper IBM Thomas J. Watson Research Center */ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Vector; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JToggleButton; import javax.swing.JToolBar; public class MemDraw extends JFrame implements ActionListener { JToolBar tbar; Mediator med; public MemDraw() { super("Memento Drawing"); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); JPanel jp = new JPanel(); getContentPane().add(jp); med = new Mediator(); jp.setLayout(new BorderLayout()); tbar = new JToolBar(); jp.add("North", tbar); RectButton rect = new RectButton(this, med); tbar.add(rect); UndoButton undo = new UndoButton(this, med); tbar.add(undo); tbar.addSeparator(); ClearButton clr = new ClearButton(this, med); tbar.add(clr); JCanvas canvas = new JCanvas(med); jp.add("Center", canvas); MouseApp map = new MouseApp(med); canvas.addMouseListener(map); MouseMoveApp mvap = new MouseMoveApp(med); canvas.addMouseMotionListener(mvap); setSize(new Dimension(400, 300)); setVisible(true); } public void actionPerformed(ActionEvent e) { Command comd = (Command) e.getSource(); comd.Execute(); } static public void main(String[] argv) { new MemDraw(); } } //============================== class MouseApp extends MouseAdapter { Mediator med; public MouseApp(Mediator md) { super(); med = md; } public void mousePressed(MouseEvent e) { med.createRect(e.getX(), e.getY()); } public void mouseReleased(MouseEvent e) { med.rememberPosition(); } } class MouseMoveApp extends MouseMotionAdapter { Mediator med; public MouseMoveApp(Mediator md) { super(); med = md; } public void mouseDragged(MouseEvent e) { med.drag(e.getX(), e.getY()); } } class ClearButton extends JButton implements Command { Mediator med; public ClearButton(ActionListener act, Mediator md) { super("C"); setToolTipText("Clear"); addActionListener(act); med = md; } public void Execute() { med.clear(); } } class JCanvas extends JPanel { Mediator med; public JCanvas(Mediator md) { med = md; med.registerCanvas(this); setBackground(Color.white); } public void paint(Graphics g) { super.paint(g); med.reDraw(g); } } class Mediator { boolean startRect; boolean rectSelected; Vector drawings; Vector undoList; RectButton rect; JPanel canvas; visRectangle selectedRectangle; public Mediator() { startRect = false; rectSelected = false; drawings = new Vector(); undoList = new Vector(); } public void startRectangle() { startRect = true; } public void createRect(int x, int y) { unpick(); //make sure no rectangle is selected if (startRect) //if rect button is depressed { Integer count = new Integer(drawings.size()); undoList.addElement(count); //Save previous drawing list size visRectangle v = new visRectangle(x, y); drawings.addElement(v); //add new element to list startRect = false; //done with this rectangle rect.setSelected(false); //unclick button canvas.repaint(); } else pickRect(x, y); //if not pressed look for rect to select } public void registerRectButton(RectButton rb) { rect = rb; } public void registerCanvas(JPanel p) { canvas = p; } private void unpick() { rectSelected = false; if (selectedRectangle != null) { selectedRectangle.setSelected(false); selectedRectangle = null; repaint(); } } public void rememberPosition() { if (rectSelected) { Memento m = new Memento(selectedRectangle); undoList.addElement(m); } } public void pickRect(int x, int y) { //save current selected rectangle to avoid double save of undo visRectangle lastPick = selectedRectangle; unpick(); for (int i = 0; i < drawings.size(); i++) { visRectangle v = (visRectangle) drawings.elementAt(i); if (v.contains(x, y)) //did click inside a rectangle { selectedRectangle = v; //save it rectSelected = true; if (selectedRectangle != lastPick) //but don't save twice rememberPosition(); v.setSelected(true); //turn on handles repaint(); //and redraw } } } public void clear() { drawings = new Vector(); undoList = new Vector(); rectSelected = false; selectedRectangle = null; repaint(); } private void repaint() { canvas.repaint(); } public void drag(int x, int y) { if (rectSelected) { if (selectedRectangle.contains(x, y)) { selectedRectangle.move(x, y); repaint(); } } } public void reDraw(Graphics g) { g.setColor(Color.black); for (int i = 0; i < drawings.size(); i++) { visRectangle v = (visRectangle) drawings.elementAt(i); v.draw(g); } } public void undo() { if (undoList.size() > 0) { //get last element in undo list Object obj = undoList.lastElement(); undoList.removeElement(obj); //and remove it //if this is an Integer, the last action was a new rectangle if (obj instanceof Integer) { //remove last created rectangle Object drawObj = drawings.lastElement(); drawings.removeElement(drawObj); } //if this is a Memento, the last action was a move if (obj instanceof Memento) { //get the Memento Memento m = (Memento) obj; m.restore(); //and restore the old position } repaint(); } } } interface Command { public void Execute(); } class RectButton extends JToggleButton implements Command { Mediator med; public RectButton(ActionListener act, Mediator md) { super("R"); //setSize(new Dimension(25,25)); //setBorder(new EmptyBorder(5,5,5,5)); setToolTipText("Draw rectangle"); addActionListener(act); med = md; med.registerRectButton(this); } public void Execute() { if (isSelected()) { med.startRectangle(); } } } class UndoButton extends JButton implements Command { Mediator med; public UndoButton(ActionListener act, Mediator md) { super("U"); //setSize(new Dimension(25,25)); //setBorder(new EmptyBorder(5,5,5,5)); setToolTipText("Undo"); addActionListener(act); med = md; } public void Execute() { med.undo(); } } class visRectangle { int x, y, w, h; Rectangle rect; boolean selected; public visRectangle(int xpt, int ypt) { x = xpt; y = ypt; w = 40; h = 30; saveAsRect(); } public void setSelected(boolean b) { selected = b; } private void saveAsRect() { rect = new Rectangle(x - w / 2, y - h / 2, w, h); } public void draw(Graphics g) { g.drawRect(x, y, w, h); if (selected) { g.fillRect(x + w / 2, y - 2, 4, 4); g.fillRect(x - 2, y + h / 2, 4, 4); g.fillRect(x + w / 2, y + h - 2, 4, 4); g.fillRect(x + w - 2, y + h / 2, 4, 4); } } public boolean contains(int x, int y) { return rect.contains(x, y); } public void move(int xpt, int ypt) { x = xpt; y = ypt; saveAsRect(); } } //=============================================== class Memento { visRectangle rect; //saved fields- remember internal fields //of the specified visual rectangle int x, y, w, h; public Memento(visRectangle r) { rect = r; x = rect.x; y = rect.y; w = rect.w; h = rect.h; } public void restore() { //restore the internal state of //the specified rectangle rect.x = x; rect.y = y; rect.h = h; rect.w = w; } }
1. | Memento Pattern 2 |