001: // This file is part of KeY - Integrated Deductive Software Design
002: // Copyright (C) 2001-2007 Universitaet Karlsruhe, Germany
003: // Universitaet Koblenz-Landau, Germany
004: // Chalmers University of Technology, Sweden
005: //
006: // The KeY system is protected by the GNU General Public License.
007: // See LICENSE.TXT for details.
008: //
009: // This file is part of KeY - Integrated Deductive Software Design
010: // Copyright (C) 2001-2004 Universitaet Karlsruhe, Germany
011: // Universitaet Koblenz-Landau, Germany
012: // Chalmers University of Technology, Sweden
013: //
014: // The KeY system is protected by the GNU General Public License.
015: // See LICENSE.TXT for details.
016: package de.uka.ilkd.key.gui.assistant;
017:
018: import java.awt.*;
019: import java.awt.event.WindowListener;
020: import java.awt.geom.Arc2D;
021: import java.awt.geom.Area;
022: import java.awt.geom.RoundRectangle2D;
023:
024: import javax.swing.*;
025:
026: import de.uka.ilkd.key.gui.IconFactory;
027:
028: /**
029: * This class implements the user interface of the proof assistant.
030: */
031: public class ProofAssistant extends JPanel {
032:
033: /** The background color of the bubble */
034: private Color BACKGROUND_COLOR = new Color(1.0f, 1.0f, 0.8f);
035:
036: /** The amount of space around the bubble at top, left and right. */
037: private int BORDER_WIDTH = 15;
038: /** The rounding radius for the corners of the bubble. */
039: private int ROUND_RADIUS = 15;
040: /** The space between the bottom of the bubble and the bottom of
041: * the window. */
042: private int BOTTOM_HEIGHT = 80;
043:
044: /** The height of the Kiki image. */
045: private int KIKI_HEIGHT = 60;
046: /** The distance of Kiki's `mouth' from the top of the Kiki image. */
047: private int KIKI_MOUTH_DESCENT = (int) (0.42 * KIKI_HEIGHT);
048:
049: /** An image of our friendly proof assistant */
050: private Image KIKI_IMAGE = IconFactory.keyAssistant(KIKI_HEIGHT,
051: KIKI_HEIGHT).getImage();
052:
053: private JTextPane textPane;
054: private JFrame frame;
055:
056: private static final String PREFIX = "<html><body style=\"font-family:"
057: + "'Times New Roman',Times,sans serif;font-size: 12pt;\">";
058:
059: private static final String POSTFIX = "</body></html>";
060:
061: /**
062: * creates the assistant user interface
063: */
064: public ProofAssistant() {
065: layoutAssistant();
066:
067: setText("Hi!<br>I am <strong>KiKi</strong> your "
068: + "personal proof assistant. <br> You "
069: + "can disable me in the <tt>Options</tt> menu.");
070:
071: // create the frame
072: frame = new JFrame("Proof Assistant");
073: frame.getContentPane().add(this );
074: frame
075: .setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
076: frame.pack();
077: frame.setVisible(false);
078: }
079:
080: /**
081: * creates the layout for the proof assistant
082: */
083:
084: private void layoutAssistant() {
085: // These borders separate the scroll view from the window borders.
086: int border = ROUND_RADIUS + BORDER_WIDTH;
087: int bottom = ROUND_RADIUS + BOTTOM_HEIGHT;
088: setBorder(new javax.swing.border.EmptyBorder(border, border,
089: bottom, border));
090:
091: BorderLayout layout = new BorderLayout();
092: setLayout(layout);
093: setBackground(Color.white);
094:
095: textPane = new JTextPane();
096: textPane.setBackground(BACKGROUND_COLOR);
097: textPane.setContentType("text/html");
098: textPane.setEditable(false);
099:
100: Dimension dim = new Dimension(200, 120);
101: JScrollPane scroll = new JScrollPane(textPane,
102: JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
103: JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
104: scroll.setPreferredSize(dim);
105: // The ScrollPane usually has a one pixel border, which we don't want.
106: scroll
107: .setBorder(new javax.swing.border.EmptyBorder(0, 0, 0,
108: 0));
109:
110: add(scroll, BorderLayout.CENTER);
111: }
112:
113: /** Paint the custom background for our component.
114: * This consists of the rounded speech bubble and the Kiki image.
115: */
116:
117: public void paintComponent(Graphics g) {
118: // Paint the background white
119: super .paintComponent(g);
120:
121: // Make a copy of the Graphics2D, so we can liberally change colors
122: Graphics2D g2 = (Graphics2D) (g.create());
123:
124: Shape bubble = bubbleShape();
125:
126: g2.setColor(BACKGROUND_COLOR);
127: g2.fill(bubble);
128: g2.setColor(Color.black);
129: g2.draw(bubble);
130:
131: // Draw the Kiki image, centered between the lower end of
132: // the rounded box and the bottom of the window, and with the
133: // right edge at the middle of the windows width.
134: g2.drawImage(KIKI_IMAGE, getWidth() / 2 - KIKI_HEIGHT,
135: getHeight() - BOTTOM_HEIGHT
136: + (BOTTOM_HEIGHT - KIKI_HEIGHT) / 2, null);
137: }
138:
139: /** Return the shape of the bubble, depending on window size. The
140: * bubble consists of a top part in th form of a rounded
141: * rectangle and a spike coming out on the lower side.
142: */
143: private Shape bubbleShape() {
144: // The upper part
145: Shape rbox = new RoundRectangle2D.Double(BORDER_WIDTH,
146: BORDER_WIDTH, getWidth() - 2 * BORDER_WIDTH,
147: getHeight() - BOTTOM_HEIGHT - BORDER_WIDTH,
148: ROUND_RADIUS, ROUND_RADIUS);
149:
150: // The spike is the difference of two elliptical arcs,
151: // centered on the middle of the lower edge of the rounded box.
152:
153: int arcHeight = (BOTTOM_HEIGHT - KIKI_HEIGHT) + 2
154: * KIKI_MOUTH_DESCENT;
155: int bigArcWidth = arcHeight;
156:
157: // We make sure that the right arc of the spike doesn't
158: // interfere with the rounding of the box.
159: if (bigArcWidth > getWidth() - 2 * BORDER_WIDTH - 2
160: * ROUND_RADIUS) {
161: bigArcWidth = getWidth() - 2 * BORDER_WIDTH - 2
162: * ROUND_RADIUS;
163: }
164: int smallArcWidth = (int) (0.46 * bigArcWidth);
165:
166: // We take the whole ellipse for the smaller arc, to be
167: // sure that we erase enough from the larger one.
168: Shape smallArc = new Arc2D.Double(getWidth() / 2
169: - smallArcWidth / 2, getHeight() - BOTTOM_HEIGHT
170: - arcHeight / 2, smallArcWidth, arcHeight, 0, 360,
171: Arc2D.CHORD);
172:
173: Shape bigArc = new Arc2D.Double(getWidth() / 2 - bigArcWidth
174: / 2, getHeight() - BOTTOM_HEIGHT - arcHeight / 2,
175: bigArcWidth, arcHeight, -90, 180, Arc2D.CHORD);
176:
177: Area bubble = new Area(bigArc);
178: bubble.subtract(new Area(smallArc));
179: bubble.add(new Area(rbox));
180:
181: return bubble;
182: }
183:
184: public int getWidth() {
185: return frame.getWidth();
186: }
187:
188: public void setLocation(int x, int y) {
189: frame.setLocation(x, y);
190: }
191:
192: public void tearUp() {
193: frame.setVisible(true);
194: frame.setState(Frame.NORMAL);
195: frame.toFront();
196: }
197:
198: public void tearDown() {
199: frame.setVisible(false);
200: }
201:
202: /**
203: * adds the listener to the window listeners
204: */
205: public void addWindowListener(WindowListener l) {
206: frame.addWindowListener(l);
207: }
208:
209: /**
210: * removes the listener from the window listeners
211: */
212: public void removeWindowListener(WindowListener l) {
213: frame.removeWindowListener(l);
214: }
215:
216: /**
217: * sets the text tip to be shown
218: * @param text the String to be displayed
219: */
220: public void setText(String text) {
221: textPane.setText(PREFIX + text + POSTFIX);
222: textPane.setCaretPosition(0);
223: }
224:
225: public static void main(String[] ags) {
226: new ProofAssistant();
227: }
228: }
|