001/* ParagraphView.java -- Renders a paragraph in HTML
002   Copyright (C) 2006 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing.text.html;
040
041import gnu.javax.swing.text.html.css.Length;
042
043import java.awt.Graphics;
044import java.awt.Rectangle;
045import java.awt.Shape;
046
047import javax.swing.SizeRequirements;
048import javax.swing.text.AttributeSet;
049import javax.swing.text.Document;
050import javax.swing.text.Element;
051import javax.swing.text.StyleConstants;
052import javax.swing.text.View;
053
054/**
055 * Renders a paragraph in HTML. This is a subclass of
056 * {@link javax.swing.text.ParagraphView} with some adjustments for
057 * understanding stylesheets.
058 *
059 * @author Roman Kennke (kennke@aicas.com)
060 */
061public class ParagraphView
062  extends javax.swing.text.ParagraphView
063{
064
065  /**
066   * The attributes used by this view.
067   */
068  private AttributeSet attributes;
069
070  /**
071   * The stylesheet's box painter.
072   */
073  private StyleSheet.BoxPainter painter;
074
075  /**
076   * The width as specified in the stylesheet or null if not specified.
077   */
078  private Length cssWidth;
079
080  /**
081   * The height as specified in the stylesheet or null if not specified.
082   */
083  private Length cssHeight;
084
085  /**
086   * Creates a new ParagraphView for the specified element.
087   *
088   * @param element the element
089   */
090  public ParagraphView(Element element)
091  {
092    super(element);
093  }
094
095  /**
096   * Sets the parent of this view. This is implemented to call the parent
097   * functionality and then trigger {@link #setPropertiesFromAttributes} in
098   * order to load the stylesheet attributes.
099   *
100   * @param parent the parent view to set
101   */
102  public void setParent(View parent)
103  {
104    super.setParent(parent);
105    if (parent != null)
106      setPropertiesFromAttributes();
107  }
108
109  /**
110   * Returns the attributes used by this view. This is implemented to multiplex
111   * the attributes of the model with the attributes of the stylesheet.
112   */
113  public AttributeSet getAttributes()
114  {
115    if (attributes == null)
116      {
117        attributes = getStyleSheet().getViewAttributes(this);
118      }
119    return attributes;
120  }
121
122  /**
123   * Loads the visual properties of the ParagraphView from the element's
124   * attributes and the stylesheet of the HTML document.
125   */
126  protected void setPropertiesFromAttributes()
127  {
128    super.setPropertiesFromAttributes();
129
130    // Fetch CSS attributes.
131    attributes = getAttributes();
132    if (attributes != null)
133      {
134        super.setPropertiesFromAttributes();
135        Object o = attributes.getAttribute(CSS.Attribute.TEXT_ALIGN);
136        if (o != null)
137          {
138            String align = o.toString();
139            if (align.equals("left"))
140              setJustification(StyleConstants.ALIGN_LEFT);
141            else if (align.equals("right"))
142              setJustification(StyleConstants.ALIGN_RIGHT);
143            else if (align.equals("center"))
144              setJustification(StyleConstants.ALIGN_CENTER);
145            else if (align.equals("justify"))
146              setJustification(StyleConstants.ALIGN_JUSTIFIED);
147          }
148
149        // Fetch StyleSheet's box painter.
150        painter = getStyleSheet().getBoxPainter(attributes);
151        setInsets((short) painter.getInset(TOP, this),
152                  (short) painter.getInset(LEFT, this),
153                  (short) painter.getInset(BOTTOM, this),
154                  (short) painter.getInset(RIGHT, this));
155
156        StyleSheet ss = getStyleSheet();
157        float emBase = ss.getEMBase(attributes);
158        float exBase = ss.getEXBase(attributes);
159        cssWidth = (Length) attributes.getAttribute(CSS.Attribute.WIDTH);
160        if (cssWidth != null)
161          cssWidth.setFontBases(emBase, exBase);
162        cssHeight = (Length) attributes.getAttribute(CSS.Attribute.WIDTH);
163        if (cssHeight != null)
164          cssHeight.setFontBases(emBase, exBase);
165      }
166  }
167
168  /**
169   * Returns the stylesheet used by this view.
170   *
171   * @return the stylesheet used by this view
172   */
173  protected StyleSheet getStyleSheet()
174  {
175    Document doc = getDocument();
176    StyleSheet styleSheet = null;
177    if (doc instanceof HTMLDocument)
178      styleSheet = ((HTMLDocument) doc).getStyleSheet();
179    return styleSheet;
180  }
181
182  /**
183   * Calculates the minor axis requirements of this view. This is implemented
184   * to return the super class'es requirements and modifies the minimumSpan
185   * slightly so that it is not smaller than the length of the longest word.
186   *
187   * @param axis the axis
188   * @param r the SizeRequirements object to be used as return parameter;
189   *        if <code>null</code> a new one will be created
190   *
191   * @return the requirements along the minor layout axis
192   */
193  protected SizeRequirements calculateMinorAxisRequirements(int axis,
194                                                            SizeRequirements r)
195  {
196    r = super.calculateMinorAxisRequirements(axis, r);
197    if (! setCSSSpan(r, axis))
198      {
199        int margin = axis == X_AXIS ? getLeftInset() + getRightInset()
200                                    : getTopInset() + getBottomInset();
201        r.minimum -= margin;
202        r.preferred -= margin;
203        r.maximum -= margin;
204      }
205    return r;
206  }
207
208  /**
209   * Sets the span on the SizeRequirements object according to the
210   * according CSS span value, when it is set.
211   *
212   * @param r the size requirements
213   * @param axis the axis
214   *
215   * @return <code>true</code> when the CSS span has been set,
216   *         <code>false</code> otherwise
217   */
218  private boolean setCSSSpan(SizeRequirements r, int axis)
219  {
220    boolean ret = false;
221    if (axis == X_AXIS)
222      {
223        if (cssWidth != null && ! cssWidth.isPercentage())
224          {
225            r.minimum = (int) cssWidth.getValue();
226            r.preferred = (int) cssWidth.getValue();
227            r.maximum = (int) cssWidth.getValue();
228            ret = true;
229          }
230      }
231    else
232      {
233        if (cssHeight != null && ! cssWidth.isPercentage())
234          {
235            r.minimum = (int) cssHeight.getValue();
236            r.preferred = (int) cssHeight.getValue();
237            r.maximum = (int) cssHeight.getValue();
238            ret = true;
239          }
240      }
241    return ret;
242  }
243
244  /**
245   * Determines if this view is visible or not. If none of the children is
246   * visible and the only visible child is the break that ends the paragraph,
247   * this paragraph is not considered to be visible.
248   *
249   * @return the visibility of this paragraph
250   */
251  public boolean isVisible()
252  {
253    // FIXME: Implement the above specified behaviour.
254    return super.isVisible();
255  }
256
257  /**
258   * Paints this view. This paints the box using the stylesheet's
259   * box painter for this view and delegates to the super class paint()
260   * afterwards.
261   *
262   * @param g the graphics object
263   * @param a the current allocation of this view
264   */
265  public void paint(Graphics g, Shape a)
266  {
267    if (a != null)
268      {
269        Rectangle r = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
270        painter.paint(g, r.x, r.y, r.width, r.height, this);
271      }
272    super.paint(g, a);
273  }
274
275  /**
276   * Returns the preferred span of this view. If this view is not visible,
277   * we return <code>0</code>, otherwise the super class is called.
278   *
279   * @param axis the axis
280   *
281   * @return the preferred span of this view
282   */
283  public float getPreferredSpan(int axis)
284  {
285    float span = 0;
286    if (isVisible())
287      span = super.getPreferredSpan(axis);
288    return span;
289  }
290
291  /**
292   * Returns the minimum span of this view. If this view is not visible,
293   * we return <code>0</code>, otherwise the super class is called.
294   *
295   * @param axis the axis
296   *
297   * @return the minimum span of this view
298   */
299  public float getMinimumSpan(int axis)
300  {
301    float span = 0;
302    if (isVisible())
303      span = super.getMinimumSpan(axis);
304    return span;
305  }
306
307  /**
308   * Returns the maximum span of this view. If this view is not visible,
309   * we return <code>0</code>, otherwise the super class is called.
310   *
311   * @param axis the axis
312   *
313   * @return the maximum span of this view
314   */
315  public float getMaximumSpan(int axis)
316  {
317    float span = 0;
318    if (isVisible())
319      span = super.getMaximumSpan(axis);
320    return span;
321  }
322}