1. /*
  2. * @(#)ScrollPane.java 1.75 00/04/06
  3. *
  4. * Copyright 1996-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 java.awt;
  11. import java.awt.peer.ScrollPanePeer;
  12. import java.awt.event.*;
  13. import java.io.Serializable;
  14. import javax.accessibility.*;
  15. /**
  16. * A container class which implements automatic horizontal and/or
  17. * vertical scrolling for a single child component. The display
  18. * policy for the scrollbars can be set to:
  19. * <OL>
  20. * <LI>as needed: scrollbars created and shown only when needed by scrollpane
  21. * <LI>always: scrollbars created and always shown by the scrollpane
  22. * <LI>never: scrollbars never created or shown by the scrollpane
  23. * </OL>
  24. * <P>
  25. * The state of the horizontal and vertical scrollbars is represented
  26. * by two objects (one for each dimension) which implement the
  27. * Adjustable interface. The API provides methods to access those
  28. * objects such that the attributes on the Adjustable object (such as unitIncrement,
  29. * value, etc.) can be manipulated.
  30. * <P>
  31. * Certain adjustable properties (minimum, maximum, blockIncrement,
  32. * and visibleAmount) are set internally by the scrollpane in accordance
  33. * with the geometry of the scrollpane and its child and these should
  34. * not be set by programs using the scrollpane.
  35. * <P>
  36. * If the scrollbar display policy is defined as "never", then the
  37. * scrollpane can still be programmatically scrolled using the
  38. * setScrollPosition() method and the scrollpane will move and clip
  39. * the child's contents appropriately. This policy is useful if the
  40. * program needs to create and manage its own adjustable controls.
  41. * <P>
  42. * The placement of the scrollbars is controlled by platform-specific
  43. * properties set by the user outside of the program.
  44. * <P>
  45. * The initial size of this container is set to 100x100, but can
  46. * be reset using setSize().
  47. * <P>
  48. * Insets are used to define any space used by scrollbars and any
  49. * borders created by the scroll pane. getInsets() can be used
  50. * to get the current value for the insets. If the value of
  51. * scrollbarsAlwaysVisible is false, then the value of the insets
  52. * will change dynamically depending on whether the scrollbars are
  53. * currently visible or not.
  54. *
  55. * @version 1.75 04/06/00
  56. * @author Tom Ball
  57. * @author Amy Fowler
  58. * @author Tim Prinzing
  59. */
  60. public class ScrollPane extends Container implements Accessible {
  61. /**
  62. * Initialize JNI field and method IDs
  63. */
  64. private static native void initIDs();
  65. static {
  66. /* ensure that the necessary native libraries are loaded */
  67. Toolkit.loadLibraries();
  68. initIDs();
  69. }
  70. /**
  71. * Specifies that horizontal/vertical scrollbar should be shown
  72. * only when the size of the child exceeds the size of the scrollpane
  73. * in the horizontal/vertical dimension.
  74. */
  75. public static final int SCROLLBARS_AS_NEEDED = 0;
  76. /**
  77. * Specifies that horizontal/vertical scrollbars should always be
  78. * shown regardless of the respective sizes of the scrollpane and child.
  79. */
  80. public static final int SCROLLBARS_ALWAYS = 1;
  81. /**
  82. * Specifies that horizontal/vertical scrollbars should never be shown
  83. * regardless of the respective sizes of the scrollpane and child.
  84. */
  85. public static final int SCROLLBARS_NEVER = 2;
  86. /**
  87. * There are 3 ways in which a scroll bar can be displayed.
  88. * This integer will represent one of these 3 displays -
  89. * (SCROLLBARS_ALWAYS, SCROLLBARS_AS_NEEDED, SCROLLBARS_NEVER)
  90. *
  91. * @serial
  92. * @see getScrollbarDisplayPolicy()
  93. */
  94. private int scrollbarDisplayPolicy;
  95. /**
  96. * An adjustable Vertical Scrollbar.
  97. * It is important to not that you must NOT call 3 Adjustable methods
  98. * ie : setMinimum(), setMaximum(), setVisibleAmount().
  99. *
  100. * @serial
  101. * @see getVAdjustable()
  102. * @see java.awt.Adjustable
  103. */
  104. private ScrollPaneAdjustable vAdjustable;
  105. /**
  106. * An adjustable Horizontal Scrollbar.
  107. * It is important to not that you must NOT call 3 Adjustable method
  108. * ie : setMinimum(), setMaximum(), setVisibleAmount().
  109. *
  110. * @serial
  111. * @see getHAdjustable()
  112. * @see java.awt.Adjustable
  113. */
  114. private ScrollPaneAdjustable hAdjustable;
  115. private static final String base = "scrollpane";
  116. private static int nameCounter = 0;
  117. /*
  118. * JDK 1.1 serialVersionUID
  119. */
  120. private static final long serialVersionUID = 7956609840827222915L;
  121. /**
  122. * Create a new scrollpane container with a scrollbar display policy of
  123. * "as needed".
  124. */
  125. public ScrollPane() {
  126. this(SCROLLBARS_AS_NEEDED);
  127. }
  128. /**
  129. * Create a new scrollpane container.
  130. * @param scrollbarDisplayPolicy policy for when scrollbars should be shown
  131. */
  132. public ScrollPane(int scrollbarDisplayPolicy) {
  133. this.layoutMgr = null;
  134. this.width = 100;
  135. this.height = 100;
  136. switch (scrollbarDisplayPolicy) {
  137. case SCROLLBARS_NEVER:
  138. case SCROLLBARS_AS_NEEDED:
  139. case SCROLLBARS_ALWAYS:
  140. this.scrollbarDisplayPolicy = scrollbarDisplayPolicy;
  141. break;
  142. default:
  143. throw new IllegalArgumentException("illegal scrollbar display policy");
  144. }
  145. vAdjustable = new ScrollPaneAdjustable(this, new PeerFixer(this),
  146. Adjustable.VERTICAL);
  147. hAdjustable = new ScrollPaneAdjustable(this, new PeerFixer(this),
  148. Adjustable.HORIZONTAL);
  149. }
  150. /**
  151. * Construct a name for this component. Called by getName() when the
  152. * name is null.
  153. */
  154. String constructComponentName() {
  155. synchronized (getClass()) {
  156. return base + nameCounter++;
  157. }
  158. }
  159. /**
  160. * Adds the specified component to this scroll pane container.
  161. * If the scroll pane has an existing child component, that
  162. * component is removed and the new one is added.
  163. * @param comp the component to be added
  164. * @param constraints not applicable
  165. * @param index position of child component (must be <= 0)
  166. */
  167. protected final void addImpl(Component comp, Object constraints, int index) {
  168. synchronized (getTreeLock()) {
  169. if (getComponentCount() > 0) {
  170. remove(0);
  171. }
  172. if (index > 0) {
  173. throw new IllegalArgumentException("position greater than 0");
  174. }
  175. super.addImpl(comp, constraints, index);
  176. }
  177. }
  178. /**
  179. * Returns the display policy for the scrollbars.
  180. * @return the display policy for the scrollbars
  181. */
  182. public int getScrollbarDisplayPolicy() {
  183. return scrollbarDisplayPolicy;
  184. }
  185. /**
  186. * Returns the current size of the scroll pane's view port.
  187. * @return the size of the view port in pixels
  188. */
  189. public Dimension getViewportSize() {
  190. Insets i = getInsets();
  191. return new Dimension(width - i.right - i.left,
  192. height - i.top - i.bottom);
  193. }
  194. /**
  195. * Returns the height that would be occupied by a horizontal
  196. * scrollbar, which is independent of whether it is currently
  197. * displayed by the scroll pane or not.
  198. * @return the height of a horizontal scrollbar in pixels
  199. */
  200. public int getHScrollbarHeight() {
  201. int h = 0;
  202. if (scrollbarDisplayPolicy != SCROLLBARS_NEVER) {
  203. ScrollPanePeer peer = (ScrollPanePeer)this.peer;
  204. if (peer != null) {
  205. h = peer.getHScrollbarHeight();
  206. }
  207. }
  208. return h;
  209. }
  210. /**
  211. * Returns the width that would be occupied by a vertical
  212. * scrollbar, which is independent of whether it is currently
  213. * displayed by the scroll pane or not.
  214. * @return the width of a vertical scrollbar in pixels
  215. */
  216. public int getVScrollbarWidth() {
  217. int w = 0;
  218. if (scrollbarDisplayPolicy != SCROLLBARS_NEVER) {
  219. ScrollPanePeer peer = (ScrollPanePeer)this.peer;
  220. if (peer != null) {
  221. w = peer.getVScrollbarWidth();
  222. }
  223. }
  224. return w;
  225. }
  226. /**
  227. * Returns the Adjustable object which represents the state of
  228. * the vertical scrollbar.
  229. */
  230. public Adjustable getVAdjustable() {
  231. return vAdjustable;
  232. }
  233. /**
  234. * Returns the Adjustable object which represents the state of
  235. * the horizontal scrollbar.
  236. */
  237. public Adjustable getHAdjustable() {
  238. return hAdjustable;
  239. }
  240. /**
  241. * Scrolls to the specified position within the child component.
  242. * A call to this method is only valid if the scroll pane contains
  243. * a child. Specifying a position outside of the legal scrolling bounds
  244. * of the child will scroll to the closest legal position.
  245. * Legal bounds are defined to be the rectangle:
  246. * x = 0, y = 0, width = (child width - view port width),
  247. * height = (child height - view port height).
  248. * This is a convenience method which interfaces with the Adjustable
  249. * objects which represent the state of the scrollbars.
  250. * @param x the x position to scroll to
  251. * @param y the y position to scroll to
  252. */
  253. public void setScrollPosition(int x, int y) {
  254. synchronized (getTreeLock()) {
  255. if (ncomponents <= 0) {
  256. throw new NullPointerException("child is null");
  257. }
  258. hAdjustable.setValue(x);
  259. vAdjustable.setValue(y);
  260. }
  261. }
  262. /**
  263. * Scrolls to the specified position within the child component.
  264. * A call to this method is only valid if the scroll pane contains
  265. * a child and the specified position is within legal scrolling bounds
  266. * of the child. Specifying a position outside of the legal scrolling
  267. * bounds of the child will scroll to the closest legal position.
  268. * Legal bounds are defined to be the rectangle:
  269. * x = 0, y = 0, width = (child width - view port width),
  270. * height = (child height - view port height).
  271. * This is a convenience method which interfaces with the Adjustable
  272. * objects which represent the state of the scrollbars.
  273. * @param p the Point representing the position to scroll to
  274. */
  275. public void setScrollPosition(Point p) {
  276. setScrollPosition(p.x, p.y);
  277. }
  278. /**
  279. * Returns the current x,y position within the child which is displayed
  280. * at the 0,0 location of the scrolled panel's view port.
  281. * This is a convenience method which interfaces with the adjustable
  282. * objects which represent the state of the scrollbars.
  283. * @return the coordinate position for the current scroll position
  284. */
  285. public Point getScrollPosition() {
  286. if (ncomponents <= 0) {
  287. throw new NullPointerException("child is null");
  288. }
  289. return new Point(hAdjustable.getValue(), vAdjustable.getValue());
  290. }
  291. /**
  292. * Sets the layout manager for this container. This method is
  293. * overridden to prevent the layout mgr from being set.
  294. * @param mgr the specified layout manager
  295. */
  296. public final void setLayout(LayoutManager mgr) {
  297. throw new AWTError("ScrollPane controls layout");
  298. }
  299. /**
  300. * Lays out this container by resizing its child to its preferred size.
  301. * If the new preferred size of the child causes the current scroll
  302. * position to be invalid, the scroll position is set to the closest
  303. * valid position.
  304. *
  305. * @see Component#validate
  306. */
  307. public void doLayout() {
  308. layout();
  309. }
  310. /**
  311. * Determine the size to allocate the child component.
  312. * If the viewport area is bigger than the childs
  313. * preferred size then the child is allocated enough
  314. * to fill the viewport, otherwise the child is given
  315. * it's preferred size.
  316. */
  317. Dimension calculateChildSize() {
  318. //
  319. // calculate the view size, accounting for border but not scrollbars
  320. // - don't use right/bottom insets since they vary depending
  321. // on whether or not scrollbars were displayed on last resize
  322. //
  323. Dimension size = getSize();
  324. Insets insets = getInsets();
  325. int viewWidth = size.width - insets.left*2;
  326. int viewHeight = size.height - insets.top*2;
  327. //
  328. // determine whether or not horz or vert scrollbars will be displayed
  329. //
  330. boolean vbarOn;
  331. boolean hbarOn;
  332. Component child = getComponent(0);
  333. Dimension childSize = new Dimension(child.getPreferredSize());
  334. if (scrollbarDisplayPolicy == SCROLLBARS_AS_NEEDED) {
  335. vbarOn = childSize.height > viewHeight;
  336. hbarOn = childSize.width > viewWidth;
  337. } else if (scrollbarDisplayPolicy == SCROLLBARS_ALWAYS) {
  338. vbarOn = hbarOn = true;
  339. } else { // SCROLLBARS_NEVER
  340. vbarOn = hbarOn = false;
  341. }
  342. //
  343. // adjust predicted view size to account for scrollbars
  344. //
  345. int vbarWidth = getVScrollbarWidth();
  346. int hbarHeight = getHScrollbarHeight();
  347. if (vbarOn) {
  348. viewWidth -= vbarWidth;
  349. }
  350. if(hbarOn) {
  351. viewHeight -= hbarHeight;
  352. }
  353. //
  354. // if child is smaller than view, size it up
  355. //
  356. if (childSize.width < viewWidth) {
  357. childSize.width = viewWidth;
  358. }
  359. if (childSize.height < viewHeight) {
  360. childSize.height = viewHeight;
  361. }
  362. return childSize;
  363. }
  364. /**
  365. * @deprecated As of JDK version 1.1,
  366. * replaced by <code>doLayout()</code>.
  367. */
  368. public void layout() {
  369. if (ncomponents > 0) {
  370. Component c = getComponent(0);
  371. Point p = getScrollPosition();
  372. Dimension cs = calculateChildSize();
  373. Dimension vs = getViewportSize();
  374. Insets i = getInsets();
  375. c.reshape(i.left - p.x, i.top - p.y, cs.width, cs.height);
  376. ScrollPanePeer peer = (ScrollPanePeer)this.peer;
  377. if (peer != null) {
  378. peer.childResized(cs.width, cs.height);
  379. }
  380. // update adjustables... the viewport size may have changed
  381. // with the scrollbars coming or going so the viewport size
  382. // is updated before the adjustables.
  383. vs = getViewportSize();
  384. hAdjustable.setSpan(0, cs.width, vs.width);
  385. vAdjustable.setSpan(0, cs.height, vs.height);
  386. }
  387. }
  388. /**
  389. * Prints the component in this scroll pane.
  390. * @param g the specified Graphics window
  391. * @see Component#print
  392. * @see Component#printAll
  393. */
  394. public void printComponents(Graphics g) {
  395. if (ncomponents > 0) {
  396. Component c = component[0];
  397. Point p = c.getLocation();
  398. Dimension vs = getViewportSize();
  399. Insets i = getInsets();
  400. Graphics cg = g.create();
  401. try {
  402. cg.clipRect(i.left, i.top, vs.width, vs.height);
  403. cg.translate(p.x, p.y);
  404. c.printAll(cg);
  405. } finally {
  406. cg.dispose();
  407. }
  408. }
  409. }
  410. /**
  411. * Creates the scroll pane's peer.
  412. */
  413. public void addNotify() {
  414. synchronized (getTreeLock()) {
  415. int vAdjustableValue = 0;
  416. int hAdjustableValue = 0;
  417. // Bug 4124460. Save the current adjustable values,
  418. // so they can be restored after addnotify. Set the
  419. // adjustibles to 0, to prevent crashes for possible
  420. // negative values.
  421. if (getComponentCount() > 0) {
  422. vAdjustableValue = vAdjustable.getValue();
  423. hAdjustableValue = hAdjustable.getValue();
  424. vAdjustable.setValue(0);
  425. hAdjustable.setValue(0);
  426. }
  427. if (peer == null)
  428. peer = getToolkit().createScrollPane(this);
  429. super.addNotify();
  430. // Bug 4124460. Restore the adjustable values.
  431. if (getComponentCount() > 0) {
  432. vAdjustable.setValue(vAdjustableValue);
  433. hAdjustable.setValue(hAdjustableValue);
  434. }
  435. if (getComponentCount() > 0) {
  436. Component comp = getComponent(0);
  437. if (comp.peer instanceof java.awt.peer.LightweightPeer) {
  438. // The scrollpane won't work with a windowless child... it assumes
  439. // it is moving a child window around so the windowless child is
  440. // wrapped with a window.
  441. remove(0);
  442. Panel child = new Panel();
  443. child.setLayout(new BorderLayout());
  444. child.add(comp);
  445. add(child);
  446. }
  447. }
  448. }
  449. }
  450. public String paramString() {
  451. String sdpStr;
  452. switch (scrollbarDisplayPolicy) {
  453. case SCROLLBARS_AS_NEEDED:
  454. sdpStr = "as-needed";
  455. break;
  456. case SCROLLBARS_ALWAYS:
  457. sdpStr = "always";
  458. break;
  459. case SCROLLBARS_NEVER:
  460. sdpStr = "never";
  461. break;
  462. default:
  463. sdpStr = "invalid display policy";
  464. }
  465. Point p = ncomponents > 0? getScrollPosition() : new Point(0,0);
  466. Insets i = getInsets();
  467. return super.paramString()+",ScrollPosition=("+p.x+","+p.y+")"+
  468. ",Insets=("+i.top+","+i.left+","+i.bottom+","+i.right+")"+
  469. ",ScrollbarDisplayPolicy="+sdpStr;
  470. }
  471. class PeerFixer implements AdjustmentListener, java.io.Serializable {
  472. PeerFixer(ScrollPane scroller) {
  473. this.scroller = scroller;
  474. }
  475. /**
  476. * Invoked when the value of the adjustable has changed.
  477. */
  478. public void adjustmentValueChanged(AdjustmentEvent e) {
  479. Adjustable adj = e.getAdjustable();
  480. int value = e.getValue();
  481. ScrollPanePeer peer = (ScrollPanePeer) scroller.peer;
  482. if (peer != null) {
  483. peer.setValue(adj, value);
  484. }
  485. Component c = scroller.getComponent(0);
  486. switch(adj.getOrientation()) {
  487. case Adjustable.VERTICAL:
  488. c.move(c.getLocation().x, -(value));
  489. break;
  490. case Adjustable.HORIZONTAL:
  491. c.move(-(value), c.getLocation().y);
  492. break;
  493. default:
  494. throw new IllegalArgumentException("Illegal adjustable orientation");
  495. }
  496. }
  497. private ScrollPane scroller;
  498. }
  499. /////////////////
  500. // Accessibility support
  501. ////////////////
  502. /**
  503. * Gets the AccessibleContext associated with this ScrollPane.
  504. * For scroll panes, the AccessibleContext takes the form of an
  505. * AccessibleAWTScrollPane.
  506. * A new AccessibleAWTScrollPane instance is created if necessary.
  507. *
  508. * @return an AccessibleAWTScrollPane that serves as the
  509. * AccessibleContext of this ScrollPane
  510. */
  511. public AccessibleContext getAccessibleContext() {
  512. if (accessibleContext == null) {
  513. accessibleContext = new AccessibleAWTScrollPane();
  514. }
  515. return accessibleContext;
  516. }
  517. /**
  518. * This class implements accessibility support for the
  519. * <code>ScrollPane</code> class. It provides an implementation of the
  520. * Java Accessibility API appropriate to scroll pane user-interface
  521. * elements.
  522. */
  523. protected class AccessibleAWTScrollPane extends AccessibleAWTContainer {
  524. /**
  525. * Get the role of this object.
  526. *
  527. * @return an instance of AccessibleRole describing the role of the
  528. * object
  529. * @see AccessibleRole
  530. */
  531. public AccessibleRole getAccessibleRole() {
  532. return AccessibleRole.SCROLL_PANE;
  533. }
  534. } // class AccessibleAWTScrollPane
  535. }
  536. /*
  537. * In JDK 1.1.1, the pkg private class java.awt.PeerFixer was moved to
  538. * become an inner class of ScrollPane, which broke serialization
  539. * for ScrollPane objects using JDK 1.1.
  540. * Instead of moving it back out here, which would break all JDK 1.1.x
  541. * releases, we keep PeerFixer in both places. Because of the scoping rules,
  542. * the PeerFixer that is used in ScrollPane will be the one that is the
  543. * inner class. This pkg private PeerFixer class below will only be used
  544. * if the Java 2 platform is used to deserialize ScrollPane objects that were serialized
  545. * using JDK1.1
  546. */
  547. class PeerFixer implements AdjustmentListener, java.io.Serializable {
  548. PeerFixer(ScrollPane scroller) {
  549. this.scroller = scroller;
  550. }
  551. /**
  552. * Invoked when the value of the adjustable has changed.
  553. */
  554. public void adjustmentValueChanged(AdjustmentEvent e) {
  555. Adjustable adj = e.getAdjustable();
  556. int value = e.getValue();
  557. ScrollPanePeer peer = (ScrollPanePeer) scroller.peer;
  558. if (peer != null) {
  559. peer.setValue(adj, value);
  560. }
  561. Component c = scroller.getComponent(0);
  562. switch(adj.getOrientation()) {
  563. case Adjustable.VERTICAL:
  564. c.move(c.getLocation().x, -(value));
  565. break;
  566. case Adjustable.HORIZONTAL:
  567. c.move(-(value), c.getLocation().y);
  568. break;
  569. default:
  570. throw new IllegalArgumentException("Illegal adjustable orientation");
  571. }
  572. }
  573. private ScrollPane scroller;
  574. }
  575. class ScrollPaneAdjustable implements Adjustable, java.io.Serializable {
  576. private ScrollPane sp;
  577. private int orientation;
  578. private int minimum;
  579. private int maximum;
  580. private int visibleAmount;
  581. private int unitIncrement = 1;
  582. private int blockIncrement = 1;
  583. private int value;
  584. private AdjustmentListener adjustmentListener;
  585. private static final String SCROLLPANE_ONLY =
  586. "Can be set by scrollpane only";
  587. /**
  588. * Initialize JNI field and method ids
  589. */
  590. private static native void initIDs();
  591. static {
  592. Toolkit.loadLibraries();
  593. initIDs();
  594. }
  595. /*
  596. * JDK 1.1 serialVersionUID
  597. */
  598. private static final long serialVersionUID = -3359745691033257079L;
  599. public ScrollPaneAdjustable(ScrollPane sp, AdjustmentListener l, int orientation) {
  600. this.sp = sp;
  601. this.orientation = orientation;
  602. addAdjustmentListener(l);
  603. }
  604. /**
  605. * This is called by the scrollpane itself to update the
  606. * min,max,visible values. The scrollpane is the only one
  607. * that should be changing these since it is the source of
  608. * these values.
  609. */
  610. void setSpan(int min, int max, int visible) {
  611. // adjust the values to be reasonable
  612. minimum = min;
  613. maximum = Math.max(max, minimum + 1);
  614. visibleAmount = Math.min(visible, maximum - minimum);
  615. visibleAmount = Math.max(visibleAmount, 1);
  616. blockIncrement = Math.max((int)(visible * .90), 1);
  617. setValue(value);
  618. }
  619. public int getOrientation() {
  620. return orientation;
  621. }
  622. public void setMinimum(int min) {
  623. throw new AWTError(SCROLLPANE_ONLY);
  624. }
  625. public int getMinimum() {
  626. return 0;
  627. }
  628. public void setMaximum(int max) {
  629. throw new AWTError(SCROLLPANE_ONLY);
  630. }
  631. public int getMaximum() {
  632. return maximum;
  633. }
  634. public synchronized void setUnitIncrement(int u) {
  635. if (u != unitIncrement) {
  636. unitIncrement = u;
  637. if (sp.peer != null) {
  638. ScrollPanePeer peer = (ScrollPanePeer) sp.peer;
  639. peer.setUnitIncrement(this, u);
  640. }
  641. }
  642. }
  643. public int getUnitIncrement() {
  644. return unitIncrement;
  645. }
  646. public synchronized void setBlockIncrement(int b) {
  647. blockIncrement = b;
  648. }
  649. public int getBlockIncrement() {
  650. return blockIncrement;
  651. }
  652. public void setVisibleAmount(int v) {
  653. throw new AWTError(SCROLLPANE_ONLY);
  654. }
  655. public int getVisibleAmount() {
  656. return visibleAmount;
  657. }
  658. public void setValue(int v) {
  659. // bounds check
  660. v = Math.max(v, minimum);
  661. v = Math.min(v, maximum - visibleAmount);
  662. if (v != value) {
  663. value = v;
  664. // Synchronously notify the listeners so that they are
  665. // guaranteed to be up-to-date with the Adjustable before
  666. // it is mutated again.
  667. AdjustmentEvent e =
  668. new AdjustmentEvent(this, AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED,
  669. AdjustmentEvent.TRACK, value);
  670. adjustmentListener.adjustmentValueChanged(e);
  671. }
  672. }
  673. public int getValue() {
  674. return value;
  675. }
  676. /**
  677. * Adds the specified adjustment listener to receive adjustment events
  678. * from this ScrollPane.
  679. * If l is null, no exception is thrown and no action is performed.
  680. *
  681. * @param l the adjustment listener.
  682. * @see java.awt.event.AdjustmentListener
  683. * @see java.awt.ScrollPane#removeAdjustmentListener
  684. */
  685. public synchronized void addAdjustmentListener(AdjustmentListener l) {
  686. if (l == null) {
  687. return;
  688. }
  689. adjustmentListener = AWTEventMulticaster.add(adjustmentListener, l);
  690. }
  691. /**
  692. * Removes the specified adjustment listener so that it no longer
  693. * receives adjustment events from this button.
  694. * If l is null, no exception is thrown and no action is performed.
  695. *
  696. * @param l the adjustment listener.
  697. * @see java.awt.event.AdjustmentListener
  698. * @see java.awt.Button#addAdjustmentListener
  699. * @since JDK1.1
  700. */
  701. public synchronized void removeAdjustmentListener(AdjustmentListener l){
  702. if (l == null) {
  703. return;
  704. }
  705. adjustmentListener = AWTEventMulticaster.remove(adjustmentListener, l);
  706. }
  707. public String toString() {
  708. return getClass().getName() + "[" + paramString() + "]";
  709. }
  710. public String paramString() {
  711. return ((orientation==Adjustable.VERTICAL?"vertical,":"horizontal,")+
  712. "[0.."+maximum+"],"+"val="+value+",vis="+visibleAmount+
  713. ",unit="+unitIncrement+",block="+blockIncrement);
  714. }
  715. }