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