001 /* BasicScrollPaneUI.java
002 Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package javax.swing.plaf.basic;
040
041 import java.awt.Dimension;
042 import java.awt.Graphics;
043 import java.awt.Point;
044 import java.awt.Rectangle;
045 import java.awt.event.ActionEvent;
046 import java.awt.event.ContainerEvent;
047 import java.awt.event.ContainerListener;
048 import java.awt.event.MouseWheelEvent;
049 import java.awt.event.MouseWheelListener;
050 import java.beans.PropertyChangeEvent;
051 import java.beans.PropertyChangeListener;
052
053 import javax.swing.AbstractAction;
054 import javax.swing.ActionMap;
055 import javax.swing.InputMap;
056 import javax.swing.JComponent;
057 import javax.swing.JScrollBar;
058 import javax.swing.JScrollPane;
059 import javax.swing.JSlider;
060 import javax.swing.JViewport;
061 import javax.swing.LookAndFeel;
062 import javax.swing.ScrollPaneConstants;
063 import javax.swing.ScrollPaneLayout;
064 import javax.swing.SwingUtilities;
065 import javax.swing.UIManager;
066 import javax.swing.border.Border;
067 import javax.swing.event.ChangeEvent;
068 import javax.swing.event.ChangeListener;
069 import javax.swing.plaf.ActionMapUIResource;
070 import javax.swing.plaf.ComponentUI;
071 import javax.swing.plaf.ScrollPaneUI;
072 import javax.swing.plaf.UIResource;
073
074 /**
075 * A UI delegate for the {@link JScrollPane} component.
076 */
077 public 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 }