001 /*
002 * Copyright 1998-2003 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025 package javax.swing.text.html;
026
027 import java.awt.*;
028 import javax.swing.SizeRequirements;
029 import javax.swing.event.DocumentEvent;
030 import javax.swing.text.Document;
031 import javax.swing.text.Element;
032 import javax.swing.text.AttributeSet;
033 import javax.swing.text.StyleConstants;
034 import javax.swing.text.View;
035 import javax.swing.text.ViewFactory;
036 import javax.swing.text.BadLocationException;
037 import javax.swing.text.JTextComponent;
038
039 /**
040 * Displays the a paragraph, and uses css attributes for its
041 * configuration.
042 *
043 * @author Timothy Prinzing
044 * @version 1.36 05/05/07
045 */
046
047 public class ParagraphView extends javax.swing.text.ParagraphView {
048
049 /**
050 * Constructs a ParagraphView for the given element.
051 *
052 * @param elem the element that this view is responsible for
053 */
054 public ParagraphView(Element elem) {
055 super (elem);
056 }
057
058 /**
059 * Establishes the parent view for this view. This is
060 * guaranteed to be called before any other methods if the
061 * parent view is functioning properly.
062 * <p>
063 * This is implemented
064 * to forward to the superclass as well as call the
065 * <a href="#setPropertiesFromAttributes">setPropertiesFromAttributes</a>
066 * method to set the paragraph properties from the css
067 * attributes. The call is made at this time to ensure
068 * the ability to resolve upward through the parents
069 * view attributes.
070 *
071 * @param parent the new parent, or null if the view is
072 * being removed from a parent it was previously added
073 * to
074 */
075 public void setParent(View parent) {
076 super .setParent(parent);
077 if (parent != null) {
078 setPropertiesFromAttributes();
079 }
080 }
081
082 /**
083 * Fetches the attributes to use when rendering. This is
084 * implemented to multiplex the attributes specified in the
085 * model with a StyleSheet.
086 */
087 public AttributeSet getAttributes() {
088 if (attr == null) {
089 StyleSheet sheet = getStyleSheet();
090 attr = sheet.getViewAttributes(this );
091 }
092 return attr;
093 }
094
095 /**
096 * Sets up the paragraph from css attributes instead of
097 * the values found in StyleConstants (i.e. which are used
098 * by the superclass). Since
099 */
100 protected void setPropertiesFromAttributes() {
101 StyleSheet sheet = getStyleSheet();
102 attr = sheet.getViewAttributes(this );
103 painter = sheet.getBoxPainter(attr);
104 if (attr != null) {
105 super .setPropertiesFromAttributes();
106 setInsets((short) painter.getInset(TOP, this ),
107 (short) painter.getInset(LEFT, this ),
108 (short) painter.getInset(BOTTOM, this ),
109 (short) painter.getInset(RIGHT, this ));
110 Object o = attr.getAttribute(CSS.Attribute.TEXT_ALIGN);
111 if (o != null) {
112 // set horizontal alignment
113 String ta = o.toString();
114 if (ta.equals("left")) {
115 setJustification(StyleConstants.ALIGN_LEFT);
116 } else if (ta.equals("center")) {
117 setJustification(StyleConstants.ALIGN_CENTER);
118 } else if (ta.equals("right")) {
119 setJustification(StyleConstants.ALIGN_RIGHT);
120 } else if (ta.equals("justify")) {
121 setJustification(StyleConstants.ALIGN_JUSTIFIED);
122 }
123 }
124 // Get the width/height
125 cssWidth = (CSS.LengthValue) attr
126 .getAttribute(CSS.Attribute.WIDTH);
127 cssHeight = (CSS.LengthValue) attr
128 .getAttribute(CSS.Attribute.HEIGHT);
129 }
130 }
131
132 protected StyleSheet getStyleSheet() {
133 HTMLDocument doc = (HTMLDocument) getDocument();
134 return doc.getStyleSheet();
135 }
136
137 /**
138 * Calculate the needs for the paragraph along the minor axis.
139 * This implemented to use the requirements of the superclass,
140 * modified slightly to set a minimum span allowed. Typical
141 * html rendering doesn't let the view size shrink smaller than
142 * the length of the longest word.
143 */
144 protected SizeRequirements calculateMinorAxisRequirements(int axis,
145 SizeRequirements r) {
146 r = super .calculateMinorAxisRequirements(axis, r);
147
148 if (!BlockView.spanSetFromAttributes(axis, r, cssWidth,
149 cssHeight)) {
150 // PENDING(prinz) Need to make this better so it doesn't require
151 // InlineView and works with font changes within the word.
152
153 // find the longest minimum span.
154 float min = 0;
155 int n = getLayoutViewCount();
156 for (int i = 0; i < n; i++) {
157 View v = getLayoutView(i);
158 if (v instanceof InlineView) {
159 float wordSpan = ((InlineView) v)
160 .getLongestWordSpan();
161 min = Math.max(wordSpan, min);
162 } else {
163 min = Math.max(v.getMinimumSpan(axis), min);
164 }
165 }
166 r.minimum = Math.max(r.minimum, (int) min);
167 r.preferred = Math.max(r.minimum, r.preferred);
168 r.maximum = Math.max(r.preferred, r.maximum);
169 } else {
170 // Offset by the margins so that pref/min/max return the
171 // right value.
172 int margin = (axis == X_AXIS) ? getLeftInset()
173 + getRightInset() : getTopInset()
174 + getBottomInset();
175 r.minimum -= margin;
176 r.preferred -= margin;
177 r.maximum -= margin;
178 }
179 return r;
180 }
181
182 /**
183 * Indicates whether or not this view should be
184 * displayed. If none of the children wish to be
185 * displayed and the only visible child is the
186 * break that ends the paragraph, the paragraph
187 * will not be considered visible. Otherwise,
188 * it will be considered visible and return true.
189 *
190 * @return true if the paragraph should be displayed
191 */
192 public boolean isVisible() {
193
194 int n = getLayoutViewCount() - 1;
195 for (int i = 0; i < n; i++) {
196 View v = getLayoutView(i);
197 if (v.isVisible()) {
198 return true;
199 }
200 }
201 if (n > 0) {
202 View v = getLayoutView(n);
203 if ((v.getEndOffset() - v.getStartOffset()) == 1) {
204 return false;
205 }
206 }
207 // If it's the last paragraph and not editable, it shouldn't
208 // be visible.
209 if (getStartOffset() == getDocument().getLength()) {
210 boolean editable = false;
211 Component c = getContainer();
212 if (c instanceof JTextComponent) {
213 editable = ((JTextComponent) c).isEditable();
214 }
215 if (!editable) {
216 return false;
217 }
218 }
219 return true;
220 }
221
222 /**
223 * Renders using the given rendering surface and area on that
224 * surface. This is implemented to delgate to the superclass
225 * after stashing the base coordinate for tab calculations.
226 *
227 * @param g the rendering surface to use
228 * @param a the allocated region to render into
229 * @see View#paint
230 */
231 public void paint(Graphics g, Shape a) {
232 if (a == null) {
233 return;
234 }
235
236 Rectangle r;
237 if (a instanceof Rectangle) {
238 r = (Rectangle) a;
239 } else {
240 r = a.getBounds();
241 }
242 painter.paint(g, r.x, r.y, r.width, r.height, this );
243 super .paint(g, a);
244 }
245
246 /**
247 * Determines the preferred span for this view. Returns
248 * 0 if the view is not visible, otherwise it calls the
249 * superclass method to get the preferred span.
250 * axis.
251 *
252 * @param axis may be either View.X_AXIS or View.Y_AXIS
253 * @return the span the view would like to be rendered into;
254 * typically the view is told to render into the span
255 * that is returned, although there is no guarantee;
256 * the parent may choose to resize or break the view
257 * @see javax.swing.text.ParagraphView#getPreferredSpan
258 */
259 public float getPreferredSpan(int axis) {
260 if (!isVisible()) {
261 return 0;
262 }
263 return super .getPreferredSpan(axis);
264 }
265
266 /**
267 * Determines the minimum span for this view along an
268 * axis. Returns 0 if the view is not visible, otherwise
269 * it calls the superclass method to get the minimum span.
270 *
271 * @param axis may be either <code>View.X_AXIS</code> or
272 * <code>View.Y_AXIS</code>
273 * @return the minimum span the view can be rendered into
274 * @see javax.swing.text.ParagraphView#getMinimumSpan
275 */
276 public float getMinimumSpan(int axis) {
277 if (!isVisible()) {
278 return 0;
279 }
280 return super .getMinimumSpan(axis);
281 }
282
283 /**
284 * Determines the maximum span for this view along an
285 * axis. Returns 0 if the view is not visible, otherwise
286 * it calls the superclass method ot get the maximum span.
287 *
288 * @param axis may be either <code>View.X_AXIS</code> or
289 * <code>View.Y_AXIS</code>
290 * @return the maximum span the view can be rendered into
291 * @see javax.swing.text.ParagraphView#getMaximumSpan
292 */
293 public float getMaximumSpan(int axis) {
294 if (!isVisible()) {
295 return 0;
296 }
297 return super .getMaximumSpan(axis);
298 }
299
300 private AttributeSet attr;
301 private StyleSheet.BoxPainter painter;
302 private CSS.LengthValue cssWidth;
303 private CSS.LengthValue cssHeight;
304 }
|