Showing the changes to java/pkg/javax/swing/text/View.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,1347 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2011, 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 | */ | ||
| 25 | package javax.swing.text; | ||
| 26 | |||
| 27 | import java.awt.*; | ||
| 28 | import javax.swing.SwingConstants; | ||
| 29 | import javax.swing.event.*; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * <p> | ||
| 33 | * A very important part of the text package is the <code>View</code> class. | ||
| 34 | * As the name suggests it represents a view of the text model, | ||
| 35 | * or a piece of the text model. | ||
| 36 | * It is this class that is responsible for the look of the text component. | ||
| 37 | * The view is not intended to be some completely new thing that one must | ||
| 38 | * learn, but rather is much like a lightweight component. | ||
| 39 | * <p> | ||
| 40 | By default, a view is very light. It contains a reference to the parent | ||
| 41 | view from which it can fetch many things without holding state, and it | ||
| 42 | contains a reference to a portion of the model (<code>Element</code>). | ||
| 43 | A view does not | ||
| 44 | have to exactly represent an element in the model, that is simply a typical | ||
| 45 | and therefore convenient mapping. A view can alternatively maintain a couple | ||
| 46 | of Position objects to maintain its location in the model (i.e. represent | ||
| 47 | a fragment of an element). This is typically the result of formatting where | ||
| 48 | views have been broken down into pieces. The convenience of a substantial | ||
| 49 | relationship to the element makes it easier to build factories to produce the | ||
| 50 | views, and makes it easier to keep track of the view pieces as the model is | ||
| 51 | changed and the view must be changed to reflect the model. Simple views | ||
| 52 | therefore represent an Element directly and complex views do not. | ||
| 53 | <p> | ||
| 54 | A view has the following responsibilities: | ||
| 55 | <dl> | ||
| 56 | |||
| 57 | <dt><b>Participate in layout.</b> | ||
| 58 | <dd> | ||
| 59 | <p>The view has a <code>setSize</code> method which is like | ||
| 60 | <code>doLayout</code> and <code>setSize</code> in <code>Component</code> combined. | ||
| 61 | The view has a <code>preferenceChanged</code> method which is | ||
| 62 | like <code>invalidate</code> in <code>Component</code> except that one can | ||
| 63 | invalidate just one axis | ||
| 64 | and the child requesting the change is identified. | ||
| 65 | <p>A View expresses the size that it would like to be in terms of three | ||
| 66 | values, a minimum, a preferred, and a maximum span. Layout in a view is | ||
| 67 | can be done independently upon each axis. For a properly functioning View | ||
| 68 | implementation, the minimum span will be <= the preferred span which in turn | ||
| 69 | will be <= the maximum span. | ||
| 70 | </p> | ||
| 71 | <p align=center><img src="doc-files/View-flexibility.jpg" | ||
| 72 | alt="The above text describes this graphic."> | ||
| 73 | <p>The minimum set of methods for layout are: | ||
| 74 | <ul> | ||
| 75 | <li><a href="#getMinimumSpan(int)">getMinimumSpan</a> | ||
| 76 | <li><a href="#getPreferredSpan(int)">getPreferredSpan</a> | ||
| 77 | <li><a href="#getMaximumSpan(int)">getMaximumSpan</a> | ||
| 78 | <li><a href="#getAlignment(int)">getAlignment</a> | ||
| 79 | <li><a href="#preferenceChanged(javax.swing.text.View, boolean, boolean)">preferenceChanged</a> | ||
| 80 | <li><a href="#setSize(float, float)">setSize</a> | ||
| 81 | </ul> | ||
| 82 | |||
| 83 | <p>The <code>setSize</code> method should be prepared to be called a number of times | ||
| 84 | (i.e. It may be called even if the size didn't change). | ||
| 85 | The <code>setSize</code> method | ||
| 86 | is generally called to make sure the View layout is complete prior to trying | ||
| 87 | to perform an operation on it that requires an up-to-date layout. A view's | ||
| 88 | size should <em>always</em> be set to a value within the minimum and maximum | ||
| 89 | span specified by that view. Additionally, the view must always call the | ||
| 90 | <code>preferenceChanged</code> method on the parent if it has changed the | ||
| 91 | values for the | ||
| 92 | layout it would like, and expects the parent to honor. The parent View is | ||
| 93 | not required to recognize a change until the <code>preferenceChanged</code> | ||
| 94 | has been sent. | ||
| 95 | This allows parent View implementations to cache the child requirements if | ||
| 96 | desired. The calling sequence looks something like the following: | ||
| 97 | </p> | ||
| 98 | <p align=center> | ||
| 99 | <img src="doc-files/View-layout.jpg" | ||
| 100 | alt="Sample calling sequence between parent view and child view: | ||
| 101 | setSize, getMinimum, getPreferred, getMaximum, getAlignment, setSize"> | ||
| 102 | <p>The exact calling sequence is up to the layout functionality of | ||
| 103 | the parent view (if the view has any children). The view may collect | ||
| 104 | the preferences of the children prior to determining what it will give | ||
| 105 | each child, or it might iteratively update the children one at a time. | ||
| 106 | </p> | ||
| 107 | |||
| 108 | <dt><b>Render a portion of the model.</b> | ||
| 109 | <dd> | ||
| 110 | <p>This is done in the paint method, which is pretty much like a component | ||
| 111 | paint method. Views are expected to potentially populate a fairly large | ||
| 112 | tree. A <code>View</code> has the following semantics for rendering: | ||
| 113 | </p> | ||
| 114 | <ul> | ||
| 115 | <li>The view gets its allocation from the parent at paint time, so it | ||
| 116 | must be prepared to redo layout if the allocated area is different from | ||
| 117 | what it is prepared to deal with. | ||
| 118 | <li>The coordinate system is the same as the hosting <code>Component</code> | ||
| 119 | (i.e. the <code>Component</code> returned by the | ||
| 120 | {@link #getContainer getContainer} method). | ||
| 121 | This means a child view lives in the same coordinate system as the parent | ||
| 122 | view unless the parent has explicitly changed the coordinate system. | ||
| 123 | To schedule itself to be repainted a view can call repaint on the hosting | ||
| 124 | <code>Component</code>. | ||
| 125 | <li>The default is to <em>not clip</em> the children. It is more efficient | ||
| 126 | to allow a view to clip only if it really feels it needs clipping. | ||
| 127 | <li>The <code>Graphics</code> object given is not initialized in any way. | ||
| 128 | A view should set any settings needed. | ||
| 129 | <li>A <code>View</code> is inherently transparent. While a view may render into its | ||
| 130 | entire allocation, typically a view does not. Rendering is performed by | ||
| 131 | tranversing down the tree of <code>View</code> implementations. | ||
| 132 | Each <code>View</code> is responsible | ||
| 133 | for rendering its children. This behavior is depended upon for thread | ||
| 134 | safety. While view implementations do not necessarily have to be implemented | ||
| 135 | with thread safety in mind, other view implementations that do make use of | ||
| 136 | concurrency can depend upon a tree traversal to guarantee thread safety. | ||
| 137 | <li>The order of views relative to the model is up to the implementation. | ||
| 138 | Although child views will typically be arranged in the same order that they | ||
| 139 | occur in the model, they may be visually arranged in an entirely different | ||
| 140 | order. View implementations may have Z-Order associated with them if the | ||
| 141 | children are overlapping. | ||
| 142 | </ul> | ||
| 143 | <p>The methods for rendering are: | ||
| 144 | <ul> | ||
| 145 | <li><a href="#paint(java.awt.Graphics, java.awt.Shape)">paint</a> | ||
| 146 | </ul> | ||
| 147 | <p> | ||
| 148 | |||
| 149 | <dt><b>Translate between the model and view coordinate systems.</b> | ||
| 150 | <dd> | ||
| 151 | <p>Because the view objects are produced from a factory and therefore cannot | ||
| 152 | necessarily be counted upon to be in a particular pattern, one must be able | ||
| 153 | to perform translation to properly locate spatial representation of the model. | ||
| 154 | The methods for doing this are: | ||
| 155 | <ul> | ||
| 156 | <li><a href="#modelToView(int, javax.swing.text.Position.Bias, int, javax.swing.text.Position.Bias, java.awt.Shape)">modelToView</a> | ||
| 157 | <li><a href="#viewToModel(float, float, java.awt.Shape, javax.swing.text.Position.Bias[])">viewToModel</a> | ||
| 158 | <li><a href="#getDocument()">getDocument</a> | ||
| 159 | <li><a href="#getElement()">getElement</a> | ||
| 160 | <li><a href="#getStartOffset()">getStartOffset</a> | ||
| 161 | <li><a href="#getEndOffset()">getEndOffset</a> | ||
| 162 | </ul> | ||
| 163 | <p>The layout must be valid prior to attempting to make the translation. | ||
| 164 | The translation is not valid, and must not be attempted while changes | ||
| 165 | are being broadcasted from the model via a <code>DocumentEvent</code>. | ||
| 166 | </p> | ||
| 167 | |||
| 168 | <dt><b>Respond to changes from the model.</b> | ||
| 169 | <dd> | ||
| 170 | <p>If the overall view is represented by many pieces (which is the best situation | ||
| 171 | if one want to be able to change the view and write the least amount of new code), | ||
| 172 | it would be impractical to have a huge number of <code>DocumentListener</code>s. | ||
| 173 | If each | ||
| 174 | view listened to the model, only a few would actually be interested in the | ||
| 175 | changes broadcasted at any given time. Since the model has no knowledge of | ||
| 176 | views, it has no way to filter the broadcast of change information. The view | ||
| 177 | hierarchy itself is instead responsible for propagating the change information. | ||
| 178 | At any level in the view hierarchy, that view knows enough about its children to | ||
| 179 | best distribute the change information further. Changes are therefore broadcasted | ||
| 180 | starting from the root of the view hierarchy. | ||
| 181 | The methods for doing this are: | ||
| 182 | <ul> | ||
| 183 | <li>{@link #insertUpdate insertUpdate} | ||
| 184 | <li>{@link #removeUpdate removeUpdate} | ||
| 185 | <li>{@link #changedUpdate changedUpdate} | ||
| 186 | </ul> | ||
| 187 | <p> | ||
| 188 | </dl> | ||
| 189 | * | ||
| 190 | * @author Timothy Prinzing | ||
| 191 | */ | ||
| 192 | public abstract class View implements SwingConstants { | ||
| 193 | |||
| 194 | /** | ||
| 195 | * Creates a new <code>View</code> object. | ||
| 196 | * | ||
| 197 | * @param elem the <code>Element</code> to represent | ||
| 198 | */ | ||
| 199 | public View(Element elem) { | ||
| 200 | this.elem = elem; | ||
| 201 | } | ||
| 202 | |||
| 203 | /** | ||
| 204 | * Returns the parent of the view. | ||
| 205 | * | ||
| 206 | * @return the parent, or <code>null</code> if none exists | ||
| 207 | */ | ||
| 208 | public View getParent() { | ||
| 209 | return parent; | ||
| 210 | } | ||
| 211 | |||
| 212 | /** | ||
| 213 | * Returns a boolean that indicates whether | ||
| 214 | * the view is visible or not. By default | ||
| 215 | * all views are visible. | ||
| 216 | * | ||
| 217 | * @return always returns true | ||
| 218 | */ | ||
| 219 | public boolean isVisible() { | ||
| 220 | return true; | ||
| 221 | } | ||
| 222 | |||
| 223 | |||
| 224 | /** | ||
| 225 | * Determines the preferred span for this view along an | ||
| 226 | * axis. | ||
| 227 | * | ||
| 228 | * @param axis may be either <code>View.X_AXIS</code> or | ||
| 229 | * <code>View.Y_AXIS</code> | ||
| 230 | * @return the span the view would like to be rendered into. | ||
| 231 | * Typically the view is told to render into the span | ||
| 232 | * that is returned, although there is no guarantee. | ||
| 233 | * The parent may choose to resize or break the view | ||
| 234 | * @see View#getPreferredSpan | ||
| 235 | */ | ||
| 236 | public abstract float getPreferredSpan(int axis); | ||
| 237 | |||
| 238 | /** | ||
| 239 | * Determines the minimum span for this view along an | ||
| 240 | * axis. | ||
| 241 | * | ||
| 242 | * @param axis may be either <code>View.X_AXIS</code> or | ||
| 243 | * <code>View.Y_AXIS</code> | ||
| 244 | * @return the minimum span the view can be rendered into | ||
| 245 | * @see View#getPreferredSpan | ||
| 246 | */ | ||
| 247 | public float getMinimumSpan(int axis) { | ||
| 248 | int w = getResizeWeight(axis); | ||
| 249 | if (w == 0) { | ||
| 250 | // can't resize | ||
| 251 | return getPreferredSpan(axis); | ||
| 252 | } | ||
| 253 | return 0; | ||
| 254 | } | ||
| 255 | |||
| 256 | /** | ||
| 257 | * Determines the maximum span for this view along an | ||
| 258 | * axis. | ||
| 259 | * | ||
| 260 | * @param axis may be either <code>View.X_AXIS</code> or | ||
| 261 | * <code>View.Y_AXIS</code> | ||
| 262 | * @return the maximum span the view can be rendered into | ||
| 263 | * @see View#getPreferredSpan | ||
| 264 | */ | ||
| 265 | public float getMaximumSpan(int axis) { | ||
| 266 | int w = getResizeWeight(axis); | ||
| 267 | if (w == 0) { | ||
| 268 | // can't resize | ||
| 269 | return getPreferredSpan(axis); | ||
| 270 | } | ||
| 271 | return Integer.MAX_VALUE; | ||
| 272 | } | ||
| 273 | |||
| 274 | /** | ||
| 275 | * Child views can call this on the parent to indicate that | ||
| 276 | * the preference has changed and should be reconsidered | ||
| 277 | * for layout. By default this just propagates upward to | ||
| 278 | * the next parent. The root view will call | ||
| 279 | * <code>revalidate</code> on the associated text component. | ||
| 280 | * | ||
| 281 | * @param child the child view | ||
| 282 | * @param width true if the width preference has changed | ||
| 283 | * @param height true if the height preference has changed | ||
| 284 | * @see javax.swing.JComponent#revalidate | ||
| 285 | */ | ||
| 286 | public void preferenceChanged(View child, boolean width, boolean height) { | ||
| 287 | View parent = getParent(); | ||
| 288 | if (parent != null) { | ||
| 289 | parent.preferenceChanged(this, width, height); | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | /** | ||
| 294 | * Determines the desired alignment for this view along an | ||
| 295 | * axis. The desired alignment is returned. This should be | ||
| 296 | * a value >= 0.0 and <= 1.0, where 0 indicates alignment at | ||
| 297 | * the origin and 1.0 indicates alignment to the full span | ||
| 298 | * away from the origin. An alignment of 0.5 would be the | ||
| 299 | * center of the view. | ||
| 300 | * | ||
| 301 | * @param axis may be either <code>View.X_AXIS</code> or | ||
| 302 | * <code>View.Y_AXIS</code> | ||
| 303 | * @return the value 0.5 | ||
| 304 | */ | ||
| 305 | public float getAlignment(int axis) { | ||
| 306 | return 0.5f; | ||
| 307 | } | ||
| 308 | |||
| 309 | /** | ||
| 310 | * Renders using the given rendering surface and area on that | ||
| 311 | * surface. The view may need to do layout and create child | ||
| 312 | * views to enable itself to render into the given allocation. | ||
| 313 | * | ||
| 314 | * @param g the rendering surface to use | ||
| 315 | * @param allocation the allocated region to render into | ||
| 316 | */ | ||
| 317 | public abstract void paint(Graphics g, Shape allocation); | ||
| 318 | |||
| 319 | /** | ||
| 320 | * Establishes the parent view for this view. This is | ||
| 321 | * guaranteed to be called before any other methods if the | ||
| 322 | * parent view is functioning properly. This is also | ||
| 323 | * the last method called, since it is called to indicate | ||
| 324 | * the view has been removed from the hierarchy as | ||
| 325 | * well. When this method is called to set the parent to | ||
| 326 | * null, this method does the same for each of its children, | ||
| 327 | * propogating the notification that they have been | ||
| 328 | * disconnected from the view tree. If this is | ||
| 329 | * reimplemented, <code>super.setParent()</code> should | ||
| 330 | * be called. | ||
| 331 | * | ||
| 332 | * @param parent the new parent, or <code>null</code> if the view is | ||
| 333 | * being removed from a parent | ||
| 334 | */ | ||
| 335 | public void setParent(View parent) { | ||
| 336 | // if the parent is null then propogate down the view tree | ||
| 337 | if (parent == null) { | ||
| 338 | for (int i = 0; i < getViewCount(); i++) { | ||
| 339 | if (getView(i).getParent() == this) { | ||
| 340 | // in FlowView.java view might be referenced | ||
| 341 | // from two super-views as a child. see logicalView | ||
| 342 | getView(i).setParent(null); | ||
| 343 | } | ||
| 344 | } | ||
| 345 | } | ||
| 346 | this.parent = parent; | ||
| 347 | } | ||
| 348 | |||
| 349 | /** | ||
| 350 | * Returns the number of views in this view. Since | ||
| 351 | * the default is to not be a composite view this | ||
| 352 | * returns 0. | ||
| 353 | * | ||
| 354 | * @return the number of views >= 0 | ||
| 355 | * @see View#getViewCount | ||
| 356 | */ | ||
| 357 | public int getViewCount() { | ||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * Gets the <i>n</i>th child view. Since there are no | ||
| 363 | * children by default, this returns <code>null</code>. | ||
| 364 | * | ||
| 365 | * @param n the number of the view to get, >= 0 && < getViewCount() | ||
| 366 | * @return the view | ||
| 367 | */ | ||
| 368 | public View getView(int n) { | ||
| 369 | return null; | ||
| 370 | } | ||
| 371 | |||
| 372 | |||
| 373 | /** | ||
| 374 | * Removes all of the children. This is a convenience | ||
| 375 | * call to <code>replace</code>. | ||
| 376 | * | ||
| 377 | * @since 1.3 | ||
| 378 | */ | ||
| 379 | public void removeAll() { | ||
| 380 | replace(0, getViewCount(), null); | ||
| 381 | } | ||
| 382 | |||
| 383 | /** | ||
| 384 | * Removes one of the children at the given position. | ||
| 385 | * This is a convenience call to <code>replace</code>. | ||
| 386 | * @since 1.3 | ||
| 387 | */ | ||
| 388 | public void remove(int i) { | ||
| 389 | replace(i, 1, null); | ||
| 390 | } | ||
| 391 | |||
| 392 | /** | ||
| 393 | * Inserts a single child view. This is a convenience | ||
| 394 | * call to <code>replace</code>. | ||
| 395 | * | ||
| 396 | * @param offs the offset of the view to insert before >= 0 | ||
| 397 | * @param v the view | ||
| 398 | * @see #replace | ||
| 399 | * @since 1.3 | ||
| 400 | */ | ||
| 401 | public void insert(int offs, View v) { | ||
| 402 | View[] one = new View[1]; | ||
| 403 | one[0] = v; | ||
| 404 | replace(offs, 0, one); | ||
| 405 | } | ||
| 406 | |||
| 407 | /** | ||
| 408 | * Appends a single child view. This is a convenience | ||
| 409 | * call to <code>replace</code>. | ||
| 410 | * | ||
| 411 | * @param v the view | ||
| 412 | * @see #replace | ||
| 413 | * @since 1.3 | ||
| 414 | */ | ||
| 415 | public void append(View v) { | ||
| 416 | View[] one = new View[1]; | ||
| 417 | one[0] = v; | ||
| 418 | replace(getViewCount(), 0, one); | ||
| 419 | } | ||
| 420 | |||
| 421 | /** | ||
| 422 | * Replaces child views. If there are no views to remove | ||
| 423 | * this acts as an insert. If there are no views to | ||
| 424 | * add this acts as a remove. Views being removed will | ||
| 425 | * have the parent set to <code>null</code>, and the internal reference | ||
| 426 | * to them removed so that they can be garbage collected. | ||
| 427 | * This is implemented to do nothing, because by default | ||
| 428 | * a view has no children. | ||
| 429 | * | ||
| 430 | * @param offset the starting index into the child views to insert | ||
| 431 | * the new views. This should be a value >= 0 and <= getViewCount | ||
| 432 | * @param length the number of existing child views to remove | ||
| 433 | * This should be a value >= 0 and <= (getViewCount() - offset). | ||
| 434 | * @param views the child views to add. This value can be | ||
| 435 | * <code>null</code> to indicate no children are being added | ||
| 436 | * (useful to remove). | ||
| 437 | * @since 1.3 | ||
| 438 | */ | ||
| 439 | public void replace(int offset, int length, View[] views) { | ||
| 440 | } | ||
| 441 | |||
| 442 | /** | ||
| 443 | * Returns the child view index representing the given position in | ||
| 444 | * the model. By default a view has no children so this is implemented | ||
| 445 | * to return -1 to indicate there is no valid child index for any | ||
| 446 | * position. | ||
| 447 | * | ||
| 448 | * @param pos the position >= 0 | ||
| 449 | * @return index of the view representing the given position, or | ||
| 450 | * -1 if no view represents that position | ||
| 451 | * @since 1.3 | ||
| 452 | */ | ||
| 453 | public int getViewIndex(int pos, Position.Bias b) { | ||
| 454 | return -1; | ||
| 455 | } | ||
| 456 | |||
| 457 | /** | ||
| 458 | * Fetches the allocation for the given child view. | ||
| 459 | * This enables finding out where various views | ||
| 460 | * are located, without assuming how the views store | ||
| 461 | * their location. This returns <code>null</code> since the | ||
| 462 | * default is to not have any child views. | ||
| 463 | * | ||
| 464 | * @param index the index of the child, >= 0 && < | ||
| 465 | * <code>getViewCount()</code> | ||
| 466 | * @param a the allocation to this view | ||
| 467 | * @return the allocation to the child | ||
| 468 | */ | ||
| 469 | public Shape getChildAllocation(int index, Shape a) { | ||
| 470 | return null; | ||
| 471 | } | ||
| 472 | |||
| 473 | /** | ||
| 474 | * Provides a way to determine the next visually represented model | ||
| 475 | * location at which one might place a caret. | ||
| 476 | * Some views may not be visible, | ||
| 477 | * they might not be in the same order found in the model, or they just | ||
| 478 | * might not allow access to some of the locations in the model. | ||
| 479 | * | ||
| 480 | * @param pos the position to convert >= 0 | ||
| 481 | * @param a the allocated region in which to render | ||
| 482 | * @param direction the direction from the current position that can | ||
| 483 | * be thought of as the arrow keys typically found on a keyboard. | ||
| 484 | * This will be one of the following values: | ||
| 485 | * <ul> | ||
| 486 | * <li>SwingConstants.WEST | ||
| 487 | * <li>SwingConstants.EAST | ||
| 488 | * <li>SwingConstants.NORTH | ||
| 489 | * <li>SwingConstants.SOUTH | ||
| 490 | * </ul> | ||
| 491 | * @return the location within the model that best represents the next | ||
| 492 | * location visual position | ||
| 493 | * @exception BadLocationException | ||
| 494 | * @exception IllegalArgumentException if <code>direction</code> | ||
| 495 | * doesn't have one of the legal values above | ||
| 496 | */ | ||
| 497 | public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, | ||
| 498 | int direction, Position.Bias[] biasRet) | ||
| 499 | throws BadLocationException { | ||
| 500 | if (pos < -1) { | ||
| 501 | // -1 is a reserved value, see the code below | ||
| 502 | throw new BadLocationException("Invalid position", pos); | ||
| 503 | } | ||
| 504 | |||
| 505 | biasRet[0] = Position.Bias.Forward; | ||
| 506 | switch (direction) { | ||
| 507 | case NORTH: | ||
| 508 | case SOUTH: | ||
| 509 | { | ||
| 510 | if (pos == -1) { | ||
| 511 | pos = (direction == NORTH) ? Math.max(0, getEndOffset() - 1) : | ||
| 512 | getStartOffset(); | ||
| 513 | break; | ||
| 514 | } | ||
| 515 | JTextComponent target = (JTextComponent) getContainer(); | ||
| 516 | Caret c = (target != null) ? target.getCaret() : null; | ||
| 517 | // YECK! Ideally, the x location from the magic caret position | ||
| 518 | // would be passed in. | ||
| 519 | Point mcp; | ||
| 520 | if (c != null) { | ||
| 521 | mcp = c.getMagicCaretPosition(); | ||
| 522 | } | ||
| 523 | else { | ||
| 524 | mcp = null; | ||
| 525 | } | ||
| 526 | int x; | ||
| 527 | if (mcp == null) { | ||
| 528 | Rectangle loc = target.modelToView(pos); | ||
| 529 | x = (loc == null) ? 0 : loc.x; | ||
| 530 | } | ||
| 531 | else { | ||
| 532 | x = mcp.x; | ||
| 533 | } | ||
| 534 | if (direction == NORTH) { | ||
| 535 | pos = Utilities.getPositionAbove(target, pos, x); | ||
| 536 | } | ||
| 537 | else { | ||
| 538 | pos = Utilities.getPositionBelow(target, pos, x); | ||
| 539 | } | ||
| 540 | } | ||
| 541 | break; | ||
| 542 | case WEST: | ||
| 543 | if(pos == -1) { | ||
| 544 | pos = Math.max(0, getEndOffset() - 1); | ||
| 545 | } | ||
| 546 | else { | ||
| 547 | pos = Math.max(0, pos - 1); | ||
| 548 | } | ||
| 549 | break; | ||
| 550 | case EAST: | ||
| 551 | if(pos == -1) { | ||
| 552 | pos = getStartOffset(); | ||
| 553 | } | ||
| 554 | else { | ||
| 555 | pos = Math.min(pos + 1, getDocument().getLength()); | ||
| 556 | } | ||
| 557 | break; | ||
| 558 | default: | ||
| 559 | throw new IllegalArgumentException("Bad direction: " + direction); | ||
| 560 | } | ||
| 561 | return pos; | ||
| 562 | } | ||
| 563 | |||
| 564 | /** | ||
| 565 | * Provides a mapping, for a given character, | ||
| 566 | * from the document model coordinate space | ||
| 567 | * to the view coordinate space. | ||
| 568 | * | ||
| 569 | * @param pos the position of the desired character (>=0) | ||
| 570 | * @param a the area of the view, which encompasses the requested character | ||
| 571 | * @param b the bias toward the previous character or the | ||
| 572 | * next character represented by the offset, in case the | ||
| 573 | * position is a boundary of two views; <code>b</code> will have one | ||
| 574 | * of these values: | ||
| 575 | * <ul> | ||
| 576 | * <li> <code>Position.Bias.Forward</code> | ||
| 577 | * <li> <code>Position.Bias.Backward</code> | ||
| 578 | * </ul> | ||
| 579 | * @return the bounding box, in view coordinate space, | ||
| 580 | * of the character at the specified position | ||
| 581 | * @exception BadLocationException if the specified position does | ||
| 582 | * not represent a valid location in the associated document | ||
| 583 | * @exception IllegalArgumentException if <code>b</code> is not one of the | ||
| 584 | * legal <code>Position.Bias</code> values listed above | ||
| 585 | * @see View#viewToModel | ||
| 586 | */ | ||
| 587 | public abstract Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException; | ||
| 588 | |||
| 589 | /** | ||
| 590 | * Provides a mapping, for a given region, | ||
| 591 | * from the document model coordinate space | ||
| 592 | * to the view coordinate space. The specified region is | ||
| 593 | * created as a union of the first and last character positions. | ||
| 594 | * | ||
| 595 | * @param p0 the position of the first character (>=0) | ||
| 596 | * @param b0 the bias of the first character position, | ||
| 597 | * toward the previous character or the | ||
| 598 | * next character represented by the offset, in case the | ||
| 599 | * position is a boundary of two views; <code>b0</code> will have one | ||
| 600 | * of these values: | ||
| 601 | * <ul> | ||
| 602 | * <li> <code>Position.Bias.Forward</code> | ||
| 603 | * <li> <code>Position.Bias.Backward</code> | ||
| 604 | * </ul> | ||
| 605 | * @param p1 the position of the last character (>=0) | ||
| 606 | * @param b1 the bias for the second character position, defined | ||
| 607 | * one of the legal values shown above | ||
| 608 | * @param a the area of the view, which encompasses the requested region | ||
| 609 | * @return the bounding box which is a union of the region specified | ||
| 610 | * by the first and last character positions | ||
| 611 | * @exception BadLocationException if the given position does | ||
| 612 | * not represent a valid location in the associated document | ||
| 613 | * @exception IllegalArgumentException if <code>b0</code> or | ||
| 614 | * <code>b1</code> are not one of the | ||
| 615 | * legal <code>Position.Bias</code> values listed above | ||
| 616 | * @see View#viewToModel | ||
| 617 | */ | ||
| 618 | public Shape modelToView(int p0, Position.Bias b0, int p1, Position.Bias b1, Shape a) throws BadLocationException { | ||
| 619 | Shape s0 = modelToView(p0, a, b0); | ||
| 620 | Shape s1; | ||
| 621 | if (p1 == getEndOffset()) { | ||
| 622 | try { | ||
| 623 | s1 = modelToView(p1, a, b1); | ||
| 624 | } catch (BadLocationException ble) { | ||
| 625 | s1 = null; | ||
| 626 | } | ||
| 627 | if (s1 == null) { | ||
| 628 | // Assume extends left to right. | ||
| 629 | Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : | ||
| 630 | a.getBounds(); | ||
| 631 | s1 = new Rectangle(alloc.x + alloc.width - 1, alloc.y, | ||
| 632 | 1, alloc.height); | ||
| 633 | } | ||
| 634 | } | ||
| 635 | else { | ||
| 636 | s1 = modelToView(p1, a, b1); | ||
| 637 | } | ||
| 638 | Rectangle r0 = s0.getBounds(); | ||
| 639 | Rectangle r1 = (s1 instanceof Rectangle) ? (Rectangle) s1 : | ||
| 640 | s1.getBounds(); | ||
| 641 | if (r0.y != r1.y) { | ||
| 642 | // If it spans lines, force it to be the width of the view. | ||
| 643 | Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : | ||
| 644 | a.getBounds(); | ||
| 645 | r0.x = alloc.x; | ||
| 646 | r0.width = alloc.width; | ||
| 647 | } | ||
| 648 | r0.add(r1); | ||
| 649 | return r0; | ||
| 650 | } | ||
| 651 | |||
| 652 | /** | ||
| 653 | * Provides a mapping from the view coordinate space to the logical | ||
| 654 | * coordinate space of the model. The <code>biasReturn</code> | ||
| 655 | * argument will be filled in to indicate that the point given is | ||
| 656 | * closer to the next character in the model or the previous | ||
| 657 | * character in the model. | ||
| 658 | * | ||
| 659 | * @param x the X coordinate >= 0 | ||
| 660 | * @param y the Y coordinate >= 0 | ||
| 661 | * @param a the allocated region in which to render | ||
| 662 | * @return the location within the model that best represents the | ||
| 663 | * given point in the view >= 0. The <code>biasReturn</code> | ||
| 664 | * argument will be | ||
| 665 | * filled in to indicate that the point given is closer to the next | ||
| 666 | * character in the model or the previous character in the model. | ||
| 667 | */ | ||
| 668 | public abstract int viewToModel(float x, float y, Shape a, Position.Bias[] biasReturn); | ||
| 669 | |||
| 670 | /** | ||
| 671 | * Gives notification that something was inserted into | ||
| 672 | * the document in a location that this view is responsible for. | ||
| 673 | * To reduce the burden to subclasses, this functionality is | ||
| 674 | * spread out into the following calls that subclasses can | ||
| 675 | * reimplement: | ||
| 676 | * <ol> | ||
| 677 | * <li>{@link #updateChildren updateChildren} is called | ||
| 678 | * if there were any changes to the element this view is | ||
| 679 | * responsible for. If this view has child views that are | ||
| 680 | * represent the child elements, then this method should do | ||
| 681 | * whatever is necessary to make sure the child views correctly | ||
| 682 | * represent the model. | ||
| 683 | * <li>{@link #forwardUpdate forwardUpdate} is called | ||
| 684 | * to forward the DocumentEvent to the appropriate child views. | ||
| 685 | * <li>{@link #updateLayout updateLayout} is called to | ||
| 686 | * give the view a chance to either repair its layout, to reschedule | ||
| 687 | * layout, or do nothing. | ||
| 688 | * </ol> | ||
| 689 | * | ||
| 690 | * @param e the change information from the associated document | ||
| 691 | * @param a the current allocation of the view | ||
| 692 | * @param f the factory to use to rebuild if the view has children | ||
| 693 | * @see View#insertUpdate | ||
| 694 | */ | ||
| 695 | public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) { | ||
| 696 | if (getViewCount() > 0) { | ||
| 697 | Element elem = getElement(); | ||
| 698 | DocumentEvent.ElementChange ec = e.getChange(elem); | ||
| 699 | if (ec != null) { | ||
| 700 | if (! updateChildren(ec, e, f)) { | ||
| 701 | // don't consider the element changes they | ||
| 702 | // are for a view further down. | ||
| 703 | ec = null; | ||
| 704 | } | ||
| 705 | } | ||
| 706 | forwardUpdate(ec, e, a, f); | ||
| 707 | updateLayout(ec, e, a); | ||
| 708 | } | ||
| 709 | } | ||
| 710 | |||
| 711 | /** | ||
| 712 | * Gives notification that something was removed from the document | ||
| 713 | * in a location that this view is responsible for. | ||
| 714 | * To reduce the burden to subclasses, this functionality is | ||
| 715 | * spread out into the following calls that subclasses can | ||
| 716 | * reimplement: | ||
| 717 | * <ol> | ||
| 718 | * <li>{@link #updateChildren updateChildren} is called | ||
| 719 | * if there were any changes to the element this view is | ||
| 720 | * responsible for. If this view has child views that are | ||
| 721 | * represent the child elements, then this method should do | ||
| 722 | * whatever is necessary to make sure the child views correctly | ||
| 723 | * represent the model. | ||
| 724 | * <li>{@link #forwardUpdate forwardUpdate} is called | ||
| 725 | * to forward the DocumentEvent to the appropriate child views. | ||
| 726 | * <li>{@link #updateLayout updateLayout} is called to | ||
| 727 | * give the view a chance to either repair its layout, to reschedule | ||
| 728 | * layout, or do nothing. | ||
| 729 | * </ol> | ||
| 730 | * | ||
| 731 | * @param e the change information from the associated document | ||
| 732 | * @param a the current allocation of the view | ||
| 733 | * @param f the factory to use to rebuild if the view has children | ||
| 734 | * @see View#removeUpdate | ||
| 735 | */ | ||
| 736 | public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) { | ||
| 737 | if (getViewCount() > 0) { | ||
| 738 | Element elem = getElement(); | ||
| 739 | DocumentEvent.ElementChange ec = e.getChange(elem); | ||
| 740 | if (ec != null) { | ||
| 741 | if (! updateChildren(ec, e, f)) { | ||
| 742 | // don't consider the element changes they | ||
| 743 | // are for a view further down. | ||
| 744 | ec = null; | ||
| 745 | } | ||
| 746 | } | ||
| 747 | forwardUpdate(ec, e, a, f); | ||
| 748 | updateLayout(ec, e, a); | ||
| 749 | } | ||
| 750 | } | ||
| 751 | |||
| 752 | /** | ||
| 753 | * Gives notification from the document that attributes were changed | ||
| 754 | * in a location that this view is responsible for. | ||
| 755 | * To reduce the burden to subclasses, this functionality is | ||
| 756 | * spread out into the following calls that subclasses can | ||
| 757 | * reimplement: | ||
| 758 | * <ol> | ||
| 759 | * <li>{@link #updateChildren updateChildren} is called | ||
| 760 | * if there were any changes to the element this view is | ||
| 761 | * responsible for. If this view has child views that are | ||
| 762 | * represent the child elements, then this method should do | ||
| 763 | * whatever is necessary to make sure the child views correctly | ||
| 764 | * represent the model. | ||
| 765 | * <li>{@link #forwardUpdate forwardUpdate} is called | ||
| 766 | * to forward the DocumentEvent to the appropriate child views. | ||
| 767 | * <li>{@link #updateLayout updateLayout} is called to | ||
| 768 | * give the view a chance to either repair its layout, to reschedule | ||
| 769 | * layout, or do nothing. | ||
| 770 | * </ol> | ||
| 771 | * | ||
| 772 | * @param e the change information from the associated document | ||
| 773 | * @param a the current allocation of the view | ||
| 774 | * @param f the factory to use to rebuild if the view has children | ||
| 775 | * @see View#changedUpdate | ||
| 776 | */ | ||
| 777 | public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) { | ||
| 778 | if (getViewCount() > 0) { | ||
| 779 | Element elem = getElement(); | ||
| 780 | DocumentEvent.ElementChange ec = e.getChange(elem); | ||
| 781 | if (ec != null) { | ||
| 782 | if (! updateChildren(ec, e, f)) { | ||
| 783 | // don't consider the element changes they | ||
| 784 | // are for a view further down. | ||
| 785 | ec = null; | ||
| 786 | } | ||
| 787 | } | ||
| 788 | forwardUpdate(ec, e, a, f); | ||
| 789 | updateLayout(ec, e, a); | ||
| 790 | } | ||
| 791 | } | ||
| 792 | |||
| 793 | /** | ||
| 794 | * Fetches the model associated with the view. | ||
| 795 | * | ||
| 796 | * @return the view model, <code>null</code> if none | ||
| 797 | * @see View#getDocument | ||
| 798 | */ | ||
| 799 | public Document getDocument() { | ||
| 800 | return elem.getDocument(); | ||
| 801 | } | ||
| 802 | |||
| 803 | /** | ||
| 804 | * Fetches the portion of the model for which this view is | ||
| 805 | * responsible. | ||
| 806 | * | ||
| 807 | * @return the starting offset into the model >= 0 | ||
| 808 | * @see View#getStartOffset | ||
| 809 | */ | ||
| 810 | public int getStartOffset() { | ||
| 811 | return elem.getStartOffset(); | ||
| 812 | } | ||
| 813 | |||
| 814 | /** | ||
| 815 | * Fetches the portion of the model for which this view is | ||
| 816 | * responsible. | ||
| 817 | * | ||
| 818 | * @return the ending offset into the model >= 0 | ||
| 819 | * @see View#getEndOffset | ||
| 820 | */ | ||
| 821 | public int getEndOffset() { | ||
| 822 | return elem.getEndOffset(); | ||
| 823 | } | ||
| 824 | |||
| 825 | /** | ||
| 826 | * Fetches the structural portion of the subject that this | ||
| 827 | * view is mapped to. The view may not be responsible for the | ||
| 828 | * entire portion of the element. | ||
| 829 | * | ||
| 830 | * @return the subject | ||
| 831 | * @see View#getElement | ||
| 832 | */ | ||
| 833 | public Element getElement() { | ||
| 834 | return elem; | ||
| 835 | } | ||
| 836 | |||
| 837 | /** | ||
| 838 | * Fetch a <code>Graphics</code> for rendering. | ||
| 839 | * This can be used to determine | ||
| 840 | * font characteristics, and will be different for a print view | ||
| 841 | * than a component view. | ||
| 842 | * | ||
| 843 | * @return a <code>Graphics</code> object for rendering | ||
| 844 | * @since 1.3 | ||
| 845 | */ | ||
| 846 | public Graphics getGraphics() { | ||
| 847 | // PENDING(prinz) this is a temporary implementation | ||
| 848 | Component c = getContainer(); | ||
| 849 | return c.getGraphics(); | ||
| 850 | } | ||
| 851 | |||
| 852 | /** | ||
| 853 | * Fetches the attributes to use when rendering. By default | ||
| 854 | * this simply returns the attributes of the associated element. | ||
| 855 | * This method should be used rather than using the element | ||
| 856 | * directly to obtain access to the attributes to allow | ||
| 857 | * view-specific attributes to be mixed in or to allow the | ||
| 858 | * view to have view-specific conversion of attributes by | ||
| 859 | * subclasses. | ||
| 860 | * Each view should document what attributes it recognizes | ||
| 861 | * for the purpose of rendering or layout, and should always | ||
| 862 | * access them through the <code>AttributeSet</code> returned | ||
| 863 | * by this method. | ||
| 864 | */ | ||
| 865 | public AttributeSet getAttributes() { | ||
| 866 | return elem.getAttributes(); | ||
| 867 | } | ||
| 868 | |||
| 869 | /** | ||
| 870 | * Tries to break this view on the given axis. This is | ||
| 871 | * called by views that try to do formatting of their | ||
| 872 | * children. For example, a view of a paragraph will | ||
| 873 | * typically try to place its children into row and | ||
| 874 | * views representing chunks of text can sometimes be | ||
| 875 | * broken down into smaller pieces. | ||
| 876 | * <p> | ||
| 877 | * This is implemented to return the view itself, which | ||
| 878 | * represents the default behavior on not being | ||
| 879 | * breakable. If the view does support breaking, the | ||
| 880 | * starting offset of the view returned should be the | ||
| 881 | * given offset, and the end offset should be less than | ||
| 882 | * or equal to the end offset of the view being broken. | ||
| 883 | * | ||
| 884 | * @param axis may be either <code>View.X_AXIS</code> or | ||
| 885 | * <code>View.Y_AXIS</code> | ||
| 886 | * @param offset the location in the document model | ||
| 887 | * that a broken fragment would occupy >= 0. This | ||
| 888 | * would be the starting offset of the fragment | ||
| 889 | * returned | ||
| 890 | * @param pos the position along the axis that the | ||
| 891 | * broken view would occupy >= 0. This may be useful for | ||
| 892 | * things like tab calculations | ||
| 893 | * @param len specifies the distance along the axis | ||
| 894 | * where a potential break is desired >= 0 | ||
| 895 | * @return the fragment of the view that represents the | ||
| 896 | * given span, if the view can be broken. If the view | ||
| 897 | * doesn't support breaking behavior, the view itself is | ||
| 898 | * returned. | ||
| 899 | * @see ParagraphView | ||
| 900 | */ | ||
| 901 | public View breakView(int axis, int offset, float pos, float len) { | ||
| 902 | return this; | ||
| 903 | } | ||
| 904 | |||
| 905 | /** | ||
| 906 | * Creates a view that represents a portion of the element. | ||
| 907 | * This is potentially useful during formatting operations | ||
| 908 | * for taking measurements of fragments of the view. If | ||
| 909 | * the view doesn't support fragmenting (the default), it | ||
| 910 | * should return itself. | ||
| 911 | * | ||
| 912 | * @param p0 the starting offset >= 0. This should be a value | ||
| 913 | * greater or equal to the element starting offset and | ||
| 914 | * less than the element ending offset. | ||
| 915 | * @param p1 the ending offset > p0. This should be a value | ||
| 916 | * less than or equal to the elements end offset and | ||
| 917 | * greater than the elements starting offset. | ||
| 918 | * @return the view fragment, or itself if the view doesn't | ||
| 919 | * support breaking into fragments | ||
| 920 | * @see LabelView | ||
| 921 | */ | ||
| 922 | public View createFragment(int p0, int p1) { | ||
| 923 | return this; | ||
| 924 | } | ||
| 925 | |||
| 926 | /** | ||
| 927 | * Determines how attractive a break opportunity in | ||
| 928 | * this view is. This can be used for determining which | ||
| 929 | * view is the most attractive to call <code>breakView</code> | ||
| 930 | * on in the process of formatting. A view that represents | ||
| 931 | * text that has whitespace in it might be more attractive | ||
| 932 | * than a view that has no whitespace, for example. The | ||
| 933 | * higher the weight, the more attractive the break. A | ||
| 934 | * value equal to or lower than <code>BadBreakWeight</code> | ||
| 935 | * should not be considered for a break. A value greater | ||
| 936 | * than or equal to <code>ForcedBreakWeight</code> should | ||
| 937 | * be broken. | ||
| 938 | * <p> | ||
| 939 | * This is implemented to provide the default behavior | ||
| 940 | * of returning <code>BadBreakWeight</code> unless the length | ||
| 941 | * is greater than the length of the view in which case the | ||
| 942 | * entire view represents the fragment. Unless a view has | ||
| 943 | * been written to support breaking behavior, it is not | ||
| 944 | * attractive to try and break the view. An example of | ||
| 945 | * a view that does support breaking is <code>LabelView</code>. | ||
| 946 | * An example of a view that uses break weight is | ||
| 947 | * <code>ParagraphView</code>. | ||
| 948 | * | ||
| 949 | * @param axis may be either <code>View.X_AXIS</code> or | ||
| 950 | * <code>View.Y_AXIS</code> | ||
| 951 | * @param pos the potential location of the start of the | ||
| 952 | * broken view >= 0. This may be useful for calculating tab | ||
| 953 | * positions | ||
| 954 | * @param len specifies the relative length from <em>pos</em> | ||
| 955 | * where a potential break is desired >= 0 | ||
| 956 | * @return the weight, which should be a value between | ||
| 957 | * ForcedBreakWeight and BadBreakWeight | ||
| 958 | * @see LabelView | ||
| 959 | * @see ParagraphView | ||
| 960 | * @see #BadBreakWeight | ||
| 961 | * @see #GoodBreakWeight | ||
| 962 | * @see #ExcellentBreakWeight | ||
| 963 | * @see #ForcedBreakWeight | ||
| 964 | */ | ||
| 965 | public int getBreakWeight(int axis, float pos, float len) { | ||
| 966 | if (len > getPreferredSpan(axis)) { | ||
| 967 | return GoodBreakWeight; | ||
| 968 | } | ||
| 969 | return BadBreakWeight; | ||
| 970 | } | ||
| 971 | |||
| 972 | /** | ||
| 973 | * Determines the resizability of the view along the | ||
| 974 | * given axis. A value of 0 or less is not resizable. | ||
| 975 | * | ||
| 976 | * @param axis may be either <code>View.X_AXIS</code> or | ||
| 977 | * <code>View.Y_AXIS</code> | ||
| 978 | * @return the weight | ||
| 979 | */ | ||
| 980 | public int getResizeWeight(int axis) { | ||
| 981 | return 0; | ||
| 982 | } | ||
| 983 | |||
| 984 | /** | ||
| 985 | * Sets the size of the view. This should cause | ||
| 986 | * layout of the view along the given axis, if it | ||
| 987 | * has any layout duties. | ||
| 988 | * | ||
| 989 | * @param width the width >= 0 | ||
| 990 | * @param height the height >= 0 | ||
| 991 | */ | ||
| 992 | public void setSize(float width, float height) { | ||
| 993 | } | ||
| 994 | |||
| 995 | /** | ||
| 996 | * Fetches the container hosting the view. This is useful for | ||
| 997 | * things like scheduling a repaint, finding out the host | ||
| 998 | * components font, etc. The default implementation | ||
| 999 | * of this is to forward the query to the parent view. | ||
| 1000 | * | ||
| 1001 | * @return the container, <code>null</code> if none | ||
| 1002 | */ | ||
| 1003 | public Container getContainer() { | ||
| 1004 | View v = getParent(); | ||
| 1005 | return (v != null) ? v.getContainer() : null; | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | /** | ||
| 1009 | * Fetches the <code>ViewFactory</code> implementation that is feeding | ||
| 1010 | * the view hierarchy. Normally the views are given this | ||
| 1011 | * as an argument to updates from the model when they | ||
| 1012 | * are most likely to need the factory, but this | ||
| 1013 | * method serves to provide it at other times. | ||
| 1014 | * | ||
| 1015 | * @return the factory, <code>null</code> if none | ||
| 1016 | */ | ||
| 1017 | public ViewFactory getViewFactory() { | ||
| 1018 | View v = getParent(); | ||
| 1019 | return (v != null) ? v.getViewFactory() : null; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | /** | ||
| 1023 | * Returns the tooltip text at the specified location. The default | ||
| 1024 | * implementation returns the value from the child View identified by | ||
| 1025 | * the passed in location. | ||
| 1026 | * | ||
| 1027 | * @since 1.4 | ||
| 1028 | * @see JTextComponent#getToolTipText | ||
| 1029 | */ | ||
| 1030 | public String getToolTipText(float x, float y, Shape allocation) { | ||
| 1031 | int viewIndex = getViewIndex(x, y, allocation); | ||
| 1032 | if (viewIndex >= 0) { | ||
| 1033 | allocation = getChildAllocation(viewIndex, allocation); | ||
| 1034 | Rectangle rect = (allocation instanceof Rectangle) ? | ||
| 1035 | (Rectangle)allocation : allocation.getBounds(); | ||
| 1036 | if (rect.contains(x, y)) { | ||
| 1037 | return getView(viewIndex).getToolTipText(x, y, allocation); | ||
| 1038 | } | ||
| 1039 | } | ||
| 1040 | return null; | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | /** | ||
| 1044 | * Returns the child view index representing the given position in | ||
| 1045 | * the view. This iterates over all the children returning the | ||
| 1046 | * first with a bounds that contains <code>x</code>, <code>y</code>. | ||
| 1047 | * | ||
| 1048 | * @param x the x coordinate | ||
| 1049 | * @param y the y coordinate | ||
| 1050 | * @param allocation current allocation of the View. | ||
| 1051 | * @return index of the view representing the given location, or | ||
| 1052 | * -1 if no view represents that position | ||
| 1053 | * @since 1.4 | ||
| 1054 | */ | ||
| 1055 | public int getViewIndex(float x, float y, Shape allocation) { | ||
| 1056 | for (int counter = getViewCount() - 1; counter >= 0; counter--) { | ||
| 1057 | Shape childAllocation = getChildAllocation(counter, allocation); | ||
| 1058 | |||
| 1059 | if (childAllocation != null) { | ||
| 1060 | Rectangle rect = (childAllocation instanceof Rectangle) ? | ||
| 1061 | (Rectangle)childAllocation : childAllocation.getBounds(); | ||
| 1062 | |||
| 1063 | if (rect.contains(x, y)) { | ||
| 1064 | return counter; | ||
| 1065 | } | ||
| 1066 | } | ||
| 1067 | } | ||
| 1068 | return -1; | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | /** | ||
| 1072 | * Updates the child views in response to receiving notification | ||
| 1073 | * that the model changed, and there is change record for the | ||
| 1074 | * element this view is responsible for. This is implemented | ||
| 1075 | * to assume the child views are directly responsible for the | ||
| 1076 | * child elements of the element this view represents. The | ||
| 1077 | * <code>ViewFactory</code> is used to create child views for each element | ||
| 1078 | * specified as added in the <code>ElementChange</code>, starting at the | ||
| 1079 | * index specified in the given <code>ElementChange</code>. The number of | ||
| 1080 | * child views representing the removed elements specified are | ||
| 1081 | * removed. | ||
| 1082 | * | ||
| 1083 | * @param ec the change information for the element this view | ||
| 1084 | * is responsible for. This should not be <code>null</code> if | ||
| 1085 | * this method gets called | ||
| 1086 | * @param e the change information from the associated document | ||
| 1087 | * @param f the factory to use to build child views | ||
| 1088 | * @return whether or not the child views represent the | ||
| 1089 | * child elements of the element this view is responsible | ||
| 1090 | * for. Some views create children that represent a portion | ||
| 1091 | * of the element they are responsible for, and should return | ||
| 1092 | * false. This information is used to determine if views | ||
| 1093 | * in the range of the added elements should be forwarded to | ||
| 1094 | * or not | ||
| 1095 | * @see #insertUpdate | ||
| 1096 | * @see #removeUpdate | ||
| 1097 | * @see #changedUpdate | ||
| 1098 | * @since 1.3 | ||
| 1099 | */ | ||
| 1100 | protected boolean updateChildren(DocumentEvent.ElementChange ec, | ||
| 1101 | DocumentEvent e, ViewFactory f) { | ||
| 1102 | Element[] removedElems = ec.getChildrenRemoved(); | ||
| 1103 | Element[] addedElems = ec.getChildrenAdded(); | ||
| 1104 | View[] added = null; | ||
| 1105 | if (addedElems != null) { | ||
| 1106 | added = new View[addedElems.length]; | ||
| 1107 | for (int i = 0; i < addedElems.length; i++) { | ||
| 1108 | added[i] = f.create(addedElems[i]); | ||
| 1109 | } | ||
| 1110 | } | ||
| 1111 | int nremoved = 0; | ||
| 1112 | int index = ec.getIndex(); | ||
| 1113 | if (removedElems != null) { | ||
| 1114 | nremoved = removedElems.length; | ||
| 1115 | } | ||
| 1116 | replace(index, nremoved, added); | ||
| 1117 | return true; | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | /** | ||
| 1121 | * Forwards the given <code>DocumentEvent</code> to the child views | ||
| 1122 | * that need to be notified of the change to the model. | ||
| 1123 | * If there were changes to the element this view is | ||
| 1124 | * responsible for, that should be considered when | ||
| 1125 | * forwarding (i.e. new child views should not get | ||
| 1126 | * notified). | ||
| 1127 | * | ||
| 1128 | * @param ec changes to the element this view is responsible | ||
| 1129 | * for (may be <code>null</code> if there were no changes). | ||
| 1130 | * @param e the change information from the associated document | ||
| 1131 | * @param a the current allocation of the view | ||
| 1132 | * @param f the factory to use to rebuild if the view has children | ||
| 1133 | * @see #insertUpdate | ||
| 1134 | * @see #removeUpdate | ||
| 1135 | * @see #changedUpdate | ||
| 1136 | * @since 1.3 | ||
| 1137 | */ | ||
| 1138 | protected void forwardUpdate(DocumentEvent.ElementChange ec, | ||
| 1139 | DocumentEvent e, Shape a, ViewFactory f) { | ||
| 1140 | Element elem = getElement(); | ||
| 1141 | int pos = e.getOffset(); | ||
| 1142 | int index0 = getViewIndex(pos, Position.Bias.Forward); | ||
| 1143 | if (index0 == -1 && e.getType() == DocumentEvent.EventType.REMOVE && | ||
| 1144 | pos >= getEndOffset()) { | ||
| 1145 | // Event beyond our offsets. We may have represented this, that is | ||
| 1146 | // the remove may have removed one of our child Elements that | ||
| 1147 | // represented this, so, we should foward to last element. | ||
| 1148 | index0 = getViewCount() - 1; | ||
| 1149 | } | ||
| 1150 | int index1 = index0; | ||
| 1151 | View v = (index0 >= 0) ? getView(index0) : null; | ||
| 1152 | if (v != null) { | ||
| 1153 | if ((v.getStartOffset() == pos) && (pos > 0)) { | ||
| 1154 | // If v is at a boundary, forward the event to the previous | ||
| 1155 | // view too. | ||
| 1156 | index0 = Math.max(index0 - 1, 0); | ||
| 1157 | } | ||
| 1158 | } | ||
| 1159 | if (e.getType() != DocumentEvent.EventType.REMOVE) { | ||
| 1160 | index1 = getViewIndex(pos + e.getLength(), Position.Bias.Forward); | ||
| 1161 | if (index1 < 0) { | ||
| 1162 | index1 = getViewCount() - 1; | ||
| 1163 | } | ||
| 1164 | } | ||
| 1165 | int hole0 = index1 + 1; | ||
| 1166 | int hole1 = hole0; | ||
| 1167 | Element[] addedElems = (ec != null) ? ec.getChildrenAdded() : null; | ||
| 1168 | if ((addedElems != null) && (addedElems.length > 0)) { | ||
| 1169 | hole0 = ec.getIndex(); | ||
| 1170 | hole1 = hole0 + addedElems.length - 1; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | // forward to any view not in the forwarding hole | ||
| 1174 | // formed by added elements (i.e. they will be updated | ||
| 1175 | // by initialization. | ||
| 1176 | index0 = Math.max(index0, 0); | ||
| 1177 | for (int i = index0; i <= index1; i++) { | ||
| 1178 | if (! ((i >= hole0) && (i <= hole1))) { | ||
| 1179 | v = getView(i); | ||
| 1180 | if (v != null) { | ||
| 1181 | Shape childAlloc = getChildAllocation(i, a); | ||
| 1182 | forwardUpdateToView(v, e, childAlloc, f); | ||
| 1183 | } | ||
| 1184 | } | ||
| 1185 | } | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | /** | ||
| 1189 | * Forwards the <code>DocumentEvent</code> to the give child view. This | ||
| 1190 | * simply messages the view with a call to <code>insertUpdate</code>, | ||
| 1191 | * <code>removeUpdate</code>, or <code>changedUpdate</code> depending | ||
| 1192 | * upon the type of the event. This is called by | ||
| 1193 | * {@link #forwardUpdate forwardUpdate} to forward | ||
| 1194 | * the event to children that need it. | ||
| 1195 | * | ||
| 1196 | * @param v the child view to forward the event to | ||
| 1197 | * @param e the change information from the associated document | ||
| 1198 | * @param a the current allocation of the view | ||
| 1199 | * @param f the factory to use to rebuild if the view has children | ||
| 1200 | * @see #forwardUpdate | ||
| 1201 | * @since 1.3 | ||
| 1202 | */ | ||
| 1203 | protected void forwardUpdateToView(View v, DocumentEvent e, | ||
| 1204 | Shape a, ViewFactory f) { | ||
| 1205 | DocumentEvent.EventType type = e.getType(); | ||
| 1206 | if (type == DocumentEvent.EventType.INSERT) { | ||
| 1207 | v.insertUpdate(e, a, f); | ||
| 1208 | } else if (type == DocumentEvent.EventType.REMOVE) { | ||
| 1209 | v.removeUpdate(e, a, f); | ||
| 1210 | } else { | ||
| 1211 | v.changedUpdate(e, a, f); | ||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | /** | ||
| 1216 | * Updates the layout in response to receiving notification of | ||
| 1217 | * change from the model. This is implemented to call | ||
| 1218 | * <code>preferenceChanged</code> to reschedule a new layout | ||
| 1219 | * if the <code>ElementChange</code> record is not <code>null</code>. | ||
| 1220 | * | ||
| 1221 | * @param ec changes to the element this view is responsible | ||
| 1222 | * for (may be <code>null</code> if there were no changes) | ||
| 1223 | * @param e the change information from the associated document | ||
| 1224 | * @param a the current allocation of the view | ||
| 1225 | * @see #insertUpdate | ||
| 1226 | * @see #removeUpdate | ||
| 1227 | * @see #changedUpdate | ||
| 1228 | * @since 1.3 | ||
| 1229 | */ | ||
| 1230 | protected void updateLayout(DocumentEvent.ElementChange ec, | ||
| 1231 | DocumentEvent e, Shape a) { | ||
| 1232 | if ((ec != null) && (a != null)) { | ||
| 1233 | // should damage more intelligently | ||
| 1234 | preferenceChanged(null, true, true); | ||
| 1235 | Container host = getContainer(); | ||
| 1236 | if (host != null) { | ||
| 1237 | host.repaint(); | ||
| 1238 | } | ||
| 1239 | } | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | /** | ||
| 1243 | * The weight to indicate a view is a bad break | ||
| 1244 | * opportunity for the purpose of formatting. This | ||
| 1245 | * value indicates that no attempt should be made to | ||
| 1246 | * break the view into fragments as the view has | ||
| 1247 | * not been written to support fragmenting. | ||
| 1248 | * | ||
| 1249 | * @see #getBreakWeight | ||
| 1250 | * @see #GoodBreakWeight | ||
| 1251 | * @see #ExcellentBreakWeight | ||
| 1252 | * @see #ForcedBreakWeight | ||
| 1253 | */ | ||
| 1254 | public static final int BadBreakWeight = 0; | ||
| 1255 | |||
| 1256 | /** | ||
| 1257 | * The weight to indicate a view supports breaking, | ||
| 1258 | * but better opportunities probably exist. | ||
| 1259 | * | ||
| 1260 | * @see #getBreakWeight | ||
| 1261 | * @see #BadBreakWeight | ||
| 1262 | * @see #ExcellentBreakWeight | ||
| 1263 | * @see #ForcedBreakWeight | ||
| 1264 | */ | ||
| 1265 | public static final int GoodBreakWeight = 1000; | ||
| 1266 | |||
| 1267 | /** | ||
| 1268 | * The weight to indicate a view supports breaking, | ||
| 1269 | * and this represents a very attractive place to | ||
| 1270 | * break. | ||
| 1271 | * | ||
| 1272 | * @see #getBreakWeight | ||
| 1273 | * @see #BadBreakWeight | ||
| 1274 | * @see #GoodBreakWeight | ||
| 1275 | * @see #ForcedBreakWeight | ||
| 1276 | */ | ||
| 1277 | public static final int ExcellentBreakWeight = 2000; | ||
| 1278 | |||
| 1279 | /** | ||
| 1280 | * The weight to indicate a view supports breaking, | ||
| 1281 | * and must be broken to be represented properly | ||
| 1282 | * when placed in a view that formats its children | ||
| 1283 | * by breaking them. | ||
| 1284 | * | ||
| 1285 | * @see #getBreakWeight | ||
| 1286 | * @see #BadBreakWeight | ||
| 1287 | * @see #GoodBreakWeight | ||
| 1288 | * @see #ExcellentBreakWeight | ||
| 1289 | */ | ||
| 1290 | public static final int ForcedBreakWeight = 3000; | ||
| 1291 | |||
| 1292 | /** | ||
| 1293 | * Axis for format/break operations. | ||
| 1294 | */ | ||
| 1295 | public static final int X_AXIS = HORIZONTAL; | ||
| 1296 | |||
| 1297 | /** | ||
| 1298 | * Axis for format/break operations. | ||
| 1299 | */ | ||
| 1300 | public static final int Y_AXIS = VERTICAL; | ||
| 1301 | |||
| 1302 | /** | ||
| 1303 | * Provides a mapping from the document model coordinate space | ||
| 1304 | * to the coordinate space of the view mapped to it. This is | ||
| 1305 | * implemented to default the bias to <code>Position.Bias.Forward</code> | ||
| 1306 | * which was previously implied. | ||
| 1307 | * | ||
| 1308 | * @param pos the position to convert >= 0 | ||
| 1309 | * @param a the allocated region in which to render | ||
| 1310 | * @return the bounding box of the given position is returned | ||
| 1311 | * @exception BadLocationException if the given position does | ||
| 1312 | * not represent a valid location in the associated document | ||
| 1313 | * @see View#modelToView | ||
| 1314 | * @deprecated | ||
| 1315 | */ | ||
| 1316 | @Deprecated | ||
| 1317 | public Shape modelToView(int pos, Shape a) throws BadLocationException { | ||
| 1318 | return modelToView(pos, a, Position.Bias.Forward); | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | |||
| 1322 | /** | ||
| 1323 | * Provides a mapping from the view coordinate space to the logical | ||
| 1324 | * coordinate space of the model. | ||
| 1325 | * | ||
| 1326 | * @param x the X coordinate >= 0 | ||
| 1327 | * @param y the Y coordinate >= 0 | ||
| 1328 | * @param a the allocated region in which to render | ||
| 1329 | * @return the location within the model that best represents the | ||
| 1330 | * given point in the view >= 0 | ||
| 1331 | * @see View#viewToModel | ||
| 1332 | * @deprecated | ||
| 1333 | */ | ||
| 1334 | @Deprecated | ||
| 1335 | public int viewToModel(float x, float y, Shape a) { | ||
| 1336 | sharedBiasReturn[0] = Position.Bias.Forward; | ||
| 1337 | return viewToModel(x, y, a, sharedBiasReturn); | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | // static argument available for viewToModel calls since only | ||
| 1341 | // one thread at a time may call this method. | ||
| 1342 | static final Position.Bias[] sharedBiasReturn = new Position.Bias[1]; | ||
| 1343 | |||
| 1344 | private View parent; | ||
| 1345 | private Element elem; | ||
| 1346 | |||
| 1347 | }; | ||