001 /*
002 * Copyright 1997-2002 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.event.DocumentEvent;
029 import javax.swing.text.*;
030 import java.util.Enumeration;
031 import java.lang.Integer;
032
033 /**
034 * A view implementation to display an html horizontal
035 * rule.
036 *
037 * @author Timothy Prinzing
038 * @author Sara Swanson
039 * @version 1.39 05/05/07
040 */
041 class HRuleView extends View {
042
043 /**
044 * Creates a new view that represents an <hr> element.
045 *
046 * @param elem the element to create a view for
047 */
048 public HRuleView(Element elem) {
049 super (elem);
050 setPropertiesFromAttributes();
051 }
052
053 /**
054 * Update any cached values that come from attributes.
055 */
056 protected void setPropertiesFromAttributes() {
057 StyleSheet sheet = ((HTMLDocument) getDocument())
058 .getStyleSheet();
059 AttributeSet eAttr = getElement().getAttributes();
060 attr = sheet.getViewAttributes(this );
061
062 alignment = StyleConstants.ALIGN_CENTER;
063 size = 0;
064 noshade = null;
065 widthValue = null;
066
067 if (attr != null) {
068 // getAlignment() returns ALIGN_LEFT by default, and HR should
069 // use ALIGN_CENTER by default, so we check if the alignment
070 // attribute is actually defined
071 if (attr.getAttribute(StyleConstants.Alignment) != null) {
072 alignment = StyleConstants.getAlignment(attr);
073 }
074
075 noshade = (String) eAttr
076 .getAttribute(HTML.Attribute.NOSHADE);
077 Object value = eAttr.getAttribute(HTML.Attribute.SIZE);
078 if (value != null && (value instanceof String))
079 size = Integer.parseInt((String) value);
080 value = attr.getAttribute(CSS.Attribute.WIDTH);
081 if (value != null && (value instanceof CSS.LengthValue)) {
082 widthValue = (CSS.LengthValue) value;
083 }
084 topMargin = getLength(CSS.Attribute.MARGIN_TOP, attr);
085 bottomMargin = getLength(CSS.Attribute.MARGIN_BOTTOM, attr);
086 leftMargin = getLength(CSS.Attribute.MARGIN_LEFT, attr);
087 rightMargin = getLength(CSS.Attribute.MARGIN_RIGHT, attr);
088 } else {
089 topMargin = bottomMargin = leftMargin = rightMargin = 0;
090 }
091 size = Math.max(2, size);
092 }
093
094 // This will be removed and centralized at some point, need to unify this
095 // and avoid private classes.
096 private float getLength(CSS.Attribute key, AttributeSet a) {
097 CSS.LengthValue lv = (CSS.LengthValue) a.getAttribute(key);
098 float len = (lv != null) ? lv.getValue() : 0;
099 return len;
100 }
101
102 // --- View methods ---------------------------------------------
103
104 /**
105 * Paints the view.
106 *
107 * @param g the graphics context
108 * @param a the allocation region for the view
109 * @see View#paint
110 */
111 public void paint(Graphics g, Shape a) {
112 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle) a : a
113 .getBounds();
114 int x = 0;
115 int y = alloc.y + SPACE_ABOVE + (int) topMargin;
116 int width = alloc.width - (int) (leftMargin + rightMargin);
117 if (widthValue != null) {
118 width = (int) widthValue.getValue((float) width);
119 }
120 int height = alloc.height
121 - (SPACE_ABOVE + SPACE_BELOW + (int) topMargin + (int) bottomMargin);
122 if (size > 0)
123 height = size;
124
125 // Align the rule horizontally.
126 switch (alignment) {
127 case StyleConstants.ALIGN_CENTER:
128 x = alloc.x + (alloc.width / 2) - (width / 2);
129 break;
130 case StyleConstants.ALIGN_RIGHT:
131 x = alloc.x + alloc.width - width - (int) rightMargin;
132 break;
133 case StyleConstants.ALIGN_LEFT:
134 default:
135 x = alloc.x + (int) leftMargin;
136 break;
137 }
138
139 // Paint either a shaded rule or a solid line.
140 if (noshade != null) {
141 g.setColor(Color.black);
142 g.fillRect(x, y, width, height);
143 } else {
144 Color bg = getContainer().getBackground();
145 Color bottom, top;
146 if (bg == null || bg.equals(Color.white)) {
147 top = Color.darkGray;
148 bottom = Color.lightGray;
149 } else {
150 top = Color.darkGray;
151 bottom = Color.white;
152 }
153 g.setColor(bottom);
154 g.drawLine(x + width - 1, y, x + width - 1, y + height - 1);
155 g
156 .drawLine(x, y + height - 1, x + width - 1, y
157 + height - 1);
158 g.setColor(top);
159 g.drawLine(x, y, x + width - 1, y);
160 g.drawLine(x, y, x, y + height - 1);
161 }
162
163 }
164
165 /**
166 * Calculates the desired shape of the rule... this is
167 * basically the preferred size of the border.
168 *
169 * @param axis may be either X_AXIS or Y_AXIS
170 * @return the desired span
171 * @see View#getPreferredSpan
172 */
173 public float getPreferredSpan(int axis) {
174 switch (axis) {
175 case View.X_AXIS:
176 return 1;
177 case View.Y_AXIS:
178 if (size > 0) {
179 return size + SPACE_ABOVE + SPACE_BELOW + topMargin
180 + bottomMargin;
181 } else {
182 if (noshade != null) {
183 return 2 + SPACE_ABOVE + SPACE_BELOW + topMargin
184 + bottomMargin;
185 } else {
186 return SPACE_ABOVE + SPACE_BELOW + topMargin
187 + bottomMargin;
188 }
189 }
190 default:
191 throw new IllegalArgumentException("Invalid axis: " + axis);
192 }
193 }
194
195 /**
196 * Gets the resize weight for the axis.
197 * The rule is: rigid vertically and flexible horizontally.
198 *
199 * @param axis may be either X_AXIS or Y_AXIS
200 * @return the weight
201 */
202 public int getResizeWeight(int axis) {
203 if (axis == View.X_AXIS) {
204 return 1;
205 } else if (axis == View.Y_AXIS) {
206 return 0;
207 } else {
208 return 0;
209 }
210 }
211
212 /**
213 * Determines how attractive a break opportunity in
214 * this view is. This is implemented to request a forced break.
215 *
216 * @param axis may be either View.X_AXIS or View.Y_AXIS
217 * @param pos the potential location of the start of the
218 * broken view (greater than or equal to zero).
219 * This may be useful for calculating tab
220 * positions.
221 * @param len specifies the relative length from <em>pos</em>
222 * where a potential break is desired. The value must be greater
223 * than or equal to zero.
224 * @return the weight, which should be a value between
225 * ForcedBreakWeight and BadBreakWeight.
226 */
227 public int getBreakWeight(int axis, float pos, float len) {
228 if (axis == X_AXIS) {
229 return ForcedBreakWeight;
230 }
231 return BadBreakWeight;
232 }
233
234 public View breakView(int axis, int offset, float pos, float len) {
235 return null;
236 }
237
238 /**
239 * Provides a mapping from the document model coordinate space
240 * to the coordinate space of the view mapped to it.
241 *
242 * @param pos the position to convert
243 * @param a the allocated region to render into
244 * @return the bounding box of the given position
245 * @exception BadLocationException if the given position does not
246 * represent a valid location in the associated document
247 * @see View#modelToView
248 */
249 public Shape modelToView(int pos, Shape a, Position.Bias b)
250 throws BadLocationException {
251 int p0 = getStartOffset();
252 int p1 = getEndOffset();
253 if ((pos >= p0) && (pos <= p1)) {
254 Rectangle r = a.getBounds();
255 if (pos == p1) {
256 r.x += r.width;
257 }
258 r.width = 0;
259 return r;
260 }
261 return null;
262 }
263
264 /**
265 * Provides a mapping from the view coordinate space to the logical
266 * coordinate space of the model.
267 *
268 * @param x the X coordinate
269 * @param y the Y coordinate
270 * @param a the allocated region to render into
271 * @return the location within the model that best represents the
272 * given point of view
273 * @see View#viewToModel
274 */
275 public int viewToModel(float x, float y, Shape a,
276 Position.Bias[] bias) {
277 Rectangle alloc = (Rectangle) a;
278 if (x < alloc.x + (alloc.width / 2)) {
279 bias[0] = Position.Bias.Forward;
280 return getStartOffset();
281 }
282 bias[0] = Position.Bias.Backward;
283 return getEndOffset();
284 }
285
286 /**
287 * Fetches the attributes to use when rendering. This is
288 * implemented to multiplex the attributes specified in the
289 * model with a StyleSheet.
290 */
291 public AttributeSet getAttributes() {
292 return attr;
293 }
294
295 public void changedUpdate(DocumentEvent changes, Shape a,
296 ViewFactory f) {
297 super .changedUpdate(changes, a, f);
298 int pos = changes.getOffset();
299 if (pos <= getStartOffset()
300 && (pos + changes.getLength()) >= getEndOffset()) {
301 setPropertiesFromAttributes();
302 }
303 }
304
305 // --- variables ------------------------------------------------
306
307 private float topMargin;
308 private float bottomMargin;
309 private float leftMargin;
310 private float rightMargin;
311 private int alignment = StyleConstants.ALIGN_CENTER;
312 private String noshade = null;
313 private int size = 0;
314 private CSS.LengthValue widthValue;
315
316 private static final int SPACE_ABOVE = 3;
317 private static final int SPACE_BELOW = 3;
318
319 /** View Attributes. */
320 private AttributeSet attr;
321 }
|