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