Frames | No Frames |
1: /* ParagraphView.java -- A composite View 2: Copyright (C) 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing.text; 40: 41: import java.awt.Shape; 42: 43: import javax.swing.event.DocumentEvent; 44: 45: /** 46: * A {@link FlowView} that flows it's children horizontally and boxes the rows 47: * vertically. 48: * 49: * @author Roman Kennke (roman@kennke.org) 50: */ 51: public class ParagraphView extends FlowView implements TabExpander 52: { 53: /** 54: * A specialized horizontal <code>BoxView</code> that represents exactly 55: * one row in a <code>ParagraphView</code>. 56: */ 57: class Row extends BoxView 58: { 59: /** 60: * Creates a new instance of <code>Row</code>. 61: */ 62: Row(Element el) 63: { 64: super(el, X_AXIS); 65: } 66: 67: public float getAlignment(int axis) 68: { 69: float align; 70: if (axis == X_AXIS) 71: align = 0.0F; // TODO: Implement according to justification 72: else 73: align = super.getAlignment(axis); 74: return align; 75: } 76: 77: protected void loadChildren(ViewFactory vf) 78: { 79: // Do nothing here. The children are added while layouting. 80: } 81: } 82: 83: /** 84: * The indentation of the first line of the paragraph. 85: */ 86: protected int firstLineIndent; 87: 88: /** 89: * The justification of the paragraph. 90: */ 91: private int justification; 92: 93: /** 94: * The line spacing of this paragraph. 95: */ 96: private float lineSpacing; 97: 98: /** 99: * The TabSet of this paragraph. 100: */ 101: private TabSet tabSet; 102: 103: /** 104: * Creates a new <code>ParagraphView</code> for the given 105: * <code>Element</code>. 106: * 107: * @param element the element that is rendered by this ParagraphView 108: */ 109: public ParagraphView(Element element) 110: { 111: super(element, Y_AXIS); 112: } 113: 114: public float nextTabStop(float x, int tabOffset) 115: { 116: throw new InternalError("Not implemented yet"); 117: } 118: 119: /** 120: * Creates a new view that represents a row within a flow. 121: * 122: * @return a view for a new row 123: */ 124: protected View createRow() 125: { 126: return new Row(getElement()); 127: } 128: 129: /** 130: * Returns the alignment for this paragraph view for the specified axis. 131: * For the X_AXIS the paragraph view will be aligned at it's left edge 132: * (0.0F). For the Y_AXIS the paragraph view will be aligned at the 133: * center of it's first row. 134: * 135: * @param axis the axis which is examined 136: * 137: * @return the alignment for this paragraph view for the specified axis 138: */ 139: public float getAlignment(int axis) 140: { 141: float align; 142: if (axis == X_AXIS) 143: align = super.getAlignment(axis); 144: else if (getViewCount() > 0) 145: { 146: float prefHeight = getPreferredSpan(Y_AXIS); 147: float firstRowHeight = getView(0).getPreferredSpan(Y_AXIS); 148: align = (firstRowHeight / 2.F) / prefHeight; 149: } 150: else 151: align = 0.0F; 152: return align; 153: } 154: 155: /** 156: * Receives notification when some attributes of the displayed element 157: * changes. This triggers a refresh of the cached attributes of this 158: * paragraph. 159: * 160: * @param ev the document event 161: * @param a the allocation of this view 162: * @param fv the view factory to use for creating new child views 163: */ 164: public void changedUpdate(DocumentEvent ev, Shape a, ViewFactory fv) 165: { 166: setPropertiesFromAttributes(); 167: } 168: 169: /** 170: * Fetches the cached properties from the element's attributes. 171: */ 172: protected void setPropertiesFromAttributes() 173: { 174: Element el = getElement(); 175: AttributeSet atts = el.getAttributes(); 176: setFirstLineIndent(StyleConstants.getFirstLineIndent(atts)); 177: setLineSpacing(StyleConstants.getLineSpacing(atts)); 178: setJustification(StyleConstants.getAlignment(atts)); 179: tabSet = StyleConstants.getTabSet(atts); 180: } 181: 182: /** 183: * Sets the indentation of the first line of the paragraph. 184: * 185: * @param i the indentation to set 186: */ 187: protected void setFirstLineIndent(float i) 188: { 189: firstLineIndent = (int) i; 190: } 191: 192: /** 193: * Sets the justification of the paragraph. 194: * 195: * @param j the justification to set 196: */ 197: protected void setJustification(int j) 198: { 199: justification = j; 200: } 201: 202: /** 203: * Sets the line spacing for this paragraph. 204: * 205: * @param s the line spacing to set 206: */ 207: protected void setLineSpacing(float s) 208: { 209: lineSpacing = s; 210: } 211: 212: /** 213: * Returns the i-th view from the logical views, before breaking into rows. 214: * 215: * @param i the index of the logical view to return 216: * 217: * @return the i-th view from the logical views, before breaking into rows 218: */ 219: protected View getLayoutView(int i) 220: { 221: return layoutPool.getView(i); 222: } 223: 224: /** 225: * Returns the number of logical child views. 226: * 227: * @return the number of logical child views 228: */ 229: protected int getLayoutViewCount() 230: { 231: return layoutPool.getViewCount(); 232: } 233: 234: /** 235: * Returns the TabSet used by this ParagraphView. 236: * 237: * @return the TabSet used by this ParagraphView 238: */ 239: protected TabSet getTabSet() 240: { 241: return tabSet; 242: } 243: 244: /** 245: * Finds the next offset in the document that has one of the characters 246: * specified in <code>string</code>. If there is no such character found, 247: * this returns -1. 248: * 249: * @param string the characters to search for 250: * @param start the start offset 251: * 252: * @return the next offset in the document that has one of the characters 253: * specified in <code>string</code> 254: */ 255: protected int findOffsetToCharactersInString(char[] string, int start) 256: { 257: int offset = -1; 258: Document doc = getDocument(); 259: Segment text = new Segment(); 260: try 261: { 262: doc.getText(start, doc.getLength() - start, text); 263: int index = start; 264: 265: searchLoop: 266: while (true) 267: { 268: char ch = text.next(); 269: if (ch == Segment.DONE) 270: break; 271: 272: for (int j = 0; j < string.length; ++j) 273: { 274: if (string[j] == ch) 275: { 276: offset = index; 277: break searchLoop; 278: } 279: } 280: index++; 281: } 282: } 283: catch (BadLocationException ex) 284: { 285: // Ignore this and return -1. 286: } 287: return offset; 288: } 289: 290: protected int getClosestPositionTo(int pos, Position.Bias bias, Shape a, 291: int direction, Position.Bias[] biasRet, 292: int rowIndex, int x) 293: throws BadLocationException 294: { 295: // FIXME: Implement this properly. However, this looks like it might 296: // have been replaced by viewToModel. 297: return pos; 298: } 299: 300: /** 301: * Returns the size that is used by this view (or it's child views) between 302: * <code>startOffset</code> and <code>endOffset</code>. If the child views 303: * implement the {@link TabableView} interface, then this is used to 304: * determine the span, otherwise we use the preferred span of the child 305: * views. 306: * 307: * @param startOffset the start offset 308: * @param endOffset the end offset 309: * 310: * @return the span used by the view between <code>startOffset</code> and 311: * <code>endOffset</cod> 312: */ 313: protected float getPartialSize(int startOffset, int endOffset) 314: { 315: int startIndex = getViewIndex(startOffset, Position.Bias.Backward); 316: int endIndex = getViewIndex(endOffset, Position.Bias.Forward); 317: float span; 318: if (startIndex == endIndex) 319: { 320: View child = getView(startIndex); 321: if (child instanceof TabableView) 322: { 323: TabableView tabable = (TabableView) child; 324: span = tabable.getPartialSpan(startOffset, endOffset); 325: } 326: else 327: span = child.getPreferredSpan(X_AXIS); 328: } 329: else if (endIndex - startIndex == 1) 330: { 331: View child1 = getView(startIndex); 332: if (child1 instanceof TabableView) 333: { 334: TabableView tabable = (TabableView) child1; 335: span = tabable.getPartialSpan(startOffset, child1.getEndOffset()); 336: } 337: else 338: span = child1.getPreferredSpan(X_AXIS); 339: View child2 = getView(endIndex); 340: if (child2 instanceof TabableView) 341: { 342: TabableView tabable = (TabableView) child2; 343: span += tabable.getPartialSpan(child2.getStartOffset(), endOffset); 344: } 345: else 346: span += child2.getPreferredSpan(X_AXIS); 347: } 348: else 349: { 350: // Start with the first view. 351: View child1 = getView(startIndex); 352: if (child1 instanceof TabableView) 353: { 354: TabableView tabable = (TabableView) child1; 355: span = tabable.getPartialSpan(startOffset, child1.getEndOffset()); 356: } 357: else 358: span = child1.getPreferredSpan(X_AXIS); 359: 360: // Add up the view spans between the start and the end view. 361: for (int i = startIndex + 1; i < endIndex; i++) 362: { 363: View child = getView(i); 364: span += child.getPreferredSpan(X_AXIS); 365: } 366: 367: // Add the span of the last view. 368: View child2 = getView(endIndex); 369: if (child2 instanceof TabableView) 370: { 371: TabableView tabable = (TabableView) child2; 372: span += tabable.getPartialSpan(child2.getStartOffset(), endOffset); 373: } 374: else 375: span += child2.getPreferredSpan(X_AXIS); 376: } 377: return span; 378: } 379: 380: /** 381: * Returns the location where the tabs are calculated from. This returns 382: * <code>0.0F</code> by default. 383: * 384: * @return the location where the tabs are calculated from 385: */ 386: protected float getTabBase() 387: { 388: return 0.0F; 389: } 390: 391: /** 392: * @specnote This method is specified to take a Row parameter, which is a 393: * private inner class of that class, which makes it unusable from 394: * application code. Also, this method seems to be replaced by 395: * {@link FlowStrategy#adjustRow(FlowView, int, int, int)}. 396: * 397: */ 398: protected void adjustRow(Row r, int desiredSpan, int x) 399: { 400: } 401: 402: /** 403: * @specnote This method's signature differs from the one defined in 404: * {@link View} and is therefore never called. It is probably there 405: * for historical reasons. 406: */ 407: public View breakView(int axis, float len, Shape a) 408: { 409: // This method is not used. 410: return null; 411: } 412: 413: /** 414: * @specnote This method's signature differs from the one defined in 415: * {@link View} and is therefore never called. It is probably there 416: * for historical reasons. 417: */ 418: public int getBreakWeight(int axis, float len) 419: { 420: // This method is not used. 421: return 0; 422: } 423: }