1. /*
  2. * @(#)CompositeView.java 1.67 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.text;
  8. import java.util.Vector;
  9. import java.awt.*;
  10. import javax.swing.event.*;
  11. import javax.swing.SwingConstants;
  12. /**
  13. * <code>CompositeView</code> is an abstract <code>View</code>
  14. * implementation which manages one or more child views.
  15. * (Note that <code>CompositeView</code> is intended
  16. * for managing relatively small numbers of child views.)
  17. * <code>CompositeView</code> is intended to be used as
  18. * a starting point for <code>View</code> implementations,
  19. * such as <code>BoxView</code>, that will contain child
  20. * <code>View</code>s. Subclasses that wish to manage the
  21. * collection of child <code>View</code>s should use the
  22. * {@link #replace} method. As <code>View</code> invokes
  23. * <code>replace</code> during <code>DocumentListener</code>
  24. * notification, you normally won't need to directly
  25. * invoke <code>replace</code>.
  26. *
  27. * <p>While <code>CompositeView</code>
  28. * does not impose a layout policy on its child <code>View</code>s,
  29. * it does allow for inseting the child <code>View</code>s
  30. * it will contain. The insets can be set by either
  31. * {@link #setInsets} or {@link #setParagraphInsets}.
  32. *
  33. * <p>In addition to the abstract methods of
  34. * {@link javax.swing.text.View},
  35. * subclasses of <code>CompositeView</code> will need to
  36. * override:
  37. * <ul>
  38. * <li>{@link #isBefore} - Used to test if a given
  39. * <code>View</code> location is before the visual space
  40. * of the <code>CompositeView</code>.
  41. * <li>{@link #isAfter} - Used to test if a given
  42. * <code>View</code> location is after the visual space
  43. * of the <code>CompositeView</code>.
  44. * <li>{@link #getViewAtPoint} - Returns the view at
  45. * a given visual location.
  46. * <li>{@link #childAllocation} - Returns the bounds of
  47. * a particular child <code>View</code>.
  48. * <code>getChildAllocation</code> will invoke
  49. * <code>childAllocation</code> after offseting
  50. * the bounds by the <code>Inset</code>s of the
  51. * <code>CompositeView</code>.
  52. * </ul>
  53. *
  54. * @author Timothy Prinzing
  55. * @version 1.67 12/19/03
  56. */
  57. public abstract class CompositeView extends View {
  58. /**
  59. * Constructs a <code>CompositeView</code> for the given element.
  60. *
  61. * @param elem the element this view is responsible for
  62. */
  63. public CompositeView(Element elem) {
  64. super(elem);
  65. children = new View[1];
  66. nchildren = 0;
  67. childAlloc = new Rectangle();
  68. }
  69. /**
  70. * Loads all of the children to initialize the view.
  71. * This is called by the {@link #setParent}
  72. * method. Subclasses can reimplement this to initialize
  73. * their child views in a different manner. The default
  74. * implementation creates a child view for each
  75. * child element.
  76. *
  77. * @param f the view factory
  78. * @see #setParent
  79. */
  80. protected void loadChildren(ViewFactory f) {
  81. if (f == null) {
  82. // No factory. This most likely indicates the parent view
  83. // has changed out from under us, bail!
  84. return;
  85. }
  86. Element e = getElement();
  87. int n = e.getElementCount();
  88. if (n > 0) {
  89. View[] added = new View[n];
  90. for (int i = 0; i < n; i++) {
  91. added[i] = f.create(e.getElement(i));
  92. }
  93. replace(0, 0, added);
  94. }
  95. }
  96. // --- View methods ---------------------------------------------
  97. /**
  98. * Sets the parent of the view.
  99. * This is reimplemented to provide the superclass
  100. * behavior as well as calling the <code>loadChildren</code>
  101. * method if this view does not already have children.
  102. * The children should not be loaded in the
  103. * constructor because the act of setting the parent
  104. * may cause them to try to search up the hierarchy
  105. * (to get the hosting <code>Container</code> for example).
  106. * If this view has children (the view is being moved
  107. * from one place in the view hierarchy to another),
  108. * the <code>loadChildren</code> method will not be called.
  109. *
  110. * @param parent the parent of the view, <code>null</code> if none
  111. */
  112. public void setParent(View parent) {
  113. super.setParent(parent);
  114. if ((parent != null) && (nchildren == 0)) {
  115. ViewFactory f = getViewFactory();
  116. loadChildren(f);
  117. }
  118. }
  119. /**
  120. * Returns the number of child views of this view.
  121. *
  122. * @return the number of views >= 0
  123. * @see #getView
  124. */
  125. public int getViewCount() {
  126. return nchildren;
  127. }
  128. /**
  129. * Returns the n-th view in this container.
  130. *
  131. * @param n the number of the desired view, >= 0 && < getViewCount()
  132. * @return the view at index <code>n</code>
  133. */
  134. public View getView(int n) {
  135. return children[n];
  136. }
  137. /**
  138. * Replaces child views. If there are no views to remove
  139. * this acts as an insert. If there are no views to
  140. * add this acts as a remove. Views being removed will
  141. * have the parent set to <code>null</code>,
  142. * and the internal reference to them removed so that they
  143. * may be garbage collected.
  144. *
  145. * @param offset the starting index into the child views to insert
  146. * the new views; >= 0 and <= getViewCount
  147. * @param length the number of existing child views to remove;
  148. * this should be a value >= 0 and <= (getViewCount() - offset)
  149. * @param views the child views to add; this value can be
  150. * <code>null</code>
  151. * to indicate no children are being added (useful to remove)
  152. */
  153. public void replace(int offset, int length, View[] views) {
  154. // make sure an array exists
  155. if (views == null) {
  156. views = ZERO;
  157. }
  158. // update parent reference on removed views
  159. for (int i = offset; i < offset + length; i++) {
  160. if (children[i].getParent() == this) {
  161. // in FlowView.java view might be referenced
  162. // from two super-views as a child. see logicalView
  163. children[i].setParent(null);
  164. }
  165. children[i] = null;
  166. }
  167. // update the array
  168. int delta = views.length - length;
  169. int src = offset + length;
  170. int nmove = nchildren - src;
  171. int dest = src + delta;
  172. if ((nchildren + delta) >= children.length) {
  173. // need to grow the array
  174. int newLength = Math.max(2*children.length, nchildren + delta);
  175. View[] newChildren = new View[newLength];
  176. System.arraycopy(children, 0, newChildren, 0, offset);
  177. System.arraycopy(views, 0, newChildren, offset, views.length);
  178. System.arraycopy(children, src, newChildren, dest, nmove);
  179. children = newChildren;
  180. } else {
  181. // patch the existing array
  182. System.arraycopy(children, src, children, dest, nmove);
  183. System.arraycopy(views, 0, children, offset, views.length);
  184. }
  185. nchildren = nchildren + delta;
  186. // update parent reference on added views
  187. for (int i = 0; i < views.length; i++) {
  188. views[i].setParent(this);
  189. }
  190. }
  191. /**
  192. * Fetches the allocation for the given child view to
  193. * render into. This enables finding out where various views
  194. * are located.
  195. *
  196. * @param index the index of the child, >= 0 && < getViewCount()
  197. * @param a the allocation to this view
  198. * @return the allocation to the child
  199. */
  200. public Shape getChildAllocation(int index, Shape a) {
  201. Rectangle alloc = getInsideAllocation(a);
  202. childAllocation(index, alloc);
  203. return alloc;
  204. }
  205. /**
  206. * Provides a mapping from the document model coordinate space
  207. * to the coordinate space of the view mapped to it.
  208. *
  209. * @param pos the position to convert >= 0
  210. * @param a the allocated region to render into
  211. * @param b a bias value of either <code>Position.Bias.Forward</code>
  212. * or <code>Position.Bias.Backward</code>
  213. * @return the bounding box of the given position
  214. * @exception BadLocationException if the given position does
  215. * not represent a valid location in the associated document
  216. * @see View#modelToView
  217. */
  218. public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
  219. boolean isBackward = (b == Position.Bias.Backward);
  220. int testPos = (isBackward) ? Math.max(0, pos - 1) : pos;
  221. if(isBackward && testPos < getStartOffset()) {
  222. return null;
  223. }
  224. int vIndex = getViewIndexAtPosition(testPos);
  225. if ((vIndex != -1) && (vIndex < getViewCount())) {
  226. View v = getView(vIndex);
  227. if(v != null && testPos >= v.getStartOffset() &&
  228. testPos < v.getEndOffset()) {
  229. Shape childShape = getChildAllocation(vIndex, a);
  230. if (childShape == null) {
  231. // We are likely invalid, fail.
  232. return null;
  233. }
  234. Shape retShape = v.modelToView(pos, childShape, b);
  235. if(retShape == null && v.getEndOffset() == pos) {
  236. if(++vIndex < getViewCount()) {
  237. v = getView(vIndex);
  238. retShape = v.modelToView(pos, getChildAllocation(vIndex, a), b);
  239. }
  240. }
  241. return retShape;
  242. }
  243. }
  244. throw new BadLocationException("Position not represented by view",
  245. pos);
  246. }
  247. /**
  248. * Provides a mapping from the document model coordinate space
  249. * to the coordinate space of the view mapped to it.
  250. *
  251. * @param p0 the position to convert >= 0
  252. * @param b0 the bias toward the previous character or the
  253. * next character represented by p0, in case the
  254. * position is a boundary of two views; either
  255. * <code>Position.Bias.Forward</code> or
  256. * <code>Position.Bias.Backward</code>
  257. * @param p1 the position to convert >= 0
  258. * @param b1 the bias toward the previous character or the
  259. * next character represented by p1, in case the
  260. * position is a boundary of two views
  261. * @param a the allocated region to render into
  262. * @return the bounding box of the given position is returned
  263. * @exception BadLocationException if the given position does
  264. * not represent a valid location in the associated document
  265. * @exception IllegalArgumentException for an invalid bias argument
  266. * @see View#viewToModel
  267. */
  268. public Shape modelToView(int p0, Position.Bias b0, int p1, Position.Bias b1, Shape a) throws BadLocationException {
  269. if (p0 == getStartOffset() && p1 == getEndOffset()) {
  270. return a;
  271. }
  272. Rectangle alloc = getInsideAllocation(a);
  273. Rectangle r0 = new Rectangle(alloc);
  274. View v0 = getViewAtPosition((b0 == Position.Bias.Backward) ?
  275. Math.max(0, p0 - 1) : p0, r0);
  276. Rectangle r1 = new Rectangle(alloc);
  277. View v1 = getViewAtPosition((b1 == Position.Bias.Backward) ?
  278. Math.max(0, p1 - 1) : p1, r1);
  279. if (v0 == v1) {
  280. if (v0 == null) {
  281. return a;
  282. }
  283. // Range contained in one view
  284. return v0.modelToView(p0, b0, p1, b1, r0);
  285. }
  286. // Straddles some views.
  287. int viewCount = getViewCount();
  288. int counter = 0;
  289. while (counter < viewCount) {
  290. View v;
  291. // Views may not be in same order as model.
  292. // v0 or v1 may be null if there is a gap in the range this
  293. // view contains.
  294. if ((v = getView(counter)) == v0 || v == v1) {
  295. View endView;
  296. Rectangle retRect;
  297. Rectangle tempRect = new Rectangle();
  298. if (v == v0) {
  299. retRect = v0.modelToView(p0, b0, v0.getEndOffset(),
  300. Position.Bias.Backward, r0).
  301. getBounds();
  302. endView = v1;
  303. }
  304. else {
  305. retRect = v1.modelToView(v1.getStartOffset(),
  306. Position.Bias.Forward,
  307. p1, b1, r1).getBounds();
  308. endView = v0;
  309. }
  310. // Views entirely covered by range.
  311. while (++counter < viewCount &&
  312. (v = getView(counter)) != endView) {
  313. tempRect.setBounds(alloc);
  314. childAllocation(counter, tempRect);
  315. retRect.add(tempRect);
  316. }
  317. // End view.
  318. if (endView != null) {
  319. Shape endShape;
  320. if (endView == v1) {
  321. endShape = v1.modelToView(v1.getStartOffset(),
  322. Position.Bias.Forward,
  323. p1, b1, r1);
  324. }
  325. else {
  326. endShape = v0.modelToView(p0, b0, v0.getEndOffset(),
  327. Position.Bias.Backward, r0);
  328. }
  329. if (endShape instanceof Rectangle) {
  330. retRect.add((Rectangle)endShape);
  331. }
  332. else {
  333. retRect.add(endShape.getBounds());
  334. }
  335. }
  336. return retRect;
  337. }
  338. counter++;
  339. }
  340. throw new BadLocationException("Position not represented by view", p0);
  341. }
  342. /**
  343. * Provides a mapping from the view coordinate space to the logical
  344. * coordinate space of the model.
  345. *
  346. * @param x x coordinate of the view location to convert >= 0
  347. * @param y y coordinate of the view location to convert >= 0
  348. * @param a the allocated region to render into
  349. * @param bias either <code>Position.Bias.Forward</code> or
  350. * <code>Position.Bias.Backward</code>
  351. * @return the location within the model that best represents the
  352. * given point in the view >= 0
  353. * @see View#viewToModel
  354. */
  355. public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) {
  356. Rectangle alloc = getInsideAllocation(a);
  357. if (isBefore((int) x, (int) y, alloc)) {
  358. // point is before the range represented
  359. int retValue = -1;
  360. try {
  361. retValue = getNextVisualPositionFrom(-1, Position.Bias.Forward,
  362. a, EAST, bias);
  363. } catch (BadLocationException ble) { }
  364. catch (IllegalArgumentException iae) { }
  365. if(retValue == -1) {
  366. retValue = getStartOffset();
  367. bias[0] = Position.Bias.Forward;
  368. }
  369. return retValue;
  370. } else if (isAfter((int) x, (int) y, alloc)) {
  371. // point is after the range represented.
  372. int retValue = -1;
  373. try {
  374. retValue = getNextVisualPositionFrom(-1, Position.Bias.Forward,
  375. a, WEST, bias);
  376. } catch (BadLocationException ble) { }
  377. catch (IllegalArgumentException iae) { }
  378. if(retValue == -1) {
  379. // NOTE: this could actually use end offset with backward.
  380. retValue = getEndOffset() - 1;
  381. bias[0] = Position.Bias.Forward;
  382. }
  383. return retValue;
  384. } else {
  385. // locate the child and pass along the request
  386. View v = getViewAtPoint((int) x, (int) y, alloc);
  387. if (v != null) {
  388. return v.viewToModel(x, y, alloc, bias);
  389. }
  390. }
  391. return -1;
  392. }
  393. /**
  394. * Provides a way to determine the next visually represented model
  395. * location that one might place a caret. Some views may not be visible,
  396. * they might not be in the same order found in the model, or they just
  397. * might not allow access to some of the locations in the model.
  398. * This is a convenience method for {@link #getNextNorthSouthVisualPositionFrom}
  399. * and {@link #getNextEastWestVisualPositionFrom}.
  400. *
  401. * @param pos the position to convert >= 0
  402. * @param b a bias value of either <code>Position.Bias.Forward</code>
  403. * or <code>Position.Bias.Backward</code>
  404. * @param a the allocated region to render into
  405. * @param direction the direction from the current position that can
  406. * be thought of as the arrow keys typically found on a keyboard;
  407. * this may be one of the following:
  408. * <ul>
  409. * <li><code>SwingConstants.WEST</code>
  410. * <li><code>SwingConstants.EAST</code>
  411. * <li><code>SwingConstants.NORTH</code>
  412. * <li><code>SwingConstants.SOUTH</code>
  413. * </ul>
  414. * @param biasRet an array containing the bias that was checked
  415. * @return the location within the model that best represents the next
  416. * location visual position
  417. * @exception BadLocationException
  418. * @exception IllegalArgumentException if <code>direction</code> is invalid
  419. */
  420. public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
  421. int direction, Position.Bias[] biasRet)
  422. throws BadLocationException {
  423. Rectangle alloc = getInsideAllocation(a);
  424. switch (direction) {
  425. case NORTH:
  426. return getNextNorthSouthVisualPositionFrom(pos, b, a, direction,
  427. biasRet);
  428. case SOUTH:
  429. return getNextNorthSouthVisualPositionFrom(pos, b, a, direction,
  430. biasRet);
  431. case EAST:
  432. return getNextEastWestVisualPositionFrom(pos, b, a, direction,
  433. biasRet);
  434. case WEST:
  435. return getNextEastWestVisualPositionFrom(pos, b, a, direction,
  436. biasRet);
  437. default:
  438. throw new IllegalArgumentException("Bad direction: " + direction);
  439. }
  440. }
  441. /**
  442. * Returns the child view index representing the given
  443. * position in the model. This is implemented to call the
  444. * <code>getViewIndexByPosition</code>
  445. * method for backward compatibility.
  446. *
  447. * @param pos the position >= 0
  448. * @return index of the view representing the given position, or
  449. * -1 if no view represents that position
  450. */
  451. public int getViewIndex(int pos, Position.Bias b) {
  452. if(b == Position.Bias.Backward) {
  453. pos -= 1;
  454. }
  455. if ((pos >= getStartOffset()) && (pos < getEndOffset())) {
  456. return getViewIndexAtPosition(pos);
  457. }
  458. return -1;
  459. }
  460. // --- local methods ----------------------------------------------------
  461. /**
  462. * Tests whether a point lies before the rectangle range.
  463. *
  464. * @param x the X coordinate >= 0
  465. * @param y the Y coordinate >= 0
  466. * @param alloc the rectangle
  467. * @return true if the point is before the specified range
  468. */
  469. protected abstract boolean isBefore(int x, int y, Rectangle alloc);
  470. /**
  471. * Tests whether a point lies after the rectangle range.
  472. *
  473. * @param x the X coordinate >= 0
  474. * @param y the Y coordinate >= 0
  475. * @param alloc the rectangle
  476. * @return true if the point is after the specified range
  477. */
  478. protected abstract boolean isAfter(int x, int y, Rectangle alloc);
  479. /**
  480. * Fetches the child view at the given coordinates.
  481. *
  482. * @param x the X coordinate >= 0
  483. * @param y the Y coordinate >= 0
  484. * @param alloc the parent's allocation on entry, which should
  485. * be changed to the child's allocation on exit
  486. * @return the child view
  487. */
  488. protected abstract View getViewAtPoint(int x, int y, Rectangle alloc);
  489. /**
  490. * Returns the allocation for a given child.
  491. *
  492. * @param index the index of the child, >= 0 && < getViewCount()
  493. * @param a the allocation to the interior of the box on entry,
  494. * and the allocation of the child view at the index on exit.
  495. */
  496. protected abstract void childAllocation(int index, Rectangle a);
  497. /**
  498. * Fetches the child view that represents the given position in
  499. * the model. This is implemented to fetch the view in the case
  500. * where there is a child view for each child element.
  501. *
  502. * @param pos the position >= 0
  503. * @param a the allocation to the interior of the box on entry,
  504. * and the allocation of the view containing the position on exit
  505. * @return the view representing the given position, or
  506. * <code>null</code> if there isn't one
  507. */
  508. protected View getViewAtPosition(int pos, Rectangle a) {
  509. int index = getViewIndexAtPosition(pos);
  510. if ((index >= 0) && (index < getViewCount())) {
  511. View v = getView(index);
  512. if (a != null) {
  513. childAllocation(index, a);
  514. }
  515. return v;
  516. }
  517. return null;
  518. }
  519. /**
  520. * Fetches the child view index representing the given position in
  521. * the model. This is implemented to fetch the view in the case
  522. * where there is a child view for each child element.
  523. *
  524. * @param pos the position >= 0
  525. * @return index of the view representing the given position, or
  526. * -1 if no view represents that position
  527. */
  528. protected int getViewIndexAtPosition(int pos) {
  529. Element elem = getElement();
  530. return elem.getElementIndex(pos);
  531. }
  532. /**
  533. * Translates the immutable allocation given to the view
  534. * to a mutable allocation that represents the interior
  535. * allocation (i.e. the bounds of the given allocation
  536. * with the top, left, bottom, and right insets removed.
  537. * It is expected that the returned value would be further
  538. * mutated to represent an allocation to a child view.
  539. * This is implemented to reuse an instance variable so
  540. * it avoids creating excessive Rectangles. Typically
  541. * the result of calling this method would be fed to
  542. * the <code>childAllocation</code> method.
  543. *
  544. * @param a the allocation given to the view
  545. * @return the allocation that represents the inside of the
  546. * view after the margins have all been removed; if the
  547. * given allocation was <code>null</code>,
  548. * the return value is <code>null</code>
  549. */
  550. protected Rectangle getInsideAllocation(Shape a) {
  551. if (a != null) {
  552. // get the bounds, hopefully without allocating
  553. // a new rectangle. The Shape argument should
  554. // not be modified... we copy it into the
  555. // child allocation.
  556. Rectangle alloc;
  557. if (a instanceof Rectangle) {
  558. alloc = (Rectangle) a;
  559. } else {
  560. alloc = a.getBounds();
  561. }
  562. childAlloc.setBounds(alloc);
  563. childAlloc.x += getLeftInset();
  564. childAlloc.y += getTopInset();
  565. childAlloc.width -= getLeftInset() + getRightInset();
  566. childAlloc.height -= getTopInset() + getBottomInset();
  567. return childAlloc;
  568. }
  569. return null;
  570. }
  571. /**
  572. * Sets the insets from the paragraph attributes specified in
  573. * the given attributes.
  574. *
  575. * @param attr the attributes
  576. */
  577. protected void setParagraphInsets(AttributeSet attr) {
  578. // Since version 1.1 doesn't have scaling and assumes
  579. // a pixel is equal to a point, we just cast the point
  580. // sizes to integers.
  581. top = (short) StyleConstants.getSpaceAbove(attr);
  582. left = (short) StyleConstants.getLeftIndent(attr);
  583. bottom = (short) StyleConstants.getSpaceBelow(attr);
  584. right = (short) StyleConstants.getRightIndent(attr);
  585. }
  586. /**
  587. * Sets the insets for the view.
  588. *
  589. * @param top the top inset >= 0
  590. * @param left the left inset >= 0
  591. * @param bottom the bottom inset >= 0
  592. * @param right the right inset >= 0
  593. */
  594. protected void setInsets(short top, short left, short bottom, short right) {
  595. this.top = top;
  596. this.left = left;
  597. this.right = right;
  598. this.bottom = bottom;
  599. }
  600. /**
  601. * Gets the left inset.
  602. *
  603. * @return the inset >= 0
  604. */
  605. protected short getLeftInset() {
  606. return left;
  607. }
  608. /**
  609. * Gets the right inset.
  610. *
  611. * @return the inset >= 0
  612. */
  613. protected short getRightInset() {
  614. return right;
  615. }
  616. /**
  617. * Gets the top inset.
  618. *
  619. * @return the inset >= 0
  620. */
  621. protected short getTopInset() {
  622. return top;
  623. }
  624. /**
  625. * Gets the bottom inset.
  626. *
  627. * @return the inset >= 0
  628. */
  629. protected short getBottomInset() {
  630. return bottom;
  631. }
  632. /**
  633. * Returns the next visual position for the cursor, in either the
  634. * north or south direction.
  635. *
  636. * @param pos the position to convert >= 0
  637. * @param b a bias value of either <code>Position.Bias.Forward</code>
  638. * or <code>Position.Bias.Backward</code>
  639. * @param a the allocated region to render into
  640. * @param direction the direction from the current position that can
  641. * be thought of as the arrow keys typically found on a keyboard;
  642. * this may be one of the following:
  643. * <ul>
  644. * <li><code>SwingConstants.NORTH</code>
  645. * <li><code>SwingConstants.SOUTH</code>
  646. * </ul>
  647. * @param biasRet an array containing the bias that was checked
  648. * @return the location within the model that best represents the next
  649. * north or south location
  650. * @exception BadLocationException
  651. * @exception IllegalArgumentException if <code>direction</code> is invalid
  652. * @see #getNextVisualPositionFrom
  653. *
  654. * @return the next position west of the passed in position
  655. */
  656. protected int getNextNorthSouthVisualPositionFrom(int pos, Position.Bias b,
  657. Shape a, int direction,
  658. Position.Bias[] biasRet)
  659. throws BadLocationException {
  660. return Utilities.getNextVisualPositionFrom(
  661. this, pos, b, a, direction, biasRet);
  662. }
  663. /**
  664. * Returns the next visual position for the cursor, in either the
  665. * east or west direction.
  666. *
  667. * @param pos the position to convert >= 0
  668. * @param b a bias value of either <code>Position.Bias.Forward</code>
  669. * or <code>Position.Bias.Backward</code>
  670. * @param a the allocated region to render into
  671. * @param direction the direction from the current position that can
  672. * be thought of as the arrow keys typically found on a keyboard;
  673. * this may be one of the following:
  674. * <ul>
  675. * <li><code>SwingConstants.WEST</code>
  676. * <li><code>SwingConstants.EAST</code>
  677. * </ul>
  678. * @param biasRet an array containing the bias that was checked
  679. * @return the location within the model that best represents the next
  680. * west or east location
  681. * @exception BadLocationException
  682. * @exception IllegalArgumentException if <code>direction</code> is invalid
  683. * @see #getNextVisualPositionFrom
  684. */
  685. protected int getNextEastWestVisualPositionFrom(int pos, Position.Bias b,
  686. Shape a,
  687. int direction,
  688. Position.Bias[] biasRet)
  689. throws BadLocationException {
  690. return Utilities.getNextVisualPositionFrom(
  691. this, pos, b, a, direction, biasRet);
  692. }
  693. /**
  694. * Determines in which direction the next view lays.
  695. * Consider the <code>View</code> at index n. Typically the
  696. * <code>View</code>s are layed out from left to right,
  697. * so that the <code>View</code> to the EAST will be
  698. * at index n + 1, and the <code>View</code> to the WEST
  699. * will be at index n - 1. In certain situations,
  700. * such as with bidirectional text, it is possible
  701. * that the <code>View</code> to EAST is not at index n + 1,
  702. * but rather at index n - 1, or that the <code>View</code>
  703. * to the WEST is not at index n - 1, but index n + 1.
  704. * In this case this method would return true, indicating the
  705. * <code>View</code>s are layed out in descending order.
  706. * <p>
  707. * This unconditionally returns false, subclasses should override this
  708. * method if there is the possibility for laying <code>View</code>s in
  709. * descending order.
  710. *
  711. * @param position position into the model
  712. * @param bias either <code>Position.Bias.Forward</code> or
  713. * <code>Position.Bias.Backward</code>
  714. * @return false
  715. */
  716. protected boolean flipEastAndWestAtEnds(int position,
  717. Position.Bias bias) {
  718. return false;
  719. }
  720. // ---- member variables ---------------------------------------------
  721. private static View[] ZERO = new View[0];
  722. private View[] children;
  723. private int nchildren;
  724. private short left;
  725. private short right;
  726. private short top;
  727. private short bottom;
  728. private Rectangle childAlloc;
  729. }