1. /*
  2. * @(#)ParagraphView.java 1.76 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.event.*;
  13. import javax.swing.SizeRequirements;
  14. /**
  15. * View of a simple line-wrapping paragraph that supports
  16. * multiple fonts, colors, components, icons, etc. It is
  17. * basically a vertical box with a margin around it. The
  18. * contents of the box are a bunch of rows which are special
  19. * horizontal boxes. This view creates a collection of
  20. * views that represent the child elements of the paragraph
  21. * element. Each of these views are placed into a row
  22. * directly if they will fit, otherwise the <code>breakView</code>
  23. * method is called to try and carve the view into pieces
  24. * that fit.
  25. *
  26. * @author Timothy Prinzing
  27. * @author Scott Violet
  28. * @version 1.76 02/02/00
  29. * @see View
  30. */
  31. public class ParagraphView extends FlowView implements TabExpander {
  32. /**
  33. * Constructs a ParagraphView for the given element.
  34. *
  35. * @param elem the element that this view is responsible for
  36. */
  37. public ParagraphView(Element elem) {
  38. super(elem, View.Y_AXIS);
  39. setPropertiesFromAttributes();
  40. Document doc = elem.getDocument();
  41. Object i18nFlag = doc.getProperty(AbstractDocument.I18NProperty);
  42. if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) {
  43. try {
  44. if (i18nStrategy == null) {
  45. // the classname should probably come from a property file.
  46. String classname = "javax.swing.text.TextLayoutStrategy";
  47. ClassLoader loader = getClass().getClassLoader();
  48. if (loader != null) {
  49. i18nStrategy = loader.loadClass(classname);
  50. } else {
  51. i18nStrategy = Class.forName(classname);
  52. }
  53. }
  54. Object o = i18nStrategy.newInstance();
  55. if (o instanceof FlowStrategy) {
  56. strategy = (FlowStrategy) o;
  57. }
  58. } catch (Throwable e) {
  59. throw new StateInvariantError("ParagraphView: Can't create i18n strategy: "
  60. + e.getMessage());
  61. }
  62. }
  63. }
  64. /**
  65. * Set the type of justification.
  66. */
  67. protected void setJustification(int j) {
  68. justification = j;
  69. }
  70. /**
  71. * Set the line spacing.
  72. *
  73. * @param ls the value in points
  74. */
  75. protected void setLineSpacing(float ls) {
  76. lineSpacing = ls;
  77. }
  78. /**
  79. * Set the indent on the first line
  80. *
  81. * @param ls the value in points
  82. */
  83. protected void setFirstLineIndent(float fi) {
  84. firstLineIndent = (int) fi;
  85. }
  86. protected void setPropertiesFromAttributes() {
  87. AttributeSet attr = getAttributes();
  88. if (attr != null) {
  89. setParagraphInsets(attr);
  90. setJustification(StyleConstants.getAlignment(attr));
  91. lineSpacing = StyleConstants.getLineSpacing(attr);
  92. firstLineIndent = (int)StyleConstants.getFirstLineIndent(attr);
  93. }
  94. }
  95. /**
  96. * The child views of the paragraph are rows which
  97. * have been used to arrange pieces of the Views that
  98. * represent the child elements. This is the number
  99. * of views that have been tiled in two dimensions,
  100. * and should be equivalent to the number of child elements
  101. * to the element this view is responsible for.
  102. */
  103. protected int getLayoutViewCount() {
  104. return layoutPool.getViewCount();
  105. }
  106. /**
  107. * The child views of the paragraph are rows which
  108. * have been used to arrange pieces of the Views that
  109. * represent the child elements. This methods returns
  110. * the view responsible for the child element index
  111. * (prior to breaking). These are the Views that were
  112. * produced from a factory (to represent the child
  113. * elements) and used for layout.
  114. */
  115. protected View getLayoutView(int index) {
  116. return layoutPool.getView(index);
  117. }
  118. /**
  119. * Adjusts the given row if possible to fit within the
  120. * layout span. By default this will try to find the
  121. * highest break weight possible nearest the end of
  122. * the row. If a forced break is encountered, the
  123. * break will be positioned there.
  124. *
  125. * @param r the row to adjust to the current layout
  126. * span.
  127. * @param desiredSpan the current layout span >= 0
  128. * @param x the location r starts at.
  129. */
  130. protected void adjustRow(Row r, int desiredSpan, int x) {
  131. }
  132. /**
  133. * Overriden from CompositeView.
  134. */
  135. protected int getNextNorthSouthVisualPositionFrom(int pos, Position.Bias b,
  136. Shape a, int direction,
  137. Position.Bias[] biasRet)
  138. throws BadLocationException {
  139. int vIndex;
  140. if(pos == -1) {
  141. vIndex = (direction == NORTH) ?
  142. getViewCount() - 1 : 0;
  143. }
  144. else {
  145. if(b == Position.Bias.Backward && pos > 0) {
  146. vIndex = getViewIndexAtPosition(pos - 1);
  147. }
  148. else {
  149. vIndex = getViewIndexAtPosition(pos);
  150. }
  151. if(direction == NORTH) {
  152. if(vIndex == 0) {
  153. return -1;
  154. }
  155. vIndex--;
  156. }
  157. else if(++vIndex >= getViewCount()) {
  158. return -1;
  159. }
  160. }
  161. // vIndex gives index of row to look in.
  162. JTextComponent text = (JTextComponent)getContainer();
  163. Caret c = text.getCaret();
  164. Point magicPoint;
  165. magicPoint = (c != null) ? c.getMagicCaretPosition() : null;
  166. int x;
  167. if(magicPoint == null) {
  168. Shape posBounds = text.getUI().modelToView(text, pos, b);
  169. if(posBounds == null) {
  170. x = 0;
  171. }
  172. else {
  173. x = posBounds.getBounds().x;
  174. }
  175. }
  176. else {
  177. x = magicPoint.x;
  178. }
  179. return getClosestPositionTo(pos, b, a, direction, biasRet, vIndex, x);
  180. }
  181. /**
  182. * Returns the closest model position to <code>x</code>.
  183. * <code>rowIndex</code> gives the index of the view that corresponds
  184. * that should be looked in.
  185. */
  186. // NOTE: This will not properly work if ParagraphView contains
  187. // other ParagraphViews. It won't raise, but this does not message
  188. // the children views with getNextVisualPositionFrom.
  189. protected int getClosestPositionTo(int pos, Position.Bias b, Shape a,
  190. int direction, Position.Bias[] biasRet,
  191. int rowIndex, int x)
  192. throws BadLocationException {
  193. JTextComponent text = (JTextComponent)getContainer();
  194. Document doc = getDocument();
  195. AbstractDocument aDoc = (doc instanceof AbstractDocument) ?
  196. (AbstractDocument)doc : null;
  197. View row = getView(rowIndex);
  198. int lastPos = -1;
  199. // This could be made better to check backward positions too.
  200. biasRet[0] = Position.Bias.Forward;
  201. for(int vc = 0, numViews = row.getViewCount(); vc < numViews; vc++) {
  202. View v = row.getView(vc);
  203. int start = v.getStartOffset();
  204. boolean ltr = (aDoc != null) ? aDoc.isLeftToRight
  205. (start, start + 1) : true;
  206. if(ltr) {
  207. lastPos = start;
  208. for(int end = v.getEndOffset(); lastPos < end; lastPos++) {
  209. if(text.modelToView(lastPos).getBounds().x >= x) {
  210. return lastPos;
  211. }
  212. }
  213. lastPos--;
  214. }
  215. else {
  216. for(lastPos = v.getEndOffset() - 1; lastPos >= start;
  217. lastPos--) {
  218. if(text.modelToView(lastPos).getBounds().x >= x) {
  219. return lastPos;
  220. }
  221. }
  222. lastPos++;
  223. }
  224. }
  225. if(lastPos == -1) {
  226. return getStartOffset();
  227. }
  228. return lastPos;
  229. }
  230. protected boolean flipEastAndWestAtEnds(int position,
  231. Position.Bias bias) {
  232. Document doc = getDocument();
  233. if(doc instanceof AbstractDocument &&
  234. !((AbstractDocument)doc).isLeftToRight(getStartOffset(),
  235. getStartOffset() + 1)) {
  236. return true;
  237. }
  238. return false;
  239. }
  240. // --- FlowView methods ---------------------------------------------
  241. /**
  242. * Fetch the constraining span to flow against for
  243. * the given child index.
  244. */
  245. public int getFlowSpan(int index) {
  246. View child = getView(index);
  247. int adjust = 0;
  248. if (child instanceof Row) {
  249. Row row = (Row) child;
  250. adjust = row.getLeftInset() + row.getRightInset();
  251. }
  252. int span = layoutSpan - adjust;
  253. return span;
  254. }
  255. /**
  256. * Fetch the location along the flow axis that the
  257. * flow span will start at.
  258. */
  259. public int getFlowStart(int index) {
  260. View child = getView(index);
  261. int adjust = 0;
  262. if (child instanceof Row) {
  263. Row row = (Row) child;
  264. adjust = row.getLeftInset();
  265. }
  266. return tabBase + adjust;
  267. }
  268. /**
  269. * Create a View that should be used to hold a
  270. * a rows worth of children in a flow.
  271. */
  272. protected View createRow() {
  273. Element elem = getElement();
  274. Row row = new Row(elem);
  275. // Adjust for line spacing
  276. if(lineSpacing > 1) {
  277. float height = row.getPreferredSpan(View.Y_AXIS);
  278. float addition = (height * lineSpacing) - height;
  279. if(addition > 0) {
  280. row.setInsets(row.getTopInset(), row.getLeftInset(),
  281. (short) addition, row.getRightInset());
  282. }
  283. }
  284. return row;
  285. }
  286. // --- TabExpander methods ------------------------------------------
  287. /**
  288. * Returns the next tab stop position given a reference position.
  289. * This view implements the tab coordinate system, and calls
  290. * <code>getTabbedSpan</code> on the logical children in the process
  291. * of layout to determine the desired span of the children. The
  292. * logical children can delegate their tab expansion upward to
  293. * the paragraph which knows how to expand tabs.
  294. * <code>LabelView</code> is an example of a view that delegates
  295. * its tab expansion needs upward to the paragraph.
  296. * <p>
  297. * This is implemented to try and locate a <code>TabSet</code>
  298. * in the paragraph element's attribute set. If one can be
  299. * found, its settings will be used, otherwise a default expansion
  300. * will be provided. The base location for for tab expansion
  301. * is the left inset from the paragraphs most recent allocation
  302. * (which is what the layout of the children is based upon).
  303. *
  304. * @param x the X reference position
  305. * @param tabOffset the position within the text stream
  306. * that the tab occurred at >= 0.
  307. * @return the trailing end of the tab expansion >= 0
  308. * @see TabSet
  309. * @see TabStop
  310. * @see LabelView
  311. */
  312. public float nextTabStop(float x, int tabOffset) {
  313. // If the text isn't left justified, offset by 10 pixels!
  314. if(justification != StyleConstants.ALIGN_LEFT)
  315. return x + 10.0f;
  316. x -= tabBase;
  317. TabSet tabs = getTabSet();
  318. if(tabs == null) {
  319. // a tab every 72 pixels.
  320. return (float)(tabBase + (((int)x / 72 + 1) * 72));
  321. }
  322. TabStop tab = tabs.getTabAfter(x + .01f);
  323. if(tab == null) {
  324. // no tab, do a default of 5 pixels.
  325. // Should this cause a wrapping of the line?
  326. return tabBase + x + 5.0f;
  327. }
  328. int alignment = tab.getAlignment();
  329. int offset;
  330. switch(alignment) {
  331. default:
  332. case TabStop.ALIGN_LEFT:
  333. // Simple case, left tab.
  334. return tabBase + tab.getPosition();
  335. case TabStop.ALIGN_BAR:
  336. // PENDING: what does this mean?
  337. return tabBase + tab.getPosition();
  338. case TabStop.ALIGN_RIGHT:
  339. case TabStop.ALIGN_CENTER:
  340. offset = findOffsetToCharactersInString(tabChars,
  341. tabOffset + 1);
  342. break;
  343. case TabStop.ALIGN_DECIMAL:
  344. offset = findOffsetToCharactersInString(tabDecimalChars,
  345. tabOffset + 1);
  346. break;
  347. }
  348. if (offset == -1) {
  349. offset = getEndOffset();
  350. }
  351. float charsSize = getPartialSize(tabOffset + 1, offset);
  352. switch(alignment) {
  353. case TabStop.ALIGN_RIGHT:
  354. case TabStop.ALIGN_DECIMAL:
  355. // right and decimal are treated the same way, the new
  356. // position will be the location of the tab less the
  357. // partialSize.
  358. return tabBase + Math.max(x, tab.getPosition() - charsSize);
  359. case TabStop.ALIGN_CENTER:
  360. // Similar to right, but half the partialSize.
  361. return tabBase + Math.max(x, tab.getPosition() - charsSize / 2.0f);
  362. }
  363. // will never get here!
  364. return x;
  365. }
  366. /**
  367. * Gets the Tabset to be used in calculating tabs.
  368. *
  369. * @return the TabSet
  370. */
  371. protected TabSet getTabSet() {
  372. return StyleConstants.getTabSet(getElement().getAttributes());
  373. }
  374. /**
  375. * Returns the size used by the views between <code>startOffset</code>
  376. * and <code>endOffset</code>. This uses getPartialView to calculate the
  377. * size if the child view implements the TabableView interface. If a
  378. * size is needed and a View does not implement the TabableView
  379. * interface, the preferredSpan will be used.
  380. *
  381. * @param startOffset the starting document offset >= 0
  382. * @param endOffset the ending document offset >= startOffset
  383. * @return the size >= 0
  384. */
  385. protected float getPartialSize(int startOffset, int endOffset) {
  386. float size = 0.0f;
  387. int viewIndex;
  388. int numViews = getViewCount();
  389. View view;
  390. int viewEnd;
  391. int tempEnd;
  392. // Have to search layoutPool!
  393. // PENDING: when ParagraphView supports breaking location
  394. // into layoutPool will have to change!
  395. viewIndex = getElement().getElementIndex(startOffset);
  396. numViews = layoutPool.getViewCount();
  397. while(startOffset < endOffset && viewIndex < numViews) {
  398. view = layoutPool.getView(viewIndex++);
  399. viewEnd = view.getEndOffset();
  400. tempEnd = Math.min(endOffset, viewEnd);
  401. if(view instanceof TabableView)
  402. size += ((TabableView)view).getPartialSpan(startOffset, tempEnd);
  403. else if(startOffset == view.getStartOffset() &&
  404. tempEnd == view.getEndOffset())
  405. size += view.getPreferredSpan(View.X_AXIS);
  406. else
  407. // PENDING: should we handle this better?
  408. return 0.0f;
  409. startOffset = viewEnd;
  410. }
  411. return size;
  412. }
  413. /**
  414. * Finds the next character in the document with a character in
  415. * <code>string</code>, starting at offset <code>start</code>. If
  416. * there are no characters found, -1 will be returned.
  417. *
  418. * @param string the string of characters
  419. * @param start where to start in the model >= 0
  420. * @return the document offset or -1
  421. */
  422. protected int findOffsetToCharactersInString(char[] string,
  423. int start) {
  424. int stringLength = string.length;
  425. int end = getEndOffset();
  426. Segment seg = new Segment();
  427. try {
  428. getDocument().getText(start, end - start, seg);
  429. } catch (BadLocationException ble) {
  430. return -1;
  431. }
  432. for(int counter = seg.offset, maxCounter = seg.offset + seg.count;
  433. counter < maxCounter; counter++) {
  434. char currentChar = seg.array[counter];
  435. for(int subCounter = 0; subCounter < stringLength;
  436. subCounter++) {
  437. if(currentChar == string[subCounter])
  438. return counter - seg.offset + start;
  439. }
  440. }
  441. // No match.
  442. return -1;
  443. }
  444. /**
  445. * @return where tabs are calculated from.
  446. */
  447. protected float getTabBase() {
  448. return (float)tabBase;
  449. }
  450. // ---- View methods ----------------------------------------------------
  451. /**
  452. * Renders using the given rendering surface and area on that
  453. * surface. This is implemented to delgate to the superclass
  454. * after stashing the base coordinate for tab calculations.
  455. *
  456. * @param g the rendering surface to use
  457. * @param a the allocated region to render into
  458. * @see View#paint
  459. */
  460. public void paint(Graphics g, Shape a) {
  461. Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds();
  462. tabBase = alloc.x + getLeftInset();
  463. super.paint(g, a);
  464. }
  465. /**
  466. * Determines the desired alignment for this view along an
  467. * axis. This is implemented to give the alignment to the
  468. * center of the first row along the y axis, and the default
  469. * along the x axis.
  470. *
  471. * @param axis may be either View.X_AXIS or View.Y_AXIS
  472. * @returns the desired alignment. This should be a value
  473. * between 0.0 and 1.0 inclusive, where 0 indicates alignment at the
  474. * origin and 1.0 indicates alignment to the full span
  475. * away from the origin. An alignment of 0.5 would be the
  476. * center of the view.
  477. */
  478. public float getAlignment(int axis) {
  479. switch (axis) {
  480. case Y_AXIS:
  481. float a = 0.5f;
  482. if (getViewCount() != 0) {
  483. int paragraphSpan = (int) getPreferredSpan(View.Y_AXIS);
  484. View v = getView(0);
  485. int rowSpan = (int) v.getPreferredSpan(View.Y_AXIS);
  486. a = (paragraphSpan != 0) ? ((float)(rowSpan / 2)) / paragraphSpan : 0;
  487. }
  488. return a;
  489. case X_AXIS:
  490. return 0.5f;
  491. default:
  492. throw new IllegalArgumentException("Invalid axis: " + axis);
  493. }
  494. }
  495. /**
  496. * Breaks this view on the given axis at the given length.<p>
  497. * ParagraphView instances are breakable along the Y_AXIS only, and only if
  498. * <code>len</code> is after the first line.
  499. *
  500. * @param axis may be either View.X_AXIS or View.Y_AXIS
  501. * @param len specifies where a potential break is desired
  502. * along the given axis >= 0
  503. * @param a the current allocation of the view
  504. * @return the fragment of the view that represents the
  505. * given span, if the view can be broken. If the view
  506. * doesn't support breaking behavior, the view itself is
  507. * returned.
  508. * @see View#breakView
  509. */
  510. public View breakView(int axis, float len, Shape a) {
  511. if(axis == View.Y_AXIS) {
  512. if(a != null) {
  513. Rectangle alloc = a.getBounds();
  514. setSize(alloc.width, alloc.height);
  515. }
  516. // Determine what row to break on.
  517. // PENDING(prinz) add break support
  518. return this;
  519. }
  520. return this;
  521. }
  522. /**
  523. * Gets the break weight for a given location.
  524. * ParagraphView instances are breakable along the Y_AXIS only, and
  525. * only if <code>len</code> is after the first row. If the length
  526. * is less than one row, a value of BadBreakWeight is returned.
  527. *
  528. * @param axis may be either View.X_AXIS or View.Y_AXIS
  529. * @param len specifies where a potential break is desired >= 0
  530. * @return a value indicating the attractiveness of breaking here
  531. * @see View#getBreakWeight
  532. */
  533. public int getBreakWeight(int axis, float len) {
  534. if(axis == View.Y_AXIS) {
  535. // PENDING(prinz) make this return a reasonable value
  536. // when paragraph breaking support is re-implemented.
  537. // If less than one row, bad weight value should be
  538. // returned.
  539. //return GoodBreakWeight;
  540. return BadBreakWeight;
  541. }
  542. return BadBreakWeight;
  543. }
  544. /**
  545. * Gives notification from the document that attributes were changed
  546. * in a location that this view is responsible for.
  547. *
  548. * @param changes the change information from the associated document
  549. * @param a the current allocation of the view
  550. * @param f the factory to use to rebuild if the view has children
  551. * @see View#changedUpdate
  552. */
  553. public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
  554. // update any property settings stored, and layout should be
  555. // recomputed
  556. setPropertiesFromAttributes();
  557. layoutChanged(X_AXIS);
  558. layoutChanged(Y_AXIS);
  559. super.changedUpdate(changes, a, f);
  560. }
  561. // --- variables -----------------------------------------------
  562. private int justification;
  563. private float lineSpacing;
  564. /** Indentation for the first line, from the left inset. */
  565. protected int firstLineIndent;
  566. /**
  567. * Used by the TabExpander functionality to determine
  568. * where to base the tab calculations. This is basically
  569. * the location of the left side of the paragraph.
  570. */
  571. private int tabBase;
  572. /**
  573. * Used to create an i18n-based layout strategy
  574. */
  575. static Class i18nStrategy;
  576. /** Used for searching for a tab. */
  577. static char[] tabChars;
  578. /** Used for searching for a tab or decimal character. */
  579. static char[] tabDecimalChars;
  580. static {
  581. tabChars = new char[1];
  582. tabChars[0] = '\t';
  583. tabDecimalChars = new char[2];
  584. tabDecimalChars[0] = '\t';
  585. tabDecimalChars[1] = '.';
  586. }
  587. /**
  588. * Internally created view that has the purpose of holding
  589. * the views that represent the children of the paragraph
  590. * that have been arranged in rows.
  591. */
  592. class Row extends BoxView {
  593. Row(Element elem) {
  594. super(elem, View.X_AXIS);
  595. }
  596. /**
  597. * This is reimplemented to do nothing since the
  598. * paragraph fills in the row with its needed
  599. * children.
  600. */
  601. protected void loadChildren(ViewFactory f) {
  602. }
  603. /**
  604. * Fetches the attributes to use when rendering. This view
  605. * isn't directly responsible for an element so it returns
  606. * the outer classes attributes.
  607. */
  608. public AttributeSet getAttributes() {
  609. View p = getParent();
  610. return (p != null) ? p.getAttributes() : null;
  611. }
  612. public float getAlignment(int axis) {
  613. if (axis == View.X_AXIS) {
  614. switch (justification) {
  615. case StyleConstants.ALIGN_LEFT:
  616. return 0;
  617. case StyleConstants.ALIGN_RIGHT:
  618. return 1;
  619. case StyleConstants.ALIGN_CENTER:
  620. case StyleConstants.ALIGN_JUSTIFIED:
  621. return 0.5f;
  622. }
  623. }
  624. return super.getAlignment(axis);
  625. }
  626. /**
  627. * Provides a mapping from the document model coordinate space
  628. * to the coordinate space of the view mapped to it. This is
  629. * implemented to let the superclass find the position along
  630. * the major axis and the allocation of the row is used
  631. * along the minor axis, so that even though the children
  632. * are different heights they all get the same caret height.
  633. *
  634. * @param pos the position to convert
  635. * @param a the allocated region to render into
  636. * @return the bounding box of the given position
  637. * @exception BadLocationException if the given position does not represent a
  638. * valid location in the associated document
  639. * @see View#modelToView
  640. */
  641. public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
  642. Rectangle r = a.getBounds();
  643. View v = getViewAtPosition(pos, r);
  644. if ((v != null) && (!v.getElement().isLeaf())) {
  645. // Don't adjust the height if the view represents a branch.
  646. return super.modelToView(pos, a, b);
  647. }
  648. r = a.getBounds();
  649. int height = r.height;
  650. int y = r.y;
  651. Shape loc = super.modelToView(pos, a, b);
  652. r = loc.getBounds();
  653. r.height = height;
  654. r.y = y;
  655. return r;
  656. }
  657. /**
  658. * Range represented by a row in the paragraph is only
  659. * a subset of the total range of the paragraph element.
  660. * @see View#getRange
  661. */
  662. public int getStartOffset() {
  663. int offs = Integer.MAX_VALUE;
  664. int n = getViewCount();
  665. for (int i = 0; i < n; i++) {
  666. View v = getView(i);
  667. offs = Math.min(offs, v.getStartOffset());
  668. }
  669. return offs;
  670. }
  671. public int getEndOffset() {
  672. int offs = 0;
  673. int n = getViewCount();
  674. for (int i = 0; i < n; i++) {
  675. View v = getView(i);
  676. offs = Math.max(offs, v.getEndOffset());
  677. }
  678. return offs;
  679. }
  680. /**
  681. * Perform layout for the minor axis of the box (i.e. the
  682. * axis orthoginal to the axis that it represents). The results
  683. * of the layout should be placed in the given arrays which represent
  684. * the allocations to the children along the minor axis.
  685. * <p>
  686. * This is implemented to do a baseline layout of the children
  687. * by calling BoxView.baselineLayout.
  688. *
  689. * @param targetSpan the total span given to the view, which
  690. * whould be used to layout the children.
  691. * @param axis the axis being layed out.
  692. * @param offsets the offsets from the origin of the view for
  693. * each of the child views. This is a return value and is
  694. * filled in by the implementation of this method.
  695. * @param spans the span of each child view. This is a return
  696. * value and is filled in by the implementation of this method.
  697. * @returns the offset and span for each child view in the
  698. * offsets and spans parameters.
  699. */
  700. protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
  701. baselineLayout(targetSpan, axis, offsets, spans);
  702. }
  703. protected SizeRequirements calculateMinorAxisRequirements(int axis,
  704. SizeRequirements r) {
  705. return baselineRequirements(axis, r);
  706. }
  707. /**
  708. * Fetches the child view index representing the given position in
  709. * the model.
  710. *
  711. * @param pos the position >= 0
  712. * @returns index of the view representing the given position, or
  713. * -1 if no view represents that position
  714. */
  715. protected int getViewIndexAtPosition(int pos) {
  716. // This is expensive, but are views are not necessarily layed
  717. // out in model order.
  718. if(pos < getStartOffset() || pos >= getEndOffset())
  719. return -1;
  720. for(int counter = getViewCount() - 1; counter >= 0; counter--) {
  721. View v = getView(counter);
  722. if(pos >= v.getStartOffset() &&
  723. pos < v.getEndOffset()) {
  724. return counter;
  725. }
  726. }
  727. return -1;
  728. }
  729. }
  730. }