1. /*
  2. * @(#)BasicScrollPaneUI.java 1.70 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.plaf.basic;
  8. import sun.swing.DefaultLookup;
  9. import sun.swing.UIAction;
  10. import javax.swing.*;
  11. import javax.swing.event.*;
  12. import javax.swing.border.*;
  13. import javax.swing.plaf.*;
  14. import java.beans.PropertyChangeListener;
  15. import java.beans.PropertyChangeEvent;
  16. import java.awt.Component;
  17. import java.awt.Container;
  18. import java.awt.LayoutManager;
  19. import java.awt.Rectangle;
  20. import java.awt.Dimension;
  21. import java.awt.Point;
  22. import java.awt.Insets;
  23. import java.awt.Graphics;
  24. import java.awt.event.*;
  25. import java.io.Serializable;
  26. import java.awt.Toolkit;
  27. /**
  28. * A default L&F implementation of ScrollPaneUI.
  29. *
  30. * @version 1.70 12/19/03
  31. * @author Hans Muller
  32. */
  33. public class BasicScrollPaneUI
  34. extends ScrollPaneUI implements ScrollPaneConstants
  35. {
  36. protected JScrollPane scrollpane;
  37. protected ChangeListener vsbChangeListener;
  38. protected ChangeListener hsbChangeListener;
  39. protected ChangeListener viewportChangeListener;
  40. protected PropertyChangeListener spPropertyChangeListener;
  41. private MouseWheelListener mouseScrollListener;
  42. /**
  43. * PropertyChangeListener installed on the vertical scrollbar.
  44. */
  45. private PropertyChangeListener vsbPropertyChangeListener;
  46. /**
  47. * PropertyChangeListener installed on the horizontal scrollbar.
  48. */
  49. private PropertyChangeListener hsbPropertyChangeListener;
  50. private Handler handler;
  51. /**
  52. * State flag that shows whether setValue() was called from a user program
  53. * before the value of "extent" was set in right-to-left component
  54. * orientation.
  55. */
  56. private boolean setValueCalled = false;
  57. public static ComponentUI createUI(JComponent x) {
  58. return new BasicScrollPaneUI();
  59. }
  60. static void loadActionMap(LazyActionMap map) {
  61. map.put(new Actions(Actions.SCROLL_UP));
  62. map.put(new Actions(Actions.SCROLL_DOWN));
  63. map.put(new Actions(Actions.SCROLL_HOME));
  64. map.put(new Actions(Actions.SCROLL_END));
  65. map.put(new Actions(Actions.UNIT_SCROLL_UP));
  66. map.put(new Actions(Actions.UNIT_SCROLL_DOWN));
  67. map.put(new Actions(Actions.SCROLL_LEFT));
  68. map.put(new Actions(Actions.SCROLL_RIGHT));
  69. map.put(new Actions(Actions.UNIT_SCROLL_RIGHT));
  70. map.put(new Actions(Actions.UNIT_SCROLL_LEFT));
  71. }
  72. public void paint(Graphics g, JComponent c) {
  73. Border vpBorder = scrollpane.getViewportBorder();
  74. if (vpBorder != null) {
  75. Rectangle r = scrollpane.getViewportBorderBounds();
  76. vpBorder.paintBorder(scrollpane, g, r.x, r.y, r.width, r.height);
  77. }
  78. }
  79. /**
  80. * @return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE)
  81. */
  82. public Dimension getMaximumSize(JComponent c) {
  83. return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
  84. }
  85. protected void installDefaults(JScrollPane scrollpane)
  86. {
  87. LookAndFeel.installBorder(scrollpane, "ScrollPane.border");
  88. LookAndFeel.installColorsAndFont(scrollpane,
  89. "ScrollPane.background",
  90. "ScrollPane.foreground",
  91. "ScrollPane.font");
  92. Border vpBorder = scrollpane.getViewportBorder();
  93. if ((vpBorder == null) ||( vpBorder instanceof UIResource)) {
  94. vpBorder = UIManager.getBorder("ScrollPane.viewportBorder");
  95. scrollpane.setViewportBorder(vpBorder);
  96. }
  97. LookAndFeel.installProperty(scrollpane, "opaque", Boolean.TRUE);
  98. }
  99. protected void installListeners(JScrollPane c)
  100. {
  101. vsbChangeListener = createVSBChangeListener();
  102. vsbPropertyChangeListener = createVSBPropertyChangeListener();
  103. hsbChangeListener = createHSBChangeListener();
  104. hsbPropertyChangeListener = createHSBPropertyChangeListener();
  105. viewportChangeListener = createViewportChangeListener();
  106. spPropertyChangeListener = createPropertyChangeListener();
  107. JViewport viewport = scrollpane.getViewport();
  108. JScrollBar vsb = scrollpane.getVerticalScrollBar();
  109. JScrollBar hsb = scrollpane.getHorizontalScrollBar();
  110. if (viewport != null) {
  111. viewport.addChangeListener(viewportChangeListener);
  112. }
  113. if (vsb != null) {
  114. vsb.getModel().addChangeListener(vsbChangeListener);
  115. vsb.addPropertyChangeListener(vsbPropertyChangeListener);
  116. }
  117. if (hsb != null) {
  118. hsb.getModel().addChangeListener(hsbChangeListener);
  119. hsb.addPropertyChangeListener(hsbPropertyChangeListener);
  120. }
  121. scrollpane.addPropertyChangeListener(spPropertyChangeListener);
  122. mouseScrollListener = createMouseWheelListener();
  123. scrollpane.addMouseWheelListener(mouseScrollListener);
  124. }
  125. protected void installKeyboardActions(JScrollPane c) {
  126. InputMap inputMap = getInputMap(JComponent.
  127. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  128. SwingUtilities.replaceUIInputMap(c, JComponent.
  129. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
  130. LazyActionMap.installLazyActionMap(c, BasicScrollPaneUI.class,
  131. "ScrollPane.actionMap");
  132. }
  133. InputMap getInputMap(int condition) {
  134. if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
  135. InputMap keyMap = (InputMap)DefaultLookup.get(scrollpane, this,
  136. "ScrollPane.ancestorInputMap");
  137. InputMap rtlKeyMap;
  138. if (scrollpane.getComponentOrientation().isLeftToRight() ||
  139. ((rtlKeyMap = (InputMap)DefaultLookup.get(scrollpane, this,
  140. "ScrollPane.ancestorInputMap.RightToLeft")) == null)) {
  141. return keyMap;
  142. } else {
  143. rtlKeyMap.setParent(keyMap);
  144. return rtlKeyMap;
  145. }
  146. }
  147. return null;
  148. }
  149. public void installUI(JComponent x) {
  150. scrollpane = (JScrollPane)x;
  151. installDefaults(scrollpane);
  152. installListeners(scrollpane);
  153. installKeyboardActions(scrollpane);
  154. }
  155. protected void uninstallDefaults(JScrollPane c) {
  156. LookAndFeel.uninstallBorder(scrollpane);
  157. if (scrollpane.getViewportBorder() instanceof UIResource) {
  158. scrollpane.setViewportBorder(null);
  159. }
  160. }
  161. protected void uninstallListeners(JComponent c) {
  162. JViewport viewport = scrollpane.getViewport();
  163. JScrollBar vsb = scrollpane.getVerticalScrollBar();
  164. JScrollBar hsb = scrollpane.getHorizontalScrollBar();
  165. if (viewport != null) {
  166. viewport.removeChangeListener(viewportChangeListener);
  167. }
  168. if (vsb != null) {
  169. vsb.getModel().removeChangeListener(vsbChangeListener);
  170. vsb.removePropertyChangeListener(vsbPropertyChangeListener);
  171. }
  172. if (hsb != null) {
  173. hsb.getModel().removeChangeListener(hsbChangeListener);
  174. hsb.removePropertyChangeListener(hsbPropertyChangeListener);
  175. }
  176. scrollpane.removePropertyChangeListener(spPropertyChangeListener);
  177. if (mouseScrollListener != null) {
  178. scrollpane.removeMouseWheelListener(mouseScrollListener);
  179. }
  180. vsbChangeListener = null;
  181. hsbChangeListener = null;
  182. viewportChangeListener = null;
  183. spPropertyChangeListener = null;
  184. mouseScrollListener = null;
  185. handler = null;
  186. }
  187. protected void uninstallKeyboardActions(JScrollPane c) {
  188. SwingUtilities.replaceUIActionMap(c, null);
  189. SwingUtilities.replaceUIInputMap(c, JComponent.
  190. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
  191. }
  192. public void uninstallUI(JComponent c) {
  193. uninstallDefaults(scrollpane);
  194. uninstallListeners(scrollpane);
  195. uninstallKeyboardActions(scrollpane);
  196. scrollpane = null;
  197. }
  198. private Handler getHandler() {
  199. if (handler == null) {
  200. handler = new Handler();
  201. }
  202. return handler;
  203. }
  204. protected void syncScrollPaneWithViewport()
  205. {
  206. JViewport viewport = scrollpane.getViewport();
  207. JScrollBar vsb = scrollpane.getVerticalScrollBar();
  208. JScrollBar hsb = scrollpane.getHorizontalScrollBar();
  209. JViewport rowHead = scrollpane.getRowHeader();
  210. JViewport colHead = scrollpane.getColumnHeader();
  211. boolean ltr = scrollpane.getComponentOrientation().isLeftToRight();
  212. if (viewport != null) {
  213. Dimension extentSize = viewport.getExtentSize();
  214. Dimension viewSize = viewport.getViewSize();
  215. Point viewPosition = viewport.getViewPosition();
  216. if (vsb != null) {
  217. int extent = extentSize.height;
  218. int max = viewSize.height;
  219. int value = Math.max(0, Math.min(viewPosition.y, max - extent));
  220. vsb.setValues(value, extent, 0, max);
  221. }
  222. if (hsb != null) {
  223. int extent = extentSize.width;
  224. int max = viewSize.width;
  225. int value;
  226. if (ltr) {
  227. value = Math.max(0, Math.min(viewPosition.x, max - extent));
  228. } else {
  229. int currentValue = hsb.getValue();
  230. /* Use a particular formula to calculate "value"
  231. * until effective x coordinate is calculated.
  232. */
  233. if (setValueCalled && ((max - currentValue) == viewPosition.x)) {
  234. value = Math.max(0, Math.min(max - extent, currentValue));
  235. /* After "extent" is set, turn setValueCalled flag off.
  236. */
  237. if (extent != 0) {
  238. setValueCalled = false;
  239. }
  240. } else {
  241. if (extent > max) {
  242. viewPosition.x = max - extent;
  243. viewport.setViewPosition(viewPosition);
  244. value = 0;
  245. } else {
  246. /* The following line can't handle a small value of
  247. * viewPosition.x like Integer.MIN_VALUE correctly
  248. * because (max - extent - viewPositoiin.x) causes
  249. * an overflow. As a result, value becomes zero.
  250. * (e.g. setViewPosition(Integer.MAX_VALUE, ...)
  251. * in a user program causes a overflow.
  252. * Its expected value is (max - extent).)
  253. * However, this seems a trivial bug and adding a
  254. * fix makes this often-called method slow, so I'll
  255. * leave it until someone claims.
  256. */
  257. value = Math.max(0, Math.min(max - extent, max - extent - viewPosition.x));
  258. }
  259. }
  260. }
  261. hsb.setValues(value, extent, 0, max);
  262. }
  263. if (rowHead != null) {
  264. Point p = rowHead.getViewPosition();
  265. p.y = viewport.getViewPosition().y;
  266. p.x = 0;
  267. rowHead.setViewPosition(p);
  268. }
  269. if (colHead != null) {
  270. Point p = colHead.getViewPosition();
  271. if (ltr) {
  272. p.x = viewport.getViewPosition().x;
  273. } else {
  274. p.x = Math.max(0, viewport.getViewPosition().x);
  275. }
  276. p.y = 0;
  277. colHead.setViewPosition(p);
  278. }
  279. }
  280. }
  281. /**
  282. * Listener for viewport events.
  283. */
  284. public class ViewportChangeHandler implements ChangeListener
  285. {
  286. // NOTE: This class exists only for backward compatability. All
  287. // its functionality has been moved into Handler. If you need to add
  288. // new functionality add it to the Handler, but make sure this
  289. // class calls into the Handler.
  290. public void stateChanged(ChangeEvent e) {
  291. getHandler().stateChanged(e);
  292. }
  293. }
  294. protected ChangeListener createViewportChangeListener() {
  295. return getHandler();
  296. }
  297. /**
  298. * Horizontal scrollbar listener.
  299. */
  300. public class HSBChangeListener implements ChangeListener
  301. {
  302. // NOTE: This class exists only for backward compatability. All
  303. // its functionality has been moved into Handler. If you need to add
  304. // new functionality add it to the Handler, but make sure this
  305. // class calls into the Handler.
  306. public void stateChanged(ChangeEvent e)
  307. {
  308. getHandler().stateChanged(e);
  309. }
  310. }
  311. /**
  312. * Returns a <code>PropertyChangeListener</code> that will be installed
  313. * on the horizontal <code>JScrollBar</code>.
  314. */
  315. private PropertyChangeListener createHSBPropertyChangeListener() {
  316. return getHandler();
  317. }
  318. protected ChangeListener createHSBChangeListener() {
  319. return getHandler();
  320. }
  321. /**
  322. * Vertical scrollbar listener.
  323. */
  324. public class VSBChangeListener implements ChangeListener
  325. {
  326. // NOTE: This class exists only for backward compatability. All
  327. // its functionality has been moved into Handler. If you need to add
  328. // new functionality add it to the Handler, but make sure this
  329. // class calls into the Handler.
  330. public void stateChanged(ChangeEvent e)
  331. {
  332. getHandler().stateChanged(e);
  333. }
  334. }
  335. /**
  336. * Returns a <code>PropertyChangeListener</code> that will be installed
  337. * on the vertical <code>JScrollBar</code>.
  338. */
  339. private PropertyChangeListener createVSBPropertyChangeListener() {
  340. return getHandler();
  341. }
  342. protected ChangeListener createVSBChangeListener() {
  343. return getHandler();
  344. }
  345. /**
  346. * MouseWheelHandler is an inner class which implements the
  347. * MouseWheelListener interface. MouseWheelHandler responds to
  348. * MouseWheelEvents by scrolling the JScrollPane appropriately.
  349. * If the scroll pane's
  350. * <code>isWheelScrollingEnabled</code>
  351. * method returns false, no scrolling occurs.
  352. *
  353. * @see javax.swing.JScrollPane#isWheelScrollingEnabled
  354. * @see #createMouseWheelListener
  355. * @see java.awt.event.MouseWheelListener
  356. * @see java.awt.event.MouseWheelEvent
  357. * @since 1.4
  358. */
  359. protected class MouseWheelHandler implements MouseWheelListener {
  360. // NOTE: This class exists only for backward compatability. All
  361. // its functionality has been moved into Handler. If you need to add
  362. // new functionality add it to the Handler, but make sure this
  363. // class calls into the Handler.
  364. /**
  365. * Called when the mouse wheel is rotated while over a
  366. * JScrollPane.
  367. *
  368. * @param e MouseWheelEvent to be handled
  369. * @since 1.4
  370. */
  371. public void mouseWheelMoved(MouseWheelEvent e) {
  372. getHandler().mouseWheelMoved(e);
  373. }
  374. }
  375. /**
  376. * Creates an instance of MouseWheelListener, which is added to the
  377. * JScrollPane by installUI(). The returned MouseWheelListener is used
  378. * to handle mouse wheel-driven scrolling.
  379. *
  380. * @return MouseWheelListener which implements wheel-driven scrolling
  381. * @see #installUI
  382. * @see MouseWheelHandler
  383. * @since 1.4
  384. */
  385. protected MouseWheelListener createMouseWheelListener() {
  386. return getHandler();
  387. }
  388. protected void updateScrollBarDisplayPolicy(PropertyChangeEvent e) {
  389. scrollpane.revalidate();
  390. scrollpane.repaint();
  391. }
  392. protected void updateViewport(PropertyChangeEvent e)
  393. {
  394. JViewport oldViewport = (JViewport)(e.getOldValue());
  395. JViewport newViewport = (JViewport)(e.getNewValue());
  396. if (oldViewport != null) {
  397. oldViewport.removeChangeListener(viewportChangeListener);
  398. }
  399. if (newViewport != null) {
  400. Point p = newViewport.getViewPosition();
  401. if (scrollpane.getComponentOrientation().isLeftToRight()) {
  402. p.x = Math.max(p.x, 0);
  403. } else {
  404. int max = newViewport.getViewSize().width;
  405. int extent = newViewport.getExtentSize().width;
  406. if (extent > max) {
  407. p.x = max - extent;
  408. } else {
  409. p.x = Math.max(0, Math.min(max - extent, p.x));
  410. }
  411. }
  412. p.y = Math.max(p.y, 0);
  413. newViewport.setViewPosition(p);
  414. newViewport.addChangeListener(viewportChangeListener);
  415. }
  416. }
  417. protected void updateRowHeader(PropertyChangeEvent e)
  418. {
  419. JViewport newRowHead = (JViewport)(e.getNewValue());
  420. if (newRowHead != null) {
  421. JViewport viewport = scrollpane.getViewport();
  422. Point p = newRowHead.getViewPosition();
  423. p.y = (viewport != null) ? viewport.getViewPosition().y : 0;
  424. newRowHead.setViewPosition(p);
  425. }
  426. }
  427. protected void updateColumnHeader(PropertyChangeEvent e)
  428. {
  429. JViewport newColHead = (JViewport)(e.getNewValue());
  430. if (newColHead != null) {
  431. JViewport viewport = scrollpane.getViewport();
  432. Point p = newColHead.getViewPosition();
  433. if (viewport == null) {
  434. p.x = 0;
  435. } else {
  436. if (scrollpane.getComponentOrientation().isLeftToRight()) {
  437. p.x = viewport.getViewPosition().x;
  438. } else {
  439. p.x = Math.max(0, viewport.getViewPosition().x);
  440. }
  441. }
  442. newColHead.setViewPosition(p);
  443. scrollpane.add(newColHead, COLUMN_HEADER);
  444. }
  445. }
  446. private void updateHorizontalScrollBar(PropertyChangeEvent pce) {
  447. updateScrollBar(pce, hsbChangeListener, hsbPropertyChangeListener);
  448. }
  449. private void updateVerticalScrollBar(PropertyChangeEvent pce) {
  450. updateScrollBar(pce, vsbChangeListener, vsbPropertyChangeListener);
  451. }
  452. private void updateScrollBar(PropertyChangeEvent pce, ChangeListener cl,
  453. PropertyChangeListener pcl) {
  454. JScrollBar sb = (JScrollBar)pce.getOldValue();
  455. if (sb != null) {
  456. if (cl != null) {
  457. sb.getModel().removeChangeListener(cl);
  458. }
  459. if (pcl != null) {
  460. sb.removePropertyChangeListener(pcl);
  461. }
  462. }
  463. sb = (JScrollBar)pce.getNewValue();
  464. if (sb != null) {
  465. if (cl != null) {
  466. sb.getModel().addChangeListener(cl);
  467. }
  468. if (pcl != null) {
  469. sb.addPropertyChangeListener(pcl);
  470. }
  471. }
  472. }
  473. public class PropertyChangeHandler implements PropertyChangeListener
  474. {
  475. // NOTE: This class exists only for backward compatability. All
  476. // its functionality has been moved into Handler. If you need to add
  477. // new functionality add it to the Handler, but make sure this
  478. // class calls into the Handler.
  479. public void propertyChange(PropertyChangeEvent e)
  480. {
  481. getHandler().propertyChange(e);
  482. }
  483. }
  484. /**
  485. * Creates an instance of PropertyChangeListener that's added to
  486. * the JScrollPane by installUI(). Subclasses can override this method
  487. * to return a custom PropertyChangeListener, e.g.
  488. * <pre>
  489. * class MyScrollPaneUI extends BasicScrollPaneUI {
  490. * protected PropertyChangeListener <b>createPropertyChangeListener</b>() {
  491. * return new MyPropertyChangeListener();
  492. * }
  493. * public class MyPropertyChangeListener extends PropertyChangeListener {
  494. * public void propertyChange(PropertyChangeEvent e) {
  495. * if (e.getPropertyName().equals("viewport")) {
  496. * // do some extra work when the viewport changes
  497. * }
  498. * super.propertyChange(e);
  499. * }
  500. * }
  501. * }
  502. * </pre>
  503. *
  504. * @see java.beans.PropertyChangeListener
  505. * @see #installUI
  506. */
  507. protected PropertyChangeListener createPropertyChangeListener() {
  508. return getHandler();
  509. }
  510. private static class Actions extends UIAction {
  511. private static final String SCROLL_UP = "scrollUp";
  512. private static final String SCROLL_DOWN = "scrollDown";
  513. private static final String SCROLL_HOME = "scrollHome";
  514. private static final String SCROLL_END = "scrollEnd";
  515. private static final String UNIT_SCROLL_UP = "unitScrollUp";
  516. private static final String UNIT_SCROLL_DOWN = "unitScrollDown";
  517. private static final String SCROLL_LEFT = "scrollLeft";
  518. private static final String SCROLL_RIGHT = "scrollRight";
  519. private static final String UNIT_SCROLL_LEFT = "unitScrollLeft";
  520. private static final String UNIT_SCROLL_RIGHT = "unitScrollRight";
  521. Actions(String key) {
  522. super(key);
  523. }
  524. public void actionPerformed(ActionEvent e) {
  525. JScrollPane scrollPane = (JScrollPane)e.getSource();
  526. boolean ltr = scrollPane.getComponentOrientation().isLeftToRight();
  527. String key = getName();
  528. if (key == SCROLL_UP) {
  529. scroll(scrollPane, SwingConstants.VERTICAL, -1, true);
  530. }
  531. else if (key == SCROLL_DOWN) {
  532. scroll(scrollPane, SwingConstants.VERTICAL, 1, true);
  533. }
  534. else if (key == SCROLL_HOME) {
  535. scrollHome(scrollPane);
  536. }
  537. else if (key == SCROLL_END) {
  538. scrollEnd(scrollPane);
  539. }
  540. else if (key == UNIT_SCROLL_UP) {
  541. scroll(scrollPane, SwingConstants.VERTICAL, -1, false);
  542. }
  543. else if (key == UNIT_SCROLL_DOWN) {
  544. scroll(scrollPane, SwingConstants.VERTICAL, 1, false);
  545. }
  546. else if (key == SCROLL_LEFT) {
  547. scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? -1 : 1,
  548. true);
  549. }
  550. else if (key == SCROLL_RIGHT) {
  551. scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? 1 : -1,
  552. true);
  553. }
  554. else if (key == UNIT_SCROLL_LEFT) {
  555. scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? -1 : 1,
  556. false);
  557. }
  558. else if (key == UNIT_SCROLL_RIGHT) {
  559. scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? 1 : -1,
  560. false);
  561. }
  562. }
  563. private void scrollEnd(JScrollPane scrollpane) {
  564. JViewport vp = scrollpane.getViewport();
  565. Component view;
  566. if (vp != null && (view = vp.getView()) != null) {
  567. Rectangle visRect = vp.getViewRect();
  568. Rectangle bounds = view.getBounds();
  569. if (scrollpane.getComponentOrientation().isLeftToRight()) {
  570. vp.setViewPosition(new Point(bounds.width - visRect.width,
  571. bounds.height - visRect.height));
  572. } else {
  573. vp.setViewPosition(new Point(0,
  574. bounds.height - visRect.height));
  575. }
  576. }
  577. }
  578. private void scrollHome(JScrollPane scrollpane) {
  579. JViewport vp = scrollpane.getViewport();
  580. Component view;
  581. if (vp != null && (view = vp.getView()) != null) {
  582. if (scrollpane.getComponentOrientation().isLeftToRight()) {
  583. vp.setViewPosition(new Point(0, 0));
  584. } else {
  585. Rectangle visRect = vp.getViewRect();
  586. Rectangle bounds = view.getBounds();
  587. vp.setViewPosition(new Point(bounds.width - visRect.width, 0));
  588. }
  589. }
  590. }
  591. private void scroll(JScrollPane scrollpane, int orientation,
  592. int direction, boolean block) {
  593. JViewport vp = scrollpane.getViewport();
  594. Component view;
  595. if (vp != null && (view = vp.getView()) != null) {
  596. Rectangle visRect = vp.getViewRect();
  597. Dimension vSize = view.getSize();
  598. int amount;
  599. if (view instanceof Scrollable) {
  600. if (block) {
  601. amount = ((Scrollable)view).getScrollableBlockIncrement
  602. (visRect, orientation, direction);
  603. }
  604. else {
  605. amount = ((Scrollable)view).getScrollableUnitIncrement
  606. (visRect, orientation, direction);
  607. }
  608. }
  609. else {
  610. if (block) {
  611. if (orientation == SwingConstants.VERTICAL) {
  612. amount = visRect.height;
  613. }
  614. else {
  615. amount = visRect.width;
  616. }
  617. }
  618. else {
  619. amount = 10;
  620. }
  621. }
  622. if (orientation == SwingConstants.VERTICAL) {
  623. visRect.y += (amount * direction);
  624. if ((visRect.y + visRect.height) > vSize.height) {
  625. visRect.y = Math.max(0, vSize.height - visRect.height);
  626. }
  627. else if (visRect.y < 0) {
  628. visRect.y = 0;
  629. }
  630. }
  631. else {
  632. if (scrollpane.getComponentOrientation().isLeftToRight()) {
  633. visRect.x += (amount * direction);
  634. if ((visRect.x + visRect.width) > vSize.width) {
  635. visRect.x = Math.max(0, vSize.width - visRect.width);
  636. } else if (visRect.x < 0) {
  637. visRect.x = 0;
  638. }
  639. } else {
  640. visRect.x -= (amount * direction);
  641. if (visRect.width > vSize.width) {
  642. visRect.x = vSize.width - visRect.width;
  643. } else {
  644. visRect.x = Math.max(0, Math.min(vSize.width - visRect.width, visRect.x));
  645. }
  646. }
  647. }
  648. vp.setViewPosition(visRect.getLocation());
  649. }
  650. }
  651. }
  652. class Handler implements ChangeListener, PropertyChangeListener, MouseWheelListener {
  653. //
  654. // MouseWheelListener
  655. //
  656. public void mouseWheelMoved(MouseWheelEvent e) {
  657. if (scrollpane.isWheelScrollingEnabled() &&
  658. e.getScrollAmount() != 0) {
  659. JScrollBar toScroll = scrollpane.getVerticalScrollBar();
  660. int direction = 0;
  661. // find which scrollbar to scroll, or return if none
  662. if (toScroll == null || !toScroll.isVisible()) {
  663. toScroll = scrollpane.getHorizontalScrollBar();
  664. if (toScroll == null || !toScroll.isVisible()) {
  665. return;
  666. }
  667. }
  668. direction = e.getWheelRotation() < 0 ? -1 : 1;
  669. if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
  670. BasicScrollBarUI.scrollByUnits(toScroll, direction,
  671. e.getScrollAmount());
  672. }
  673. else if (e.getScrollType() ==
  674. MouseWheelEvent.WHEEL_BLOCK_SCROLL) {
  675. BasicScrollBarUI.scrollByBlock(toScroll, direction);
  676. }
  677. }
  678. }
  679. //
  680. // ChangeListener: This is added to the vieport, and hsb/vsb models.
  681. //
  682. public void stateChanged(ChangeEvent e) {
  683. JViewport viewport = scrollpane.getViewport();
  684. if (viewport != null) {
  685. if (e.getSource() == viewport) {
  686. viewportStateChanged(e);
  687. }
  688. else {
  689. JScrollBar hsb = scrollpane.getHorizontalScrollBar();
  690. if (hsb != null && e.getSource() == hsb.getModel()) {
  691. hsbStateChanged(viewport, e);
  692. }
  693. else {
  694. JScrollBar vsb = scrollpane.getVerticalScrollBar();
  695. if (vsb != null && e.getSource() == vsb.getModel()) {
  696. vsbStateChanged(viewport, e);
  697. }
  698. }
  699. }
  700. }
  701. }
  702. private void vsbStateChanged(JViewport viewport, ChangeEvent e) {
  703. BoundedRangeModel model = (BoundedRangeModel)(e.getSource());
  704. Point p = viewport.getViewPosition();
  705. p.y = model.getValue();
  706. viewport.setViewPosition(p);
  707. }
  708. private void hsbStateChanged(JViewport viewport, ChangeEvent e) {
  709. BoundedRangeModel model = (BoundedRangeModel)(e.getSource());
  710. Point p = viewport.getViewPosition();
  711. int value = model.getValue();
  712. if (scrollpane.getComponentOrientation().isLeftToRight()) {
  713. p.x = value;
  714. } else {
  715. int max = viewport.getViewSize().width;
  716. int extent = viewport.getExtentSize().width;
  717. int oldX = p.x;
  718. /* Set new X coordinate based on "value".
  719. */
  720. p.x = max - extent - value;
  721. /* If setValue() was called before "extent" was fixed,
  722. * turn setValueCalled flag on.
  723. */
  724. if ((extent == 0) && (value != 0) && (oldX == max)) {
  725. setValueCalled = true;
  726. } else {
  727. /* When a pane without a horizontal scroll bar was
  728. * reduced and the bar appeared, the viewport should
  729. * show the right side of the view.
  730. */
  731. if ((extent != 0) && (oldX < 0) && (p.x == 0)) {
  732. p.x += value;
  733. }
  734. }
  735. }
  736. viewport.setViewPosition(p);
  737. }
  738. private void viewportStateChanged(ChangeEvent e) {
  739. syncScrollPaneWithViewport();
  740. }
  741. //
  742. // PropertyChangeListener: This is installed on both the JScrollPane
  743. // and the horizontal/vertical scrollbars.
  744. //
  745. // Listens for changes in the model property and reinstalls the
  746. // horizontal/vertical PropertyChangeListeners.
  747. public void propertyChange(PropertyChangeEvent e) {
  748. if (e.getSource() == scrollpane) {
  749. scrollPanePropertyChange(e);
  750. }
  751. else {
  752. sbPropertyChange(e);
  753. }
  754. }
  755. private void scrollPanePropertyChange(PropertyChangeEvent e) {
  756. String propertyName = e.getPropertyName();
  757. if (propertyName == "verticalScrollBarDisplayPolicy") {
  758. updateScrollBarDisplayPolicy(e);
  759. }
  760. else if (propertyName == "horizontalScrollBarDisplayPolicy") {
  761. updateScrollBarDisplayPolicy(e);
  762. }
  763. else if (propertyName == "viewport") {
  764. updateViewport(e);
  765. }
  766. else if (propertyName == "rowHeader") {
  767. updateRowHeader(e);
  768. }
  769. else if (propertyName == "columnHeader") {
  770. updateColumnHeader(e);
  771. }
  772. else if (propertyName == "verticalScrollBar") {
  773. updateVerticalScrollBar(e);
  774. }
  775. else if (propertyName == "horizontalScrollBar") {
  776. updateHorizontalScrollBar(e);
  777. }
  778. else if (propertyName == "componentOrientation") {
  779. scrollpane.revalidate();
  780. scrollpane.repaint();
  781. }
  782. }
  783. // PropertyChangeListener for the horizontal and vertical scrollbars.
  784. private void sbPropertyChange(PropertyChangeEvent e) {
  785. String propertyName = e.getPropertyName();
  786. Object source = e.getSource();
  787. if ("model" == propertyName) {
  788. JScrollBar sb = scrollpane.getVerticalScrollBar();
  789. BoundedRangeModel oldModel = (BoundedRangeModel)e.
  790. getOldValue();
  791. ChangeListener cl = null;
  792. if (source == sb) {
  793. cl = vsbChangeListener;
  794. }
  795. else if (source == scrollpane.getHorizontalScrollBar()) {
  796. sb = scrollpane.getHorizontalScrollBar();
  797. cl = hsbChangeListener;
  798. }
  799. if (cl != null) {
  800. if (oldModel != null) {
  801. oldModel.removeChangeListener(cl);
  802. }
  803. if (sb.getModel() != null) {
  804. sb.getModel().addChangeListener(cl);
  805. }
  806. }
  807. }
  808. else if ("componentOrientation" == propertyName) {
  809. if (source == scrollpane.getHorizontalScrollBar()) {
  810. JScrollBar hsb = scrollpane.getHorizontalScrollBar();
  811. JViewport viewport = scrollpane.getViewport();
  812. Point p = viewport.getViewPosition();
  813. if (scrollpane.getComponentOrientation().isLeftToRight()) {
  814. p.x = hsb.getValue();
  815. } else {
  816. p.x = viewport.getViewSize().width - viewport.getExtentSize().width - hsb.getValue();
  817. }
  818. viewport.setViewPosition(p);
  819. }
  820. }
  821. }
  822. }
  823. }