1/* 2 * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25package javax.swing.text.html; 26 27import java.awt.*; 28import javax.swing.event.DocumentEvent; 29import javax.swing.text.*; 30import java.util.Enumeration; 31import java.lang.Integer; 32 33/** 34 * A view implementation to display an html horizontal 35 * rule. 36 * 37 * @author Timothy Prinzing 38 * @author Sara Swanson 39 */ 40class HRuleView extends View { 41 42 /** 43 * Creates a new view that represents an <hr> element. 44 * 45 * @param elem the element to create a view for 46 */ 47 public HRuleView(Element elem) { 48 super(elem); 49 setPropertiesFromAttributes(); 50 } 51 52 /** 53 * Update any cached values that come from attributes. 54 */ 55 protected void setPropertiesFromAttributes() { 56 StyleSheet sheet = ((HTMLDocument)getDocument()).getStyleSheet(); 57 AttributeSet eAttr = getElement().getAttributes(); 58 attr = sheet.getViewAttributes(this); 59 60 alignment = StyleConstants.ALIGN_CENTER; 61 size = 0; 62 noshade = null; 63 widthValue = null; 64 65 if (attr != null) { 66 // getAlignment() returns ALIGN_LEFT by default, and HR should 67 // use ALIGN_CENTER by default, so we check if the alignment 68 // attribute is actually defined 69 if (attr.getAttribute(StyleConstants.Alignment) != null) { 70 alignment = StyleConstants.getAlignment(attr); 71 } 72 73 noshade = (String)eAttr.getAttribute(HTML.Attribute.NOSHADE); 74 Object value = eAttr.getAttribute(HTML.Attribute.SIZE); 75 if (value != null && (value instanceof String)) { 76 try { 77 size = Integer.parseInt((String)value); 78 } catch (NumberFormatException e) { 79 size = 1; 80 } 81 } 82 value = attr.getAttribute(CSS.Attribute.WIDTH); 83 if (value != null && (value instanceof CSS.LengthValue)) { 84 widthValue = (CSS.LengthValue)value; 85 } 86 topMargin = getLength(CSS.Attribute.MARGIN_TOP, attr); 87 bottomMargin = getLength(CSS.Attribute.MARGIN_BOTTOM, attr); 88 leftMargin = getLength(CSS.Attribute.MARGIN_LEFT, attr); 89 rightMargin = getLength(CSS.Attribute.MARGIN_RIGHT, attr); 90 } 91 else { 92 topMargin = bottomMargin = leftMargin = rightMargin = 0; 93 } 94 size = Math.max(2, size); 95 } 96 97 // This will be removed and centralized at some point, need to unify this 98 // and avoid private classes. 99 private float getLength(CSS.Attribute key, AttributeSet a) { 100 CSS.LengthValue lv = (CSS.LengthValue) a.getAttribute(key); 101 float len = (lv != null) ? lv.getValue() : 0; 102 return len; 103 } 104 105 // --- View methods --------------------------------------------- 106 107 /** 108 * Paints the view. 109 * 110 * @param g the graphics context 111 * @param a the allocation region for the view 112 * @see View#paint 113 */ 114 public void paint(Graphics g, Shape a) { 115 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : 116 a.getBounds(); 117 int x = 0; 118 int y = alloc.y + SPACE_ABOVE + (int)topMargin; 119 int width = alloc.width - (int)(leftMargin + rightMargin); 120 if (widthValue != null) { 121 width = (int)widthValue.getValue((float)width); 122 } 123 int height = alloc.height - (SPACE_ABOVE + SPACE_BELOW + 124 (int)topMargin + (int)bottomMargin); 125 if (size > 0) 126 height = size; 127 128 // Align the rule horizontally. 129 switch (alignment) { 130 case StyleConstants.ALIGN_CENTER: 131 x = alloc.x + (alloc.width / 2) - (width / 2); 132 break; 133 case StyleConstants.ALIGN_RIGHT: 134 x = alloc.x + alloc.width - width - (int)rightMargin; 135 break; 136 case StyleConstants.ALIGN_LEFT: 137 default: 138 x = alloc.x + (int)leftMargin; 139 break; 140 } 141 142 // Paint either a shaded rule or a solid line. 143 if (noshade != null) { 144 g.setColor(Color.black); 145 g.fillRect(x, y, width, height); 146 } 147 else { 148 Color bg = getContainer().getBackground(); 149 Color bottom, top; 150 if (bg == null || bg.equals(Color.white)) { 151 top = Color.darkGray; 152 bottom = Color.lightGray; 153 } 154 else { 155 top = Color.darkGray; 156 bottom = Color.white; 157 } 158 g.setColor(bottom); 159 g.drawLine(x + width - 1, y, x + width - 1, y + height - 1); 160 g.drawLine(x, y + height - 1, x + width - 1, y + height - 1); 161 g.setColor(top); 162 g.drawLine(x, y, x + width - 1, y); 163 g.drawLine(x, y, x, y + height - 1); 164 } 165 166 } 167 168 169 /** 170 * Calculates the desired shape of the rule... this is 171 * basically the preferred size of the border. 172 * 173 * @param axis may be either X_AXIS or Y_AXIS 174 * @return the desired span 175 * @see View#getPreferredSpan 176 */ 177 public float getPreferredSpan(int axis) { 178 switch (axis) { 179 case View.X_AXIS: 180 return 1; 181 case View.Y_AXIS: 182 if (size > 0) { 183 return size + SPACE_ABOVE + SPACE_BELOW + topMargin + 184 bottomMargin; 185 } else { 186 if (noshade != null) { 187 return 2 + SPACE_ABOVE + SPACE_BELOW + topMargin + 188 bottomMargin; 189 } else { 190 return SPACE_ABOVE + SPACE_BELOW + topMargin +bottomMargin; 191 } 192 } 193 default: 194 throw new IllegalArgumentException("Invalid axis: " + axis); 195 } 196 } 197 198 /** 199 * Gets the resize weight for the axis. 200 * The rule is: rigid vertically and flexible horizontally. 201 * 202 * @param axis may be either X_AXIS or Y_AXIS 203 * @return the weight 204 */ 205 public int getResizeWeight(int axis) { 206 if (axis == View.X_AXIS) { 207 return 1; 208 } else if (axis == View.Y_AXIS) { 209 return 0; 210 } else { 211 return 0; 212 } 213 } 214 215 /** 216 * Determines how attractive a break opportunity in 217 * this view is. This is implemented to request a forced break. 218 * 219 * @param axis may be either View.X_AXIS or View.Y_AXIS 220 * @param pos the potential location of the start of the 221 * broken view (greater than or equal to zero). 222 * This may be useful for calculating tab 223 * positions. 224 * @param len specifies the relative length from <em>pos</em> 225 * where a potential break is desired. The value must be greater 226 * than or equal to zero. 227 * @return the weight, which should be a value between 228 * ForcedBreakWeight and BadBreakWeight. 229 */ 230 public int getBreakWeight(int axis, float pos, float len) { 231 if (axis == X_AXIS) { 232 return ForcedBreakWeight; 233 } 234 return BadBreakWeight; 235 } 236 237 public View breakView(int axis, int offset, float pos, float len) { 238 return null; 239 } 240 241 /** 242 * Provides a mapping from the document model coordinate space 243 * to the coordinate space of the view mapped to it. 244 * 245 * @param pos the position to convert 246 * @param a the allocated region to render into 247 * @return the bounding box of the given position 248 * @exception BadLocationException if the given position does not 249 * represent a valid location in the associated document 250 * @see View#modelToView 251 */ 252 public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { 253 int p0 = getStartOffset(); 254 int p1 = getEndOffset(); 255 if ((pos >= p0) && (pos <= p1)) { 256 Rectangle r = a.getBounds(); 257 if (pos == p1) { 258 r.x += r.width; 259 } 260 r.width = 0; 261 return r; 262 } 263 return null; 264 } 265 266 /** 267 * Provides a mapping from the view coordinate space to the logical 268 * coordinate space of the model. 269 * 270 * @param x the X coordinate 271 * @param y the Y coordinate 272 * @param a the allocated region to render into 273 * @return the location within the model that best represents the 274 * given point of view 275 * @see View#viewToModel 276 */ 277 public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) { 278 Rectangle alloc = (Rectangle) a; 279 if (x < alloc.x + (alloc.width / 2)) { 280 bias[0] = Position.Bias.Forward; 281 return getStartOffset(); 282 } 283 bias[0] = Position.Bias.Backward; 284 return getEndOffset(); 285 } 286 287 /** 288 * Fetches the attributes to use when rendering. This is 289 * implemented to multiplex the attributes specified in the 290 * model with a StyleSheet. 291 */ 292 public AttributeSet getAttributes() { 293 return attr; 294 } 295 296 public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) { 297 super.changedUpdate(changes, a, f); 298 int pos = changes.getOffset(); 299 if (pos <= getStartOffset() && (pos + changes.getLength()) >= 300 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} 322