001 /*
002 * Copyright 2002 - 2007 JEuclid, http://jeuclid.sf.net
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 /* $Id: MathComponentUI.java 442 2007-08-21 12:47:57Z maxberger $ */
018
019 package net.sourceforge.jeuclid.swing;
020
021 import java.awt.Color;
022 import java.awt.Dimension;
023 import java.awt.Graphics;
024 import java.awt.Graphics2D;
025 import java.awt.Insets;
026 import java.awt.Point;
027 import java.awt.geom.Point2D;
028 import java.beans.PropertyChangeEvent;
029 import java.beans.PropertyChangeListener;
030 import java.util.Map;
031
032 import javax.swing.JComponent;
033 import javax.swing.LookAndFeel;
034 import javax.swing.SwingConstants;
035 import javax.swing.border.Border;
036 import javax.swing.plaf.ComponentUI;
037
038 import net.sourceforge.jeuclid.DOMBuilder;
039 import net.sourceforge.jeuclid.Defense;
040 import net.sourceforge.jeuclid.MathBase;
041 import net.sourceforge.jeuclid.ParameterKey;
042
043 import org.apache.commons.logging.Log;
044 import org.apache.commons.logging.LogFactory;
045 import org.w3c.dom.Document;
046
047 /**
048 * See
049 * http://today.java.net/pub/a/today/2007/02/22/how-to-write-custom-swing-component.html
050 * for details.
051 *
052 * @author putrycze
053 * @version $Revision: 442 $
054 *
055 */
056 public class MathComponentUI extends ComponentUI implements
057 PropertyChangeListener {
058
059 /**
060 * Logger for this class
061 */
062 private static final Log LOGGER = LogFactory
063 .getLog(MathComponentUI.class);
064
065 private JMathComponent mathComponent;
066
067 /**
068 * Reference to the MathBase class.
069 */
070 private MathBase base;
071
072 /**
073 * Creates a new UI.
074 *
075 */
076 public MathComponentUI() {
077 // nothing to do
078 }
079
080 /** {@inheritDoc} */
081 @Override
082 public void paint(final Graphics g, final JComponent c) {
083 final Graphics2D g2 = (Graphics2D) g;
084 final Dimension dim = new Dimension(this.mathComponent.getWidth(),
085 this.mathComponent.getHeight());
086 final Point start = this
087 .getStartPointWithBordersAndAdjustDimension(dim);
088 this.paintBackground(g, dim, start);
089 if (this.base != null) {
090 final Point2D alignOffset = this.calucateAlignmentOffset(g2, dim);
091 this.base.paint((Graphics2D) g, (float) alignOffset.getX()
092 + start.x, (float) alignOffset.getY() + start.y);
093 }
094
095 }
096
097 private Point2D calucateAlignmentOffset(final Graphics2D g2,
098 final Dimension dim) {
099 final float xo;
100 if ((this.mathComponent.getHorizontalAlignment() == SwingConstants.LEADING)
101 || (this.mathComponent.getHorizontalAlignment() == SwingConstants.LEFT)) {
102 xo = 0.0f;
103 } else if ((this.mathComponent.getHorizontalAlignment() == SwingConstants.TRAILING)
104 || (this.mathComponent.getHorizontalAlignment() == SwingConstants.RIGHT)) {
105 xo = dim.width - this.base.getWidth(g2);
106 } else {
107 xo = (dim.width - this.base.getWidth(g2)) / 2.0f;
108 }
109 final float yo;
110 if (this.mathComponent.getVerticalAlignment() == SwingConstants.TOP) {
111 yo = 0.0f;
112 } else if (this.mathComponent.getVerticalAlignment() == SwingConstants.BOTTOM) {
113 yo = dim.height - this.base.getHeight(g2);
114 } else {
115 yo = (dim.height - this.base.getHeight(g2)) / 2.0f;
116 }
117 final Point2D alignOffset = new Point2D.Float(xo, yo);
118 return alignOffset;
119 }
120
121 private void paintBackground(final Graphics g, final Dimension dim,
122 final Point start) {
123 final Color back = this.getRealBackgroundColor();
124 if (back != null) {
125 g.setColor(back);
126 g.fillRect(start.x, start.y, dim.width, dim.height);
127 }
128 }
129
130 private Point getStartPointWithBordersAndAdjustDimension(
131 final Dimension dim) {
132 Point start = new Point(0, 0);
133 final Border border = this.mathComponent.getBorder();
134 if (border != null) {
135 final Insets insets = border.getBorderInsets(this.mathComponent);
136 if (insets != null) {
137 dim.width -= insets.left + insets.right;
138 dim.height -= insets.top + insets.bottom;
139 start = new Point(insets.left, insets.top);
140 }
141 }
142 return start;
143 }
144
145 private Color getRealBackgroundColor() {
146 Color back = this.mathComponent.getBackground();
147 if (this.mathComponent.isOpaque()) {
148 if (back == null) {
149 back = Color.WHITE;
150 }
151 // Remove Alpha
152 back = new Color(back.getRGB());
153 }
154 return back;
155 }
156
157 /** {@inheritDoc} */
158 @Override
159 public void installUI(final JComponent c) {
160 this.mathComponent = (JMathComponent) c;
161 c.addPropertyChangeListener(this);
162 this.installDefaults(this.mathComponent);
163 }
164
165 /**
166 * Configures the default properties from L&F.
167 *
168 * @param c
169 * the component
170 */
171 protected void installDefaults(final JMathComponent c) {
172 // LookAndFeel.installColorsAndFont(c, "Label.background",
173 // "Label.foreground", "Label.font");
174 LookAndFeel.installProperty(c, "opaque", Boolean.FALSE);
175 }
176
177 /** {@inheritDoc} */
178 @Override
179 public void uninstallUI(final JComponent c) {
180 c.removePropertyChangeListener(this);
181 this.mathComponent = null;
182 }
183
184 /** {@inheritDoc} */
185 public void propertyChange(final PropertyChangeEvent evt) {
186 final String name = evt.getPropertyName();
187 if (name.equals("document") || name.equals("property")) {
188 final JMathComponent jc = (JMathComponent) evt.getSource();
189 this.redo((Document) evt.getNewValue(), jc.getParameters());
190 // jc.repaint();
191 } else {
192 try {
193 final ParameterKey key = ParameterKey.valueOf(name);
194 this.base.setParam(key, evt.getNewValue().toString());
195 } catch (final IllegalArgumentException ia) {
196 MathComponentUI.LOGGER.debug(ia);
197 }
198 }
199 }
200
201 private void redo(final Document doc,
202 final Map<ParameterKey, String> parameters) {
203 if (doc != null) {
204 this.base = new MathBase(parameters);
205 new DOMBuilder(doc, this.base);
206 } else {
207 this.base = null;
208 }
209 }
210
211 /** {@inheritDoc} */
212 @Override
213 public Dimension getMinimumSize(final JComponent c) {
214 final Dimension dim;
215 if (this.base == null || c.getGraphics() == null) {
216 dim = this.getPreferredSize(c);
217 } else {
218 final Graphics2D g2d = (Graphics2D) c.getGraphics();
219 Defense.notNull(g2d, "g2d");
220 dim = new Dimension((int) Math.ceil(this.base.getWidth(g2d)),
221 (int) Math.ceil(this.base.getHeight(g2d)));
222 }
223 final Border border = c.getBorder();
224 if (border != null) {
225 final Insets insets = border.getBorderInsets(c);
226 if (insets != null) {
227 dim.width += insets.left + insets.right; // here +
228 dim.height += insets.top + insets.bottom; // here +
229 }
230 }
231 return dim;
232
233 }
234
235 }