001/* BasicScrollPaneUI.java 002 Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package javax.swing.plaf.basic; 040 041import java.awt.Dimension; 042import java.awt.Graphics; 043import java.awt.Point; 044import java.awt.Rectangle; 045import java.awt.event.ActionEvent; 046import java.awt.event.ContainerEvent; 047import java.awt.event.ContainerListener; 048import java.awt.event.MouseWheelEvent; 049import java.awt.event.MouseWheelListener; 050import java.beans.PropertyChangeEvent; 051import java.beans.PropertyChangeListener; 052 053import javax.swing.AbstractAction; 054import javax.swing.ActionMap; 055import javax.swing.InputMap; 056import javax.swing.JComponent; 057import javax.swing.JScrollBar; 058import javax.swing.JScrollPane; 059import javax.swing.JSlider; 060import javax.swing.JViewport; 061import javax.swing.LookAndFeel; 062import javax.swing.ScrollPaneConstants; 063import javax.swing.ScrollPaneLayout; 064import javax.swing.SwingUtilities; 065import javax.swing.UIManager; 066import javax.swing.border.Border; 067import javax.swing.event.ChangeEvent; 068import javax.swing.event.ChangeListener; 069import javax.swing.plaf.ActionMapUIResource; 070import javax.swing.plaf.ComponentUI; 071import javax.swing.plaf.ScrollPaneUI; 072import javax.swing.plaf.UIResource; 073 074/** 075 * A UI delegate for the {@link JScrollPane} component. 076 */ 077public class BasicScrollPaneUI extends ScrollPaneUI 078 implements ScrollPaneConstants 079{ 080 081 /** 082 * Listens for changes in the state of the horizontal scrollbar's model and 083 * updates the scrollpane accordingly. 084 * 085 * @author Roman Kennke (kennke@aicas.com) 086 */ 087 public class HSBChangeListener implements ChangeListener 088 { 089 090 /** 091 * Receives notification when the state of the horizontal scrollbar 092 * model has changed. 093 * 094 * @param event the change event 095 */ 096 public void stateChanged(ChangeEvent event) 097 { 098 JScrollBar hsb = scrollpane.getHorizontalScrollBar(); 099 JViewport vp = scrollpane.getViewport(); 100 Point viewPosition = vp.getViewPosition(); 101 viewPosition.x = hsb.getValue(); 102 vp.setViewPosition(viewPosition); 103 } 104 105 } 106 107 /** 108 * Listens for changes in the state of the vertical scrollbar's model and 109 * updates the scrollpane accordingly. 110 * 111 * @author Roman Kennke (kennke@aicas.com) 112 */ 113 public class VSBChangeListener implements ChangeListener 114 { 115 116 /** 117 * Receives notification when the state of the vertical scrollbar 118 * model has changed. 119 * 120 * @param event the change event 121 */ 122 public void stateChanged(ChangeEvent event) 123 { 124 JScrollBar vsb = scrollpane.getVerticalScrollBar(); 125 JViewport vp = scrollpane.getViewport(); 126 Point viewPosition = vp.getViewPosition(); 127 viewPosition.y = vsb.getValue(); 128 vp.setViewPosition(viewPosition); 129 } 130 131 } 132 133 /** 134 * Listens for changes of the viewport's extent size and updates the 135 * scrollpane accordingly. 136 * 137 * @author Roman Kennke (kennke@aicas.com) 138 */ 139 public class ViewportChangeHandler implements ChangeListener 140 { 141 142 /** 143 * Receives notification when the view's size, position or extent size 144 * changes. When the extents size has changed, this method calls 145 * {@link BasicScrollPaneUI#syncScrollPaneWithViewport()} to adjust the 146 * scrollbars extents as well. 147 * 148 * @param event the change event 149 */ 150 public void stateChanged(ChangeEvent event) 151 { 152 syncScrollPaneWithViewport(); 153 } 154 155 } 156 157 /** 158 * Listens for property changes on the scrollpane and update the view 159 * accordingly. 160 * 161 * @author Roman Kennke (kennke@aicas.com) 162 */ 163 public class PropertyChangeHandler implements PropertyChangeListener 164 { 165 166 /** 167 * Receives notification when any of the scrollpane's bound property 168 * changes. This method calls the appropriate update method on the 169 * <code>ScrollBarUI</code>. 170 * 171 * @param e the property change event 172 * 173 * @see BasicScrollPaneUI#updateColumnHeader(PropertyChangeEvent) 174 * @see BasicScrollPaneUI#updateRowHeader(PropertyChangeEvent) 175 * @see BasicScrollPaneUI#updateScrollBarDisplayPolicy(PropertyChangeEvent) 176 * @see BasicScrollPaneUI#updateViewport(PropertyChangeEvent) 177 */ 178 public void propertyChange(PropertyChangeEvent e) 179 { 180 String propName = e.getPropertyName(); 181 if (propName.equals("viewport")) 182 updateViewport(e); 183 else if (propName.equals("rowHeader")) 184 updateRowHeader(e); 185 else if (propName.equals("columnHeader")) 186 updateColumnHeader(e); 187 else if (propName.equals("horizontalScrollBarPolicy") 188 || e.getPropertyName().equals("verticalScrollBarPolicy")) 189 updateScrollBarDisplayPolicy(e); 190 else if (propName.equals("verticalScrollBar")) 191 { 192 JScrollBar oldSb = (JScrollBar) e.getOldValue(); 193 oldSb.getModel().removeChangeListener(vsbChangeListener); 194 JScrollBar newSb = (JScrollBar) e.getNewValue(); 195 newSb.getModel().addChangeListener(vsbChangeListener); 196 } 197 else if (propName.equals("horizontalScrollBar")) 198 { 199 JScrollBar oldSb = (JScrollBar) e.getOldValue(); 200 oldSb.getModel().removeChangeListener(hsbChangeListener); 201 JScrollBar newSb = (JScrollBar) e.getNewValue(); 202 newSb.getModel().addChangeListener(hsbChangeListener); 203 } 204 } 205 206 } 207 208 /** 209 * Listens for mouse wheel events and update the scrollpane accordingly. 210 * 211 * @author Roman Kennke (kennke@aicas.com) 212 * 213 * @since 1.4 214 */ 215 protected class MouseWheelHandler implements MouseWheelListener 216 { 217 /** 218 * Use to compute the visible rectangle. 219 */ 220 final Rectangle rect = new Rectangle(); 221 222 /** 223 * Scroll with the mouse wheel. 224 * 225 * @author Audrius Meskauskas (audriusa@Bioinformatics.org) 226 */ 227 public void mouseWheelMoved(MouseWheelEvent e) 228 { 229 if (scrollpane.isWheelScrollingEnabled() && e.getScrollAmount() != 0) 230 { 231 // Try to scroll vertically first. 232 JScrollBar scrollBar = scrollpane.getVerticalScrollBar(); 233 if (scrollBar == null || ! scrollBar.isVisible()) 234 scrollBar = scrollpane.getHorizontalScrollBar(); 235 if (scrollBar != null && scrollBar.isVisible()) 236 { 237 int direction = e.getWheelRotation() < 0 ? -1 : 1; 238 int scrollType = e.getScrollType(); 239 if (scrollType == MouseWheelEvent.WHEEL_UNIT_SCROLL) 240 BasicScrollBarUI.scrollByUnits(scrollBar, direction, 241 e.getScrollAmount()); 242 else if (scrollType == MouseWheelEvent.WHEEL_BLOCK_SCROLL) 243 BasicScrollBarUI.scrollByBlock(scrollBar, direction); 244 } 245 } 246 } 247 } 248 249 /** 250 * Adds/removes the mouse wheel listener when the component is added/removed 251 * to/from the scroll pane view port. 252 * 253 * @author Audrius Meskauskas (audriusa@bioinformatics.org) 254 */ 255 class ViewportContainerListener implements ContainerListener 256 { 257 /** 258 * Add the mouse wheel listener, allowing to scroll with the mouse. 259 */ 260 public void componentAdded(ContainerEvent e) 261 { 262 e.getChild().addMouseWheelListener(mouseWheelListener); 263 } 264 265 /** 266 * Remove the mouse wheel listener. 267 */ 268 public void componentRemoved(ContainerEvent e) 269 { 270 e.getChild().removeMouseWheelListener(mouseWheelListener); 271 } 272 } 273 274 /** 275 * The number of pixels by that we should scroll the content that does 276 * not implement Scrollable. 277 */ 278 static int SCROLL_NON_SCROLLABLES = 10; 279 280 /** 281 * The number of rows to scroll per mouse wheel click. From impression, 282 * Sun seems using the value 3. 283 */ 284 static int ROWS_PER_WHEEL_CLICK = 3; 285 286 /** The Scrollpane for which the UI is provided by this class. */ 287 protected JScrollPane scrollpane; 288 289 /** 290 * The horizontal scrollbar listener. 291 */ 292 protected ChangeListener hsbChangeListener; 293 294 /** 295 * The vertical scrollbar listener. 296 */ 297 protected ChangeListener vsbChangeListener; 298 299 /** 300 * The viewport listener. 301 */ 302 protected ChangeListener viewportChangeListener; 303 304 /** 305 * The scrollpane property change listener. 306 */ 307 protected PropertyChangeListener spPropertyChangeListener; 308 309 /** 310 * The mousewheel listener for the scrollpane. 311 */ 312 MouseWheelListener mouseWheelListener; 313 314 /** 315 * The listener to add and remove the mouse wheel listener to/from 316 * the component container. 317 */ 318 ContainerListener containerListener; 319 320 public static ComponentUI createUI(final JComponent c) 321 { 322 return new BasicScrollPaneUI(); 323 } 324 325 protected void installDefaults(JScrollPane p) 326 { 327 scrollpane = p; 328 LookAndFeel.installColorsAndFont(p, "ScrollPane.background", 329 "ScrollPane.foreground", 330 "ScrollPane.font"); 331 LookAndFeel.installBorder(p, "ScrollPane.border"); 332 333 // Install Viewport border. 334 Border vpBorder = p.getViewportBorder(); 335 if (vpBorder == null || vpBorder instanceof UIResource) 336 { 337 vpBorder = UIManager.getBorder("ScrollPane.viewportBorder"); 338 p.setViewportBorder(vpBorder); 339 } 340 341 p.setOpaque(true); 342 } 343 344 protected void uninstallDefaults(JScrollPane p) 345 { 346 LookAndFeel.uninstallBorder(p); 347 Border vpBorder = p.getViewportBorder(); 348 if (vpBorder != null && vpBorder instanceof UIResource) 349 p.setViewportBorder(null); 350 } 351 352 public void installUI(final JComponent c) 353 { 354 super.installUI(c); 355 installDefaults((JScrollPane) c); 356 installListeners((JScrollPane) c); 357 installKeyboardActions((JScrollPane) c); 358 } 359 360 /** 361 * Installs the listeners on the scrollbars, the viewport and the scrollpane. 362 * 363 * @param sp the scrollpane on which to install the listeners 364 */ 365 protected void installListeners(JScrollPane sp) 366 { 367 if (spPropertyChangeListener == null) 368 spPropertyChangeListener = createPropertyChangeListener(); 369 sp.addPropertyChangeListener(spPropertyChangeListener); 370 371 if (hsbChangeListener == null) 372 hsbChangeListener = createHSBChangeListener(); 373 sp.getHorizontalScrollBar().getModel().addChangeListener(hsbChangeListener); 374 375 if (vsbChangeListener == null) 376 vsbChangeListener = createVSBChangeListener(); 377 sp.getVerticalScrollBar().getModel().addChangeListener(vsbChangeListener); 378 379 if (viewportChangeListener == null) 380 viewportChangeListener = createViewportChangeListener(); 381 382 if (mouseWheelListener == null) 383 mouseWheelListener = createMouseWheelListener(); 384 385 if (containerListener == null) 386 containerListener = new ViewportContainerListener(); 387 388 JViewport v = sp.getViewport(); 389 v.addChangeListener(viewportChangeListener); 390 v.addContainerListener(containerListener); 391 392 // Add mouse wheel listeners to the componets that are probably already 393 // in the view port. 394 for (int i = 0; i < v.getComponentCount(); i++) 395 v.getComponent(i).addMouseWheelListener(mouseWheelListener); 396 } 397 398 InputMap getInputMap(int condition) 399 { 400 if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) 401 return (InputMap) UIManager.get("ScrollPane.ancestorInputMap"); 402 return null; 403 } 404 405 /** 406 * Returns the action map for the {@link JScrollPane}. All scroll panes 407 * share a single action map which is created the first time this method is 408 * called, then stored in the UIDefaults table for subsequent access. 409 * 410 * @return The shared action map. 411 */ 412 ActionMap getActionMap() 413 { 414 ActionMap map = (ActionMap) UIManager.get("ScrollPane.actionMap"); 415 416 if (map == null) // first time here 417 { 418 map = createActionMap(); 419 if (map != null) 420 UIManager.put("ScrollPane.actionMap", map); 421 } 422 return map; 423 } 424 425 /** 426 * Creates the action map shared by all {@link JSlider} instances. 427 * This method is called once by {@link #getActionMap()} when it 428 * finds no action map in the UIDefaults table...after the map is 429 * created, it gets added to the defaults table so that subsequent 430 * calls to {@link #getActionMap()} will return the same shared 431 * instance. 432 * 433 * @return The action map. 434 */ 435 ActionMap createActionMap() 436 { 437 ActionMap map = new ActionMapUIResource(); 438 map.put("scrollLeft", 439 new AbstractAction("scrollLeft") { 440 public void actionPerformed(ActionEvent event) 441 { 442 JScrollPane sp = (JScrollPane) event.getSource(); 443 JScrollBar sb = sp.getHorizontalScrollBar(); 444 if (sb.isVisible()) 445 { 446 int delta = sb.getBlockIncrement(-1); 447 sb.setValue(sb.getValue() + delta); 448 } 449 } 450 } 451 ); 452 map.put("scrollEnd", 453 new AbstractAction("scrollEnd") { 454 public void actionPerformed(ActionEvent event) 455 { 456 JScrollPane sp = (JScrollPane) event.getSource(); 457 JScrollBar sb1 = sp.getHorizontalScrollBar(); 458 if (sb1.isVisible()) 459 { 460 sb1.setValue(sb1.getMaximum()); 461 } 462 JScrollBar sb2 = sp.getVerticalScrollBar(); 463 if (sb2.isVisible()) 464 { 465 sb2.setValue(sb2.getMaximum()); 466 } 467 } 468 } 469 ); 470 map.put("unitScrollUp", 471 new AbstractAction("unitScrollUp") { 472 public void actionPerformed(ActionEvent event) 473 { 474 JScrollPane sp = (JScrollPane) event.getSource(); 475 JScrollBar sb = sp.getVerticalScrollBar(); 476 if (sb.isVisible()) 477 { 478 int delta = sb.getUnitIncrement(-1); 479 sb.setValue(sb.getValue() + delta); 480 } 481 } 482 } 483 ); 484 map.put("unitScrollLeft", 485 new AbstractAction("unitScrollLeft") { 486 public void actionPerformed(ActionEvent event) 487 { 488 JScrollPane sp = (JScrollPane) event.getSource(); 489 JScrollBar sb = sp.getHorizontalScrollBar(); 490 if (sb.isVisible()) 491 { 492 int delta = sb.getUnitIncrement(-1); 493 sb.setValue(sb.getValue() + delta); 494 } 495 } 496 } 497 ); 498 map.put("scrollUp", 499 new AbstractAction("scrollUp") { 500 public void actionPerformed(ActionEvent event) 501 { 502 JScrollPane sp = (JScrollPane) event.getSource(); 503 JScrollBar sb = sp.getVerticalScrollBar(); 504 if (sb.isVisible()) 505 { 506 int delta = sb.getBlockIncrement(-1); 507 sb.setValue(sb.getValue() + delta); 508 } 509 } 510 } 511 ); 512 map.put("scrollRight", 513 new AbstractAction("scrollRight") { 514 public void actionPerformed(ActionEvent event) 515 { 516 JScrollPane sp = (JScrollPane) event.getSource(); 517 JScrollBar sb = sp.getHorizontalScrollBar(); 518 if (sb.isVisible()) 519 { 520 int delta = sb.getBlockIncrement(1); 521 sb.setValue(sb.getValue() + delta); 522 } 523 } 524 } 525 ); 526 map.put("scrollHome", 527 new AbstractAction("scrollHome") { 528 public void actionPerformed(ActionEvent event) 529 { 530 JScrollPane sp = (JScrollPane) event.getSource(); 531 JScrollBar sb1 = sp.getHorizontalScrollBar(); 532 if (sb1.isVisible()) 533 { 534 sb1.setValue(sb1.getMinimum()); 535 } 536 JScrollBar sb2 = sp.getVerticalScrollBar(); 537 if (sb2.isVisible()) 538 { 539 sb2.setValue(sb2.getMinimum()); 540 } 541 } 542 } 543 ); 544 map.put("scrollDown", 545 new AbstractAction("scrollDown") { 546 public void actionPerformed(ActionEvent event) 547 { 548 JScrollPane sp = (JScrollPane) event.getSource(); 549 JScrollBar sb = sp.getVerticalScrollBar(); 550 if (sb.isVisible()) 551 { 552 int delta = sb.getBlockIncrement(1); 553 sb.setValue(sb.getValue() + delta); 554 } 555 } 556 } 557 ); 558 map.put("unitScrollDown", 559 new AbstractAction("unitScrollDown") { 560 public void actionPerformed(ActionEvent event) 561 { 562 JScrollPane sp = (JScrollPane) event.getSource(); 563 JScrollBar sb = sp.getVerticalScrollBar(); 564 if (sb.isVisible()) 565 { 566 int delta = sb.getUnitIncrement(1); 567 sb.setValue(sb.getValue() + delta); 568 } 569 } 570 } 571 ); 572 map.put("unitScrollRight", 573 new AbstractAction("unitScrollRight") { 574 public void actionPerformed(ActionEvent event) 575 { 576 JScrollPane sp = (JScrollPane) event.getSource(); 577 JScrollBar sb = sp.getHorizontalScrollBar(); 578 if (sb.isVisible()) 579 { 580 int delta = sb.getUnitIncrement(1); 581 sb.setValue(sb.getValue() + delta); 582 } 583 } 584 } 585 ); 586 return map; 587 } 588 589 /** 590 * Installs additional keyboard actions on the scrollpane. This is a hook 591 * method provided to subclasses in order to install their own keyboard 592 * actions. 593 * 594 * @param sp the scrollpane to install keyboard actions on 595 */ 596 protected void installKeyboardActions(JScrollPane sp) 597 { 598 InputMap keyMap = getInputMap( 599 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 600 SwingUtilities.replaceUIInputMap(sp, 601 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keyMap); 602 ActionMap map = getActionMap(); 603 SwingUtilities.replaceUIActionMap(sp, map); 604 } 605 606 /** 607 * Uninstalls all keyboard actions from the JScrollPane that have been 608 * installed by {@link #installKeyboardActions}. This is a hook method 609 * provided to subclasses to add their own keyboard actions. 610 * 611 * @param sp the scrollpane to uninstall keyboard actions from 612 */ 613 protected void uninstallKeyboardActions(JScrollPane sp) 614 { 615 SwingUtilities.replaceUIActionMap(sp, null); 616 SwingUtilities.replaceUIInputMap(sp, 617 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null); 618 } 619 620 /** 621 * Creates and returns the change listener for the horizontal scrollbar. 622 * 623 * @return the change listener for the horizontal scrollbar 624 */ 625 protected ChangeListener createHSBChangeListener() 626 { 627 return new HSBChangeListener(); 628 } 629 630 /** 631 * Creates and returns the change listener for the vertical scrollbar. 632 * 633 * @return the change listener for the vertical scrollbar 634 */ 635 protected ChangeListener createVSBChangeListener() 636 { 637 return new VSBChangeListener(); 638 } 639 640 /** 641 * Creates and returns the change listener for the viewport. 642 * 643 * @return the change listener for the viewport 644 */ 645 protected ChangeListener createViewportChangeListener() 646 { 647 return new ViewportChangeHandler(); 648 } 649 650 /** 651 * Creates and returns the property change listener for the scrollpane. 652 * 653 * @return the property change listener for the scrollpane 654 */ 655 protected PropertyChangeListener createPropertyChangeListener() 656 { 657 return new PropertyChangeHandler(); 658 } 659 660 /** 661 * Creates and returns the mouse wheel listener for the scrollpane. 662 * 663 * @return the mouse wheel listener for the scrollpane 664 * 665 * @since 1.4 666 */ 667 protected MouseWheelListener createMouseWheelListener() 668 { 669 return new MouseWheelHandler(); 670 } 671 672 public void uninstallUI(final JComponent c) 673 { 674 uninstallDefaults((JScrollPane) c); 675 uninstallListeners(c); 676 installKeyboardActions((JScrollPane) c); 677 } 678 679 /** 680 * Uninstalls all the listeners that have been installed in 681 * {@link #installListeners(JScrollPane)}. 682 * 683 * @param c the scrollpane from which to uninstall the listeners 684 */ 685 protected void uninstallListeners(JComponent c) 686 { 687 JScrollPane sp = (JScrollPane) c; 688 sp.removePropertyChangeListener(spPropertyChangeListener); 689 sp.getHorizontalScrollBar().getModel() 690 .removeChangeListener(hsbChangeListener); 691 sp.getVerticalScrollBar().getModel() 692 .removeChangeListener(vsbChangeListener); 693 694 JViewport v = sp.getViewport(); 695 v.removeChangeListener(viewportChangeListener); 696 v.removeContainerListener(containerListener); 697 698 for (int i = 0; i < v.getComponentCount(); i++) 699 v.getComponent(i).removeMouseWheelListener(mouseWheelListener); 700 701 } 702 703 public Dimension getMinimumSize(JComponent c) 704 { 705 JScrollPane p = (JScrollPane) c; 706 ScrollPaneLayout sl = (ScrollPaneLayout) p.getLayout(); 707 return sl.minimumLayoutSize(c); 708 } 709 710 public void paint(Graphics g, JComponent c) 711 { 712 Border vpBorder = scrollpane.getViewportBorder(); 713 if (vpBorder != null) 714 { 715 Rectangle r = scrollpane.getViewportBorderBounds(); 716 vpBorder.paintBorder(scrollpane, g, r.x, r.y, r.width, r.height); 717 } 718 } 719 720 /** 721 * Synchronizes the scrollbar and header settings positions and extent 722 * with the viewport's view position and extent. 723 */ 724 protected void syncScrollPaneWithViewport() 725 { 726 JViewport vp = scrollpane.getViewport(); 727 728 if (vp != null) 729 { 730 Dimension extentSize = vp.getExtentSize(); 731 Point viewPos = vp.getViewPosition(); 732 Dimension viewSize = vp.getViewSize(); 733 734 // Update the vertical scrollbar. 735 JScrollBar vsb = scrollpane.getVerticalScrollBar(); 736 if (vsb != null) 737 { 738 int extent = extentSize.height; 739 int max = viewSize.height; 740 int val = Math.max(0, Math.min(viewPos.y, max - extent)); 741 vsb.setValues(val, extent, 0, max); 742 } 743 744 // Update the horizontal scrollbar. 745 JScrollBar hsb = scrollpane.getHorizontalScrollBar(); 746 if (hsb != null) 747 { 748 int extent = extentSize.width; 749 int max = viewSize.width; 750 int val = Math.max(0, Math.min(viewPos.x, max - extent)); 751 hsb.setValues(val, extent, 0, max); 752 } 753 754 // Update the row header. 755 JViewport rowHeader = scrollpane.getRowHeader(); 756 if (rowHeader != null) 757 { 758 Point p = new Point(0, viewPos.y); 759 rowHeader.setViewPosition(p); 760 } 761 762 // Update the column header. 763 JViewport colHeader = scrollpane.getColumnHeader(); 764 if (colHeader != null) 765 { 766 Point p = new Point(viewPos.x, 0); 767 colHeader.setViewPosition(p); 768 } 769 } 770 } 771 772 /** 773 * Receives notification when the <code>columnHeader</code> property has 774 * changed on the scrollpane. 775 * 776 * @param ev the property change event 777 */ 778 protected void updateColumnHeader(PropertyChangeEvent ev) 779 { 780 // TODO: Find out what should be done here. Or is this only a hook? 781 } 782 783 /** 784 * Receives notification when the <code>rowHeader</code> property has changed 785 * on the scrollpane. 786 * 787 * @param ev the property change event 788 */ 789 protected void updateRowHeader(PropertyChangeEvent ev) 790 { 791 // TODO: Find out what should be done here. Or is this only a hook? 792 } 793 794 /** 795 * Receives notification when the <code>scrollBarDisplayPolicy</code> 796 * property has changed on the scrollpane. 797 * 798 * @param ev the property change event 799 */ 800 protected void updateScrollBarDisplayPolicy(PropertyChangeEvent ev) 801 { 802 scrollpane.revalidate(); 803 scrollpane.repaint(); 804 } 805 806 /** 807 * Receives notification when the <code>viewport</code> property has changed 808 * on the scrollpane. 809 * 810 * This method sets removes the viewportChangeListener from the old viewport 811 * and adds it to the new viewport. 812 * 813 * @param ev the property change event 814 */ 815 protected void updateViewport(PropertyChangeEvent ev) 816 { 817 JViewport oldViewport = (JViewport) ev.getOldValue(); 818 oldViewport.removeChangeListener(viewportChangeListener); 819 JViewport newViewport = (JViewport) ev.getNewValue(); 820 newViewport.addChangeListener(viewportChangeListener); 821 syncScrollPaneWithViewport(); 822 } 823}