package open.dolphin.impl.schema; import java.awt.*; import java.awt.event.*; import java.awt.font.FontRenderContext; import java.awt.font.TextLayout; import java.awt.geom.*; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import javax.swing.*; import open.dolphin.client.AutoKanjiListener; import open.dolphin.client.ClientContext; import open.dolphin.client.SchemaEditor; import open.dolphin.infomodel.ExtRefModel; import open.dolphin.infomodel.SchemaModel; import open.dolphin.project.Project; /** * * @author Kazushi Minagawa. */ public class SchemaEditorImpl implements SchemaEditor { private static final float DEFAULT_LINE_WIDTH = 4.0f; private static final Color DEFAULT_FILL_COLOR = Color.RED; private static final float DEFAULT_ALPHA = 0.5f; private static final int DEFAULT_TEXT_SIZE = 24; private static final String DEFAULT_FONT_NAME = "Dialog"; private static final String TITLE = java.util.ResourceBundle.getBundle("open/dolphin/impl/schema/resources/SchemaEditorImpl").getString("title.schemaEditor"); private static final String DEFAULT_ROLE = java.util.ResourceBundle.getBundle("open/dolphin/impl/schema/resources/SchemaEditorImpl").getString("defaultRole.refFig"); private static final String DEFAULT_TITLE = java.util.ResourceBundle.getBundle("open/dolphin/impl/schema/resources/SchemaEditorImpl").getString("defaultTitle.refImage"); private SchemaModel model; protected Image srcImage; private Insets margin; protected ArrayList<DrawingHolder> drawingList; private float lineWidth = DEFAULT_LINE_WIDTH; private Color fillColor = DEFAULT_FILL_COLOR; private float alpha = DEFAULT_ALPHA; private String fontName = DEFAULT_FONT_NAME; private int fontStyle = Font.BOLD; private int textSize = DEFAULT_TEXT_SIZE; private boolean outline = false; private SchemaCanvas canvas; private SimpleCanvas view; private JPanel canvasPanel; private StateMgr stateMgr; private boolean editable; private PropertyChangeSupport boundSupport; public SchemaEditorImpl() { } @Override public void setSchema(SchemaModel model) { this.model = model; } @Override public void setEditable(boolean b) { this.editable = b; } @Override public void start() { if (editable) { initComponents(); } else { initComponentsUneditable(); } } private BufferedImage createImage() { BufferedImage result = null; try { int width = srcImage.getWidth(null); int height = srcImage.getHeight(null); width = margin != null ? width + margin.left + margin.right : width; height = margin != null ? height + margin.top + margin.bottom : height; int x = margin != null ? margin.left : 0; int y = margin != null ? margin.top : 0; result = new BufferedImage( width, height, BufferedImage.TYPE_INT_BGR); Graphics2D g2 = result.createGraphics(); Rectangle2D bounds = new Rectangle2D.Double(0, 0, width, height); g2.setPaint(Color.WHITE); g2.fill(bounds); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.drawImage(srcImage, x, y, srcImage.getWidth(null), srcImage.getHeight(null), null); drawingList.stream().forEach((d) -> { d.draw(g2); }); } catch (Exception e) { e.printStackTrace(System.err); } return result; } private void firePropertyChange(BufferedImage image) { if (image != null) { ImageIcon icon = new ImageIcon(image); model.setIcon(icon); String text = view.getTitleFld().getText().trim(); if (text.equals("")) { text = DEFAULT_TITLE; } model.getExtRefModel().setTitle(text); model.getExtRefModel().setMedicalRole((String) view.getRoleCombo().getSelectedItem()); boundSupport.firePropertyChange("imageProp", null, model); } else { boundSupport.firePropertyChange("imageProp", model, null); } } @Override public void addPropertyChangeListener(PropertyChangeListener l) { if (boundSupport == null) { boundSupport = new PropertyChangeSupport(this); } boundSupport.addPropertyChangeListener(l); } @Override public void removePropertyChangeListener(PropertyChangeListener l) { if (boundSupport == null) { boundSupport = new PropertyChangeSupport(this); } boundSupport.removePropertyChangeListener(l); } private void initComponentsUneditable() { srcImage = model.getIcon().getImage(); margin = new Insets(12, 12, 11, 11); canvas = new SchemaCanvas(srcImage, margin); canvas.setController(this); canvas.setBorder(BorderFactory.createEtchedBorder()); view = new SimpleCanvas((Frame) null, ClientContext.getFrameTitle(TITLE), true); canvasPanel = view.getCanvasPanel(); canvasPanel.add(canvas); view.getSelectBtn().setEnabled(false); view.getLineBtn().setEnabled(false); view.getRectBtn().setEnabled(false); view.getOvalBtn().setEnabled(false); view.getOpenPathBtn().setEnabled(false); view.getPolyBtn().setEnabled(false); view.getRectFillBtn().setEnabled(false); view.getOvalFillBtn().setEnabled(false); view.getPolyFillBtn().setEnabled(false); view.getTextBtn().setEnabled(false); JComboBox widthCombo = view.getLineWidthCombo(); Object[] lines = new Object[4]; lines[0] = ShapeIconMaker.createRectFillIcon(Color.BLACK, new Dimension(30, 1)); lines[1] = ShapeIconMaker.createRectFillIcon(Color.BLACK, new Dimension(30, 2)); lines[2] = ShapeIconMaker.createRectFillIcon(Color.BLACK, new Dimension(30, 4)); lines[3] = ShapeIconMaker.createRectFillIcon(Color.BLACK, new Dimension(30, 8)); widthCombo.setModel(new DefaultComboBoxModel(lines)); widthCombo.setEnabled(false); view.getColorBtn().setEnabled(false); view.getUndoBtn().setEnabled(false); view.getClearBtn().setEnabled(false); view.getColorBtn().setIcon(ShapeIconMaker.createRectFillIcon(DEFAULT_FILL_COLOR, new Dimension(32,32))); JTextField titleFld = view.getTitleFld(); titleFld.setEditable(false); view.getRoleCombo().setEnabled(false); ExtRefModel extRef = model.getExtRefModel(); if (extRef != null) { String text = extRef.getTitle(); if (text != null && (!text.equals(""))) { titleFld.setText(text); } text = extRef.getMedicalRole(); if (text != null && (!text.equals(""))) { view.getRoleCombo().setSelectedItem((String) text); } } view.getOkBtn().setEnabled(false); String canceltext = (String) UIManager.get("OptionPane.cancelButtonText"); JButton cancelBtn = view.getCancelBtn(); cancelBtn.setText(canceltext); cancelBtn.addActionListener((ActionEvent e) -> { close(); firePropertyChange(null); }); int height = canvas.getPreferredSize().height + 150; int width = view.getPreferredSize().width; Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); if(dim.width < width) width = dim.width; if(dim.height < height) height = dim.height; int offsetX = (dim.width - width) / 2; int offsetY = (dim.height - height) / 2; view.setBounds(offsetX, offsetY, width, height); view.setVisible(true); } private void initComponents() { float w = Project.getFloat("schemaEditor.lineWidth", DEFAULT_LINE_WIDTH); setLineWidth(w); Color c = Project.getColor("schemaEditor.fillColor", DEFAULT_FILL_COLOR); setFillColor(c); float a = Project.getFloat("schemaEditor.alpha", DEFAULT_ALPHA); setAlpha(a); srcImage = model.getIcon().getImage(); margin = new Insets(12, 12, 11, 11); canvas = new SchemaCanvas(srcImage, margin); canvas.setController(this); canvas.setBorder(BorderFactory.createEtchedBorder()); view = new SimpleCanvas((Frame) null, ClientContext.getFrameTitle(TITLE), true); canvasPanel = view.getCanvasPanel(); canvasPanel.add(canvas); JToggleButton selectBtn = view.getSelectBtn(); JToggleButton lineBtn = view.getLineBtn(); JToggleButton rectBtn = view.getRectBtn(); JToggleButton ellipseBtn = view.getOvalBtn(); JToggleButton openPathBtn = view.getOpenPathBtn(); JToggleButton polygonBtn = view.getPolyBtn(); JToggleButton rectFillBtn = view.getRectFillBtn(); JToggleButton ellipseFillBtn = view.getOvalFillBtn(); JToggleButton polygonFillBtn = view.getPolyFillBtn(); JToggleButton textBtn = view.getTextBtn(); ButtonGroup bg = new ButtonGroup(); bg.add(selectBtn); bg.add(lineBtn); bg.add(rectBtn); bg.add(ellipseBtn); bg.add(openPathBtn); bg.add(polygonBtn); bg.add(rectFillBtn); bg.add(ellipseFillBtn); bg.add(polygonFillBtn); bg.add(textBtn); JComboBox widthCombo = view.getLineWidthCombo(); Object[] lines = new Object[4]; lines[0] = ShapeIconMaker.createRectFillIcon(Color.BLACK, new Dimension(30, 1)); lines[1] = ShapeIconMaker.createRectFillIcon(Color.BLACK, new Dimension(30, 2)); lines[2] = ShapeIconMaker.createRectFillIcon(Color.BLACK, new Dimension(30, 4)); lines[3] = ShapeIconMaker.createRectFillIcon(Color.BLACK, new Dimension(30, 8)); widthCombo.setModel(new DefaultComboBoxModel(lines)); widthCombo.addItemListener((ItemEvent e) -> { if (e.getStateChange() == ItemEvent.SELECTED) { JComboBox cmb = (JComboBox) e.getSource(); int index = cmb.getSelectedIndex(); switch (index) { case 0: setLineWidth(1); break; case 1: setLineWidth(2); break; case 2: setLineWidth(4); break; case 3: setLineWidth(8); break; } } }); float lw = getLineWidth(); if (lw == 1.0f) { widthCombo.setSelectedIndex(0); } else if (lw == 2.0f) { widthCombo.setSelectedIndex(1); } else if (lw == 4.0f) { widthCombo.setSelectedIndex(2); } else if (lw == 8.0f) { widthCombo.setSelectedIndex(3); } else { // never } JButton colorBtn = view.getColorBtn(); JButton undoBtn = view.getUndoBtn(); JButton clearBtn = view.getClearBtn(); colorBtn.setIcon(ShapeIconMaker.createRectFillIcon(getFillColor(), new Dimension(32,32))); canvas.addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { stateMgr.mouseDown(e.getPoint()); } @Override public void mouseReleased(MouseEvent e) { stateMgr.mouseUp(e.getPoint()); } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } }); canvas.addMouseMotionListener(new MouseMotionListener() { @Override public void mouseDragged(MouseEvent e) { stateMgr.mouseDragged(e.getPoint()); } @Override public void mouseMoved(MouseEvent e) { } }); selectBtn.addActionListener((ActionEvent e) -> { stateMgr.startSelect(); }); lineBtn.addActionListener((ActionEvent e) -> { stateMgr.startLine(); }); rectBtn.addActionListener((ActionEvent e) -> { stateMgr.startRect(); }); ellipseBtn.addActionListener((ActionEvent e) -> { stateMgr.startEllipse(); }); openPathBtn.addActionListener((ActionEvent e) -> { stateMgr.startOpenPath(); }); polygonBtn.addActionListener((ActionEvent e) -> { stateMgr.startPolygon(); }); rectFillBtn.addActionListener((ActionEvent e) -> { stateMgr.startRectFill(); }); ellipseFillBtn.addActionListener((ActionEvent e) -> { stateMgr.startEllipseFill(); }); polygonFillBtn.addActionListener((ActionEvent e) -> { stateMgr.startPolygonFill(); }); textBtn.addActionListener((ActionEvent e) -> { stateMgr.startText(); }); colorBtn.addActionListener((ActionEvent e) -> { chooseColor(); }); undoBtn.addActionListener((ActionEvent e) -> { stateMgr.undo(); }); clearBtn.addActionListener((ActionEvent e) -> { stateMgr.clear(); }); JTextField titleFld = view.getTitleFld(); titleFld.setText(DEFAULT_TITLE); titleFld.addFocusListener(AutoKanjiListener.getInstance()); JComboBox roleCombo = view.getRoleCombo(); roleCombo.setSelectedItem(DEFAULT_ROLE); ExtRefModel extRef = model.getExtRefModel(); if (extRef != null) { String text = extRef.getTitle(); if (text != null && (!text.equals(""))) { titleFld.setText(text); } text = extRef.getMedicalRole(); if (text != null && (!text.equals(""))) { roleCombo.setSelectedItem((String) text); } } drawingList = new ArrayList<>(5); stateMgr = new StateMgr(); JButton okBtn = view.getOkBtn(); okBtn.addActionListener((ActionEvent e) -> { close(); firePropertyChange(createImage()); }); String canceltext = (String) UIManager.get("OptionPane.cancelButtonText"); JButton cancelBtn = view.getCancelBtn(); cancelBtn.setText(canceltext); cancelBtn.addActionListener((ActionEvent e) -> { close(); firePropertyChange(null); }); int height = canvas.getPreferredSize().height + 150; int width = view.getPreferredSize().width; Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); int offsetX = (dim.width - width) / 2; int offsetY = (dim.height - height) / 2; view.setBounds(offsetX,offsetY,width, height); view.setVisible(true); rectBtn.doClick(); } private void close() { Project.setFloat("schemaEditor.lineWidth", getLineWidth()); Project.setColor("schemaEditor.fillColor", getFillColor()); Project.setFloat("schemaEditor.alpha", getAlpha()); view.setVisible(false); view.dispose(); } private void chooseColor() { Color newColor = JColorChooser.showDialog(view, ClientContext.getMyBundle(SchemaEditorImpl.class).getString("title.colorChooser.selectColor"), getFillColor()); if (newColor != null) { setFillColor(newColor); ImageIcon icon = ShapeIconMaker.createRectFillIcon(getFillColor(), new Dimension(32, 32)); view.getColorBtn().setIcon(icon); } } public void draw(Graphics2D g2d) { if (stateMgr!= null) { stateMgr.draw(g2d); } } public void addShape(DrawingHolder s) { drawingList.add(s); } public DrawingHolder findDrawing(Point p) { DrawingHolder found = null; int cnt = drawingList.size(); int last = cnt > 0 ? cnt -1 : 0; for (int i = last; i > -1; i--) { DrawingHolder d = drawingList.get(i); if (d.contains(p)) { found = d; break; } } return found; } public void removeLastShape() { if (drawingList.size()>0) { DrawingHolder remove = drawingList.get(drawingList.size()-1); // .lastElement(); drawingList.remove(remove); } } public Stroke getStroke() { return new BasicStroke(getLineWidth()); } public Paint getPaint() { return getFillColor(); } public AlphaComposite getAlphaComposite() { return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha()); } public AlphaComposite getTextComposite() { return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getTextAlpha()); } public Font getFont() { return new Font(getFontName(), getFontStyle(), getTextSize()); } public float getLineWidth() { return lineWidth; } public void setLineWidth(float lineWidth) { this.lineWidth = lineWidth; } public Color getFillColor() { return fillColor; } public void setFillColor(Color fillColor) { this.fillColor = fillColor; } public float getAlpha() { return alpha; } public void setAlpha(float alpha) { this.alpha = alpha; } public int getTextSize() { return textSize; } public void setTextSize(int textSize) { this.textSize = textSize; } public Color getTextColor() { return getFillColor(); } public void setTextColor(Color textColor) { //this.textColor = textColor; } public float getTextAlpha() { return getAlpha(); } public void setTextAlpha(float textAlpha) { //this.textAlpha = textAlpha; } public boolean isOutline() { return outline; } public void setOutline(boolean outline) { this.outline = outline; } public String getFontName() { return fontName; } public void setFontName(String fontName) { this.fontName = fontName; } public int getFontStyle() { return fontStyle; } public void setFontStyle(int fontStyle) { this.fontStyle = fontStyle; } protected abstract class State { protected boolean first; protected Point start; protected Point end; public abstract void mouseDown(Point p); public abstract void mouseDragged(Point p); public abstract void mouseUp(Point p); public void draw(Graphics2D g2d) { } protected boolean isDragged() { if (start == null || end == null) { return false; } int x = Math.abs(start.x - end.x); int y = Math.abs(start.y - end.y); return x > 5 || y > 5; } } class SelectState extends State { private DrawingHolder moving; @Override public void mouseDown(Point p) { moving = findDrawing(p); if (moving != null) { start = p; end = null; } } @Override public void mouseDragged(Point p) { if (moving != null) { end = p; if (isDragged()) { moving.translate(end.getX() - start.getX(), end.getY() - start.getY()); canvas.repaint(); start = end; } } } @Override public void mouseUp(Point p) { } } class RectState extends State { @Override public void mouseDown(Point p) { start = p; end = null; first = true; } @Override public void mouseDragged(Point p) { end = p; if (isDragged()) { createAndAddShape(); canvas.repaint(); } } @Override public void mouseUp(Point p) { } private void createAndAddShape() { Rectangle2D shape = new Rectangle2D.Double(); shape.setFrameFromDiagonal(start, end); if (first) { first = false; } else { removeLastShape(); } AreaHolder sh = new AreaHolder(new Area(shape), getStroke(), getPaint(), getAlphaComposite(), false); addShape(sh); } } class EllipseState extends State { @Override public void mouseDown(Point p) { start = p; end = null; first = true; } @Override public void mouseDragged(Point p) { end = p; if (isDragged()) { createAndAddShape(); canvas.repaint(); } } @Override public void mouseUp(Point p) { } private void createAndAddShape() { Ellipse2D shape = new Ellipse2D.Double(); shape.setFrameFromDiagonal(start, end); if (first) { first = false; } else { removeLastShape(); } AreaHolder sh = new AreaHolder(new Area(shape), getStroke(), getPaint(), getAlphaComposite(), false); addShape(sh); } } class PolygonState extends State { private GeneralPath gpath; @Override public void mouseDown(Point p) { start = p; end = null; first = true; gpath = null; } @Override public void mouseDragged(Point p) { end = p; if (isDragged()) { if (first) { gpath = new GeneralPath(); gpath.moveTo(start.x, start.y); gpath.lineTo(end.x, end.y); first = false; } else { gpath.lineTo(end.x, end.y); } canvas.repaint(); start = end; } } @Override public void mouseUp(Point p) { end = p; if (gpath != null) { gpath.closePath(); canvas.repaint(); AreaHolder sh = new AreaHolder(new Area(gpath), getStroke(), getPaint(), getAlphaComposite(), false); addShape(sh); } gpath = null; } @Override public void draw(Graphics2D g2d) { if (gpath == null) { return; } Stroke saveStroke = g2d.getStroke(); Paint savePaint = g2d.getPaint(); Composite saveComposite = g2d.getComposite(); g2d.setStroke(getStroke()); g2d.setComposite(getAlphaComposite()); g2d.setPaint(getPaint()); g2d.draw(gpath); g2d.setStroke(saveStroke); g2d.setPaint(savePaint); g2d.setComposite(saveComposite); } } class OpenPathState extends State { private GeneralPath gpath; @Override public void mouseDown(Point p) { start = p; end = null; first = true; gpath = null; } @Override public void mouseDragged(Point p) { end = p; if (isDragged()) { if (first) { gpath = new GeneralPath(); gpath.moveTo(start.x, start.y); gpath.lineTo(end.x, end.y); first = false; } else { gpath.lineTo(end.x, end.y); } canvas.repaint(); start = end; } } @Override public void mouseUp(Point p) { end = p; if (gpath != null) { //gpath.closePath(); canvas.repaint(); //AreaHolder sh = new AreaHolder(new Area(gpath), getStroke(), getPaint(), getAlphaComposite(), false); OpenPathHolder sh = new OpenPathHolder(gpath, getStroke(), getPaint(), getAlphaComposite(), false); addShape(sh); } gpath = null; } @Override public void draw(Graphics2D g2d) { if (gpath == null) { return; } Stroke saveStroke = g2d.getStroke(); Paint savePaint = g2d.getPaint(); Composite saveComposite = g2d.getComposite(); g2d.setStroke(getStroke()); g2d.setComposite(getAlphaComposite()); g2d.setPaint(getPaint()); g2d.draw(gpath); g2d.setStroke(saveStroke); g2d.setPaint(savePaint); g2d.setComposite(saveComposite); } } class RectFillState extends State { @Override public void mouseDown(Point p) { start = p; end = null; first = true; } @Override public void mouseDragged(Point p) { end = p; if (isDragged()) { createAndAddShape(); canvas.repaint(); } } @Override public void mouseUp(Point p) { } private void createAndAddShape() { Rectangle2D shape = new Rectangle2D.Double(); shape.setFrameFromDiagonal(start, end); if (first) { first = false; } else { removeLastShape(); } AreaHolder sh = new AreaHolder(new Area(shape), null, getPaint(), getAlphaComposite(), true); addShape(sh); } } class EllipseFillState extends State { @Override public void mouseDown(Point p) { start = p; end = null; first = true; } @Override public void mouseDragged(Point p) { end = p; if (isDragged()) { createAndAddShape(); canvas.repaint(); } } @Override public void mouseUp(Point p) { } private void createAndAddShape() { Ellipse2D shape = new Ellipse2D.Double(); shape.setFrameFromDiagonal(start, end); if (first) { first = false; } else { removeLastShape(); } AreaHolder sh = new AreaHolder(new Area(shape), null, getPaint(), getAlphaComposite(), true); addShape(sh); } } class PolygonFillState extends State { private GeneralPath gpath; private boolean closed; @Override public void mouseDown(Point p) { start = p; end = null; first = true; gpath = null; closed = false; } @Override public void mouseDragged(Point p) { end = p; if (isDragged()) { if (first) { gpath = new GeneralPath(); gpath.moveTo(start.x, start.y); gpath.lineTo(end.x, end.y); first = false; } else { gpath.lineTo(end.x, end.y); } canvas.repaint(); start = end; } } @Override public void mouseUp(Point p) { end = p; if (gpath != null) { gpath.closePath(); closed = true; canvas.repaint(); AreaHolder sh = new AreaHolder(new Area(gpath), null, getPaint(), getAlphaComposite(), true); addShape(sh); } gpath = null; } @Override public void draw(Graphics2D g2d) { if (gpath == null) { return; } Stroke saveStroke = g2d.getStroke(); Paint savePaint = g2d.getPaint(); Composite saveComposite = g2d.getComposite(); g2d.setComposite(getAlphaComposite()); g2d.setPaint(getPaint()); if (closed) { g2d.fill(gpath); } else { g2d.setStroke(getStroke()); g2d.draw(gpath); } g2d.setStroke(saveStroke); g2d.setPaint(savePaint); g2d.setComposite(saveComposite); } } class LineState extends State { @Override public void mouseDown(Point p) { start = p; end = null; first = true; } @Override public void mouseDragged(Point p) { end = p; if (isDragged()) { Line2D.Double shape = getShape(); if (shape != null) { if (first) { first = false; } else { removeLastShape(); } Line2DHolder sh = new Line2DHolder(shape, getStroke(), getPaint(), getAlphaComposite()); addShape(sh); canvas.repaint(); } } } @Override public void mouseUp(Point p) { } private Line2D.Double getShape() { return new Line2D.Double(start.getX(), start.getY(), end.getX(), end.getY()); } } class TextState extends State { private String inputText; @Override public void mouseDown(Point p) { inputText = JOptionPane.showInputDialog(view, ClientContext.getMyBundle(SchemaEditorImpl.class).getString("inputText.inputDialog")); if (inputText != null) { start = p; end = null; canvas.repaint(); } else { start = null; end = null; } } @Override public void mouseDragged(Point p) { } @Override public void mouseUp(Point p) { } @Override public void draw(Graphics2D g2d) { if (inputText != null && start != null) { Stroke saveStroke = g2d.getStroke(); Paint savePaint = g2d.getPaint(); Composite saveComposite = g2d.getComposite(); FontRenderContext ctx = g2d.getFontRenderContext(); Font f = getFont(); TextLayout layout = new TextLayout(inputText, f, ctx); AffineTransform trans = AffineTransform.getTranslateInstance(start.getX(), start.getY()); Shape outLine = layout.getOutline(trans); g2d.setPaint(getTextColor()); if (isOutline()) { g2d.draw(outLine); } else { g2d.fill(outLine); } g2d.setStroke(saveStroke); g2d.setPaint(savePaint); g2d.setComposite(saveComposite); AreaHolder sh = new TextHolder(new Area(outLine), null, getTextColor(), getTextComposite(), !isOutline()); addShape(sh); inputText = null; } } } class UndoState extends State { @Override public void mouseDown(Point p) { } @Override public void mouseDragged(Point p) { } @Override public void mouseUp(Point p) { } @Override public void draw(Graphics2D g2d) { } } class StateMgr { private final State selectState; private final State lineState; private final State rectState; private final State ellipseState; private final State openPathState; private final State polygonState; private State rectFillState; private final State ellipseFillState; private final State polygonFillState; private final State textState; private final State undoState; private State curState = rectFillState; private State savedState; public StateMgr() { selectState = new SelectState(); lineState = new LineState(); rectState = new RectState(); ellipseState = new EllipseState(); openPathState = new OpenPathState(); polygonState = new PolygonState(); rectFillState = new RectFillState(); ellipseFillState = new EllipseFillState(); polygonFillState = new PolygonFillState(); textState = new TextState(); undoState = new UndoState(); curState = rectFillState; } public void startSelect() { curState = selectState; } public void startLine() { curState = lineState; } public void startRect() { curState = rectState; } public void startEllipse() { curState = ellipseState; } public void startOpenPath() { curState = openPathState; } public void startPolygon() { curState = polygonState; } public void startRectFill() { curState = rectFillState; } public void startEllipseFill() { curState = ellipseFillState; } public void startPolygonFill() { curState = polygonFillState; } public void startText() { curState = textState; } public void mouseDown(Point p) { curState.mouseDown(p); } public void mouseDragged(Point p) { curState.mouseDragged(p); } public void mouseUp(Point p) { curState.mouseUp(p); } public void draw(Graphics2D g2d) { for (DrawingHolder d : drawingList) { d.draw(g2d); } if (curState == undoState) { curState = savedState; } else { curState.draw(g2d); } } public void undo() { if (drawingList!=null && drawingList.size()>0) { int len = drawingList.size(); DrawingHolder d = drawingList.get(len-1); //.lastElement(); drawingList.remove(d); savedState = curState; curState = undoState; canvas.repaint(); } } public void clear() { drawingList.clear(); savedState = curState; curState = undoState; canvas.repaint(); } } }