History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/plaf/basic/BasicScrollPaneUI.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/plaf/basic/BasicScrollPaneUI.java+1178−0
@@ -0,0 +1,1178 @@
1+/*
2+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package javax.swing.plaf.basic;
27+
28+import sun.swing.DefaultLookup;
29+import sun.swing.UIAction;
30+
31+import javax.swing.*;
32+import javax.swing.event.*;
33+import javax.swing.border.*;
34+import javax.swing.plaf.*;
35+
36+import java.beans.PropertyChangeListener;
37+import java.beans.PropertyChangeEvent;
38+
39+import java.awt.Component;
40+import java.awt.Rectangle;
41+import java.awt.Dimension;
42+import java.awt.Point;
43+import java.awt.Insets;
44+import java.awt.Graphics;
45+import java.awt.event.*;
46+
47+/**
48+ * A default L&F implementation of ScrollPaneUI.
49+ *
50+ * @author Hans Muller
51+ */
52+public class BasicScrollPaneUI
53+ extends ScrollPaneUI implements ScrollPaneConstants
54+{
55+ protected JScrollPane scrollpane;
56+ protected ChangeListener vsbChangeListener;
57+ protected ChangeListener hsbChangeListener;
58+ protected ChangeListener viewportChangeListener;
59+ protected PropertyChangeListener spPropertyChangeListener;
60+ private MouseWheelListener mouseScrollListener;
61+ private int oldExtent = Integer.MIN_VALUE;
62+
63+ /**
64+ * PropertyChangeListener installed on the vertical scrollbar.
65+ */
66+ private PropertyChangeListener vsbPropertyChangeListener;
67+
68+ /**
69+ * PropertyChangeListener installed on the horizontal scrollbar.
70+ */
71+ private PropertyChangeListener hsbPropertyChangeListener;
72+
73+ private Handler handler;
74+
75+ /**
76+ * State flag that shows whether setValue() was called from a user program
77+ * before the value of "extent" was set in right-to-left component
78+ * orientation.
79+ */
80+ private boolean setValueCalled = false;
81+
82+
83+ public static ComponentUI createUI(JComponent x) {
84+ return new BasicScrollPaneUI();
85+ }
86+
87+ static void loadActionMap(LazyActionMap map) {
88+ map.put(new Actions(Actions.SCROLL_UP));
89+ map.put(new Actions(Actions.SCROLL_DOWN));
90+ map.put(new Actions(Actions.SCROLL_HOME));
91+ map.put(new Actions(Actions.SCROLL_END));
92+ map.put(new Actions(Actions.UNIT_SCROLL_UP));
93+ map.put(new Actions(Actions.UNIT_SCROLL_DOWN));
94+ map.put(new Actions(Actions.SCROLL_LEFT));
95+ map.put(new Actions(Actions.SCROLL_RIGHT));
96+ map.put(new Actions(Actions.UNIT_SCROLL_RIGHT));
97+ map.put(new Actions(Actions.UNIT_SCROLL_LEFT));
98+ }
99+
100+
101+
102+ public void paint(Graphics g, JComponent c) {
103+ Border vpBorder = scrollpane.getViewportBorder();
104+ if (vpBorder != null) {
105+ Rectangle r = scrollpane.getViewportBorderBounds();
106+ vpBorder.paintBorder(scrollpane, g, r.x, r.y, r.width, r.height);
107+ }
108+ }
109+
110+
111+ /**
112+ * @return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE)
113+ */
114+ public Dimension getMaximumSize(JComponent c) {
115+ return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
116+ }
117+
118+
119+ protected void installDefaults(JScrollPane scrollpane)
120+ {
121+ LookAndFeel.installBorder(scrollpane, "ScrollPane.border");
122+ LookAndFeel.installColorsAndFont(scrollpane,
123+ "ScrollPane.background",
124+ "ScrollPane.foreground",
125+ "ScrollPane.font");
126+
127+ Border vpBorder = scrollpane.getViewportBorder();
128+ if ((vpBorder == null) ||( vpBorder instanceof UIResource)) {
129+ vpBorder = UIManager.getBorder("ScrollPane.viewportBorder");
130+ scrollpane.setViewportBorder(vpBorder);
131+ }
132+ LookAndFeel.installProperty(scrollpane, "opaque", Boolean.TRUE);
133+ }
134+
135+
136+ protected void installListeners(JScrollPane c)
137+ {
138+ vsbChangeListener = createVSBChangeListener();
139+ vsbPropertyChangeListener = createVSBPropertyChangeListener();
140+ hsbChangeListener = createHSBChangeListener();
141+ hsbPropertyChangeListener = createHSBPropertyChangeListener();
142+ viewportChangeListener = createViewportChangeListener();
143+ spPropertyChangeListener = createPropertyChangeListener();
144+
145+ JViewport viewport = scrollpane.getViewport();
146+ JScrollBar vsb = scrollpane.getVerticalScrollBar();
147+ JScrollBar hsb = scrollpane.getHorizontalScrollBar();
148+
149+ if (viewport != null) {
150+ viewport.addChangeListener(viewportChangeListener);
151+ }
152+ if (vsb != null) {
153+ vsb.getModel().addChangeListener(vsbChangeListener);
154+ vsb.addPropertyChangeListener(vsbPropertyChangeListener);
155+ }
156+ if (hsb != null) {
157+ hsb.getModel().addChangeListener(hsbChangeListener);
158+ hsb.addPropertyChangeListener(hsbPropertyChangeListener);
159+ }
160+
161+ scrollpane.addPropertyChangeListener(spPropertyChangeListener);
162+
163+ mouseScrollListener = createMouseWheelListener();
164+ scrollpane.addMouseWheelListener(mouseScrollListener);
165+
166+ }
167+
168+ protected void installKeyboardActions(JScrollPane c) {
169+ InputMap inputMap = getInputMap(JComponent.
170+ WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
171+
172+ SwingUtilities.replaceUIInputMap(c, JComponent.
173+ WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
174+
175+ LazyActionMap.installLazyActionMap(c, BasicScrollPaneUI.class,
176+ "ScrollPane.actionMap");
177+ }
178+
179+ InputMap getInputMap(int condition) {
180+ if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
181+ InputMap keyMap = (InputMap)DefaultLookup.get(scrollpane, this,
182+ "ScrollPane.ancestorInputMap");
183+ InputMap rtlKeyMap;
184+
185+ if (scrollpane.getComponentOrientation().isLeftToRight() ||
186+ ((rtlKeyMap = (InputMap)DefaultLookup.get(scrollpane, this,
187+ "ScrollPane.ancestorInputMap.RightToLeft")) == null)) {
188+ return keyMap;
189+ } else {
190+ rtlKeyMap.setParent(keyMap);
191+ return rtlKeyMap;
192+ }
193+ }
194+ return null;
195+ }
196+
197+ public void installUI(JComponent x) {
198+ scrollpane = (JScrollPane)x;
199+ installDefaults(scrollpane);
200+ installListeners(scrollpane);
201+ installKeyboardActions(scrollpane);
202+ }
203+
204+
205+ protected void uninstallDefaults(JScrollPane c) {
206+ LookAndFeel.uninstallBorder(scrollpane);
207+
208+ if (scrollpane.getViewportBorder() instanceof UIResource) {
209+ scrollpane.setViewportBorder(null);
210+ }
211+ }
212+
213+
214+ protected void uninstallListeners(JComponent c) {
215+ JViewport viewport = scrollpane.getViewport();
216+ JScrollBar vsb = scrollpane.getVerticalScrollBar();
217+ JScrollBar hsb = scrollpane.getHorizontalScrollBar();
218+
219+ if (viewport != null) {
220+ viewport.removeChangeListener(viewportChangeListener);
221+ }
222+ if (vsb != null) {
223+ vsb.getModel().removeChangeListener(vsbChangeListener);
224+ vsb.removePropertyChangeListener(vsbPropertyChangeListener);
225+ }
226+ if (hsb != null) {
227+ hsb.getModel().removeChangeListener(hsbChangeListener);
228+ hsb.removePropertyChangeListener(hsbPropertyChangeListener);
229+ }
230+
231+ scrollpane.removePropertyChangeListener(spPropertyChangeListener);
232+
233+ if (mouseScrollListener != null) {
234+ scrollpane.removeMouseWheelListener(mouseScrollListener);
235+ }
236+
237+ vsbChangeListener = null;
238+ hsbChangeListener = null;
239+ viewportChangeListener = null;
240+ spPropertyChangeListener = null;
241+ mouseScrollListener = null;
242+ handler = null;
243+ }
244+
245+
246+ protected void uninstallKeyboardActions(JScrollPane c) {
247+ SwingUtilities.replaceUIActionMap(c, null);
248+ SwingUtilities.replaceUIInputMap(c, JComponent.
249+ WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
250+ }
251+
252+
253+ public void uninstallUI(JComponent c) {
254+ uninstallDefaults(scrollpane);
255+ uninstallListeners(scrollpane);
256+ uninstallKeyboardActions(scrollpane);
257+ scrollpane = null;
258+ }
259+
260+ private Handler getHandler() {
261+ if (handler == null) {
262+ handler = new Handler();
263+ }
264+ return handler;
265+ }
266+
267+ protected void syncScrollPaneWithViewport()
268+ {
269+ JViewport viewport = scrollpane.getViewport();
270+ JScrollBar vsb = scrollpane.getVerticalScrollBar();
271+ JScrollBar hsb = scrollpane.getHorizontalScrollBar();
272+ JViewport rowHead = scrollpane.getRowHeader();
273+ JViewport colHead = scrollpane.getColumnHeader();
274+ boolean ltr = scrollpane.getComponentOrientation().isLeftToRight();
275+
276+ if (viewport != null) {
277+ Dimension extentSize = viewport.getExtentSize();
278+ Dimension viewSize = viewport.getViewSize();
279+ Point viewPosition = viewport.getViewPosition();
280+
281+ if (vsb != null) {
282+ int extent = extentSize.height;
283+ int max = viewSize.height;
284+ int value = Math.max(0, Math.min(viewPosition.y, max - extent));
285+ vsb.setValues(value, extent, 0, max);
286+ }
287+
288+ if (hsb != null) {
289+ int extent = extentSize.width;
290+ int max = viewSize.width;
291+ int value;
292+
293+ if (ltr) {
294+ value = Math.max(0, Math.min(viewPosition.x, max - extent));
295+ } else {
296+ int currentValue = hsb.getValue();
297+
298+ /* Use a particular formula to calculate "value"
299+ * until effective x coordinate is calculated.
300+ */
301+ if (setValueCalled && ((max - currentValue) == viewPosition.x)) {
302+ value = Math.max(0, Math.min(max - extent, currentValue));
303+ /* After "extent" is set, turn setValueCalled flag off.
304+ */
305+ if (extent != 0) {
306+ setValueCalled = false;
307+ }
308+ } else {
309+ if (extent > max) {
310+ viewPosition.x = max - extent;
311+ viewport.setViewPosition(viewPosition);
312+ value = 0;
313+ } else {
314+ /* The following line can't handle a small value of
315+ * viewPosition.x like Integer.MIN_VALUE correctly
316+ * because (max - extent - viewPositoiin.x) causes
317+ * an overflow. As a result, value becomes zero.
318+ * (e.g. setViewPosition(Integer.MAX_VALUE, ...)
319+ * in a user program causes a overflow.
320+ * Its expected value is (max - extent).)
321+ * However, this seems a trivial bug and adding a
322+ * fix makes this often-called method slow, so I'll
323+ * leave it until someone claims.
324+ */
325+ value = Math.max(0, Math.min(max - extent, max - extent - viewPosition.x));
326+ if (oldExtent > extent) {
327+ value -= oldExtent - extent;
328+ }
329+ }
330+ }
331+ }
332+ oldExtent = extent;
333+ hsb.setValues(value, extent, 0, max);
334+ }
335+
336+ if (rowHead != null) {
337+ Point p = rowHead.getViewPosition();
338+ p.y = viewport.getViewPosition().y;
339+ p.x = 0;
340+ rowHead.setViewPosition(p);
341+ }
342+
343+ if (colHead != null) {
344+ Point p = colHead.getViewPosition();
345+ if (ltr) {
346+ p.x = viewport.getViewPosition().x;
347+ } else {
348+ p.x = Math.max(0, viewport.getViewPosition().x);
349+ }
350+ p.y = 0;
351+ colHead.setViewPosition(p);
352+ }
353+ }
354+ }
355+
356+ /**
357+ * Returns the baseline.
358+ *
359+ * @throws NullPointerException {@inheritDoc}
360+ * @throws IllegalArgumentException {@inheritDoc}
361+ * @see javax.swing.JComponent#getBaseline(int, int)
362+ * @since 1.6
363+ */
364+ public int getBaseline(JComponent c, int width, int height) {
365+ if (c == null) {
366+ throw new NullPointerException("Component must be non-null");
367+ }
368+
369+ if (width < 0 || height < 0) {
370+ throw new IllegalArgumentException("Width and height must be >= 0");
371+ }
372+
373+ JViewport viewport = scrollpane.getViewport();
374+ Insets spInsets = scrollpane.getInsets();
375+ int y = spInsets.top;
376+ height = height - spInsets.top - spInsets.bottom;
377+ width = width - spInsets.left - spInsets.right;
378+ JViewport columnHeader = scrollpane.getColumnHeader();
379+ if (columnHeader != null && columnHeader.isVisible()) {
380+ Component header = columnHeader.getView();
381+ if (header != null && header.isVisible()) {
382+ // Header is always given it's preferred size.
383+ Dimension headerPref = header.getPreferredSize();
384+ int baseline = header.getBaseline(headerPref.width,
385+ headerPref.height);
386+ if (baseline >= 0) {
387+ return y + baseline;
388+ }
389+ }
390+ Dimension columnPref = columnHeader.getPreferredSize();
391+ height -= columnPref.height;
392+ y += columnPref.height;
393+ }
394+ Component view = (viewport == null) ? null : viewport.getView();
395+ if (view != null && view.isVisible() &&
396+ view.getBaselineResizeBehavior() ==
397+ Component.BaselineResizeBehavior.CONSTANT_ASCENT) {
398+ Border viewportBorder = scrollpane.getViewportBorder();
399+ if (viewportBorder != null) {
400+ Insets vpbInsets = viewportBorder.getBorderInsets(scrollpane);
401+ y += vpbInsets.top;
402+ height = height - vpbInsets.top - vpbInsets.bottom;
403+ width = width - vpbInsets.left - vpbInsets.right;
404+ }
405+ if (view.getWidth() > 0 && view.getHeight() > 0) {
406+ Dimension min = view.getMinimumSize();
407+ width = Math.max(min.width, view.getWidth());
408+ height = Math.max(min.height, view.getHeight());
409+ }
410+ if (width > 0 && height > 0) {
411+ int baseline = view.getBaseline(width, height);
412+ if (baseline > 0) {
413+ return y + baseline;
414+ }
415+ }
416+ }
417+ return -1;
418+ }
419+
420+ /**
421+ * Returns an enum indicating how the baseline of the component
422+ * changes as the size changes.
423+ *
424+ * @throws NullPointerException {@inheritDoc}
425+ * @see javax.swing.JComponent#getBaseline(int, int)
426+ * @since 1.6
427+ */
428+ public Component.BaselineResizeBehavior getBaselineResizeBehavior(
429+ JComponent c) {
430+ super.getBaselineResizeBehavior(c);
431+ // Baseline is either from the header, in which case it's always
432+ // the same size and therefor can be created as CONSTANT_ASCENT.
433+ // If the header doesn't have a baseline than the baseline will only
434+ // be valid if it's BaselineResizeBehavior is
435+ // CONSTANT_ASCENT, so, return CONSTANT_ASCENT.
436+ return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
437+ }
438+
439+
440+ /**
441+ * Listener for viewport events.
442+ */
443+ public class ViewportChangeHandler implements ChangeListener
444+ {
445+
446+ // NOTE: This class exists only for backward compatability. All
447+ // its functionality has been moved into Handler. If you need to add
448+ // new functionality add it to the Handler, but make sure this
449+ // class calls into the Handler.
450+
451+ public void stateChanged(ChangeEvent e) {
452+ getHandler().stateChanged(e);
453+ }
454+ }
455+
456+ protected ChangeListener createViewportChangeListener() {
457+ return getHandler();
458+ }
459+
460+
461+ /**
462+ * Horizontal scrollbar listener.
463+ */
464+ public class HSBChangeListener implements ChangeListener
465+ {
466+
467+ // NOTE: This class exists only for backward compatability. All
468+ // its functionality has been moved into Handler. If you need to add
469+ // new functionality add it to the Handler, but make sure this
470+ // class calls into the Handler.
471+
472+ public void stateChanged(ChangeEvent e)
473+ {
474+ getHandler().stateChanged(e);
475+ }
476+ }
477+
478+ /**
479+ * Returns a <code>PropertyChangeListener</code> that will be installed
480+ * on the horizontal <code>JScrollBar</code>.
481+ */
482+ private PropertyChangeListener createHSBPropertyChangeListener() {
483+ return getHandler();
484+ }
485+
486+ protected ChangeListener createHSBChangeListener() {
487+ return getHandler();
488+ }
489+
490+
491+ /**
492+ * Vertical scrollbar listener.
493+ */
494+ public class VSBChangeListener implements ChangeListener
495+ {
496+
497+ // NOTE: This class exists only for backward compatability. All
498+ // its functionality has been moved into Handler. If you need to add
499+ // new functionality add it to the Handler, but make sure this
500+ // class calls into the Handler.
501+
502+ public void stateChanged(ChangeEvent e)
503+ {
504+ getHandler().stateChanged(e);
505+ }
506+ }
507+
508+
509+ /**
510+ * Returns a <code>PropertyChangeListener</code> that will be installed
511+ * on the vertical <code>JScrollBar</code>.
512+ */
513+ private PropertyChangeListener createVSBPropertyChangeListener() {
514+ return getHandler();
515+ }
516+
517+ protected ChangeListener createVSBChangeListener() {
518+ return getHandler();
519+ }
520+
521+ /**
522+ * MouseWheelHandler is an inner class which implements the
523+ * MouseWheelListener interface. MouseWheelHandler responds to
524+ * MouseWheelEvents by scrolling the JScrollPane appropriately.
525+ * If the scroll pane's
526+ * <code>isWheelScrollingEnabled</code>
527+ * method returns false, no scrolling occurs.
528+ *
529+ * @see javax.swing.JScrollPane#isWheelScrollingEnabled
530+ * @see #createMouseWheelListener
531+ * @see java.awt.event.MouseWheelListener
532+ * @see java.awt.event.MouseWheelEvent
533+ * @since 1.4
534+ */
535+ protected class MouseWheelHandler implements MouseWheelListener {
536+
537+ // NOTE: This class exists only for backward compatability. All
538+ // its functionality has been moved into Handler. If you need to add
539+ // new functionality add it to the Handler, but make sure this
540+ // class calls into the Handler.
541+
542+ /**
543+ * Called when the mouse wheel is rotated while over a
544+ * JScrollPane.
545+ *
546+ * @param e MouseWheelEvent to be handled
547+ * @since 1.4
548+ */
549+ public void mouseWheelMoved(MouseWheelEvent e) {
550+ getHandler().mouseWheelMoved(e);
551+ }
552+ }
553+
554+ /**
555+ * Creates an instance of MouseWheelListener, which is added to the
556+ * JScrollPane by installUI(). The returned MouseWheelListener is used
557+ * to handle mouse wheel-driven scrolling.
558+ *
559+ * @return MouseWheelListener which implements wheel-driven scrolling
560+ * @see #installUI
561+ * @see MouseWheelHandler
562+ * @since 1.4
563+ */
564+ protected MouseWheelListener createMouseWheelListener() {
565+ return getHandler();
566+ }
567+
568+ protected void updateScrollBarDisplayPolicy(PropertyChangeEvent e) {
569+ scrollpane.revalidate();
570+ scrollpane.repaint();
571+ }
572+
573+
574+ protected void updateViewport(PropertyChangeEvent e)
575+ {
576+ JViewport oldViewport = (JViewport)(e.getOldValue());
577+ JViewport newViewport = (JViewport)(e.getNewValue());
578+
579+ if (oldViewport != null) {
580+ oldViewport.removeChangeListener(viewportChangeListener);
581+ }
582+
583+ if (newViewport != null) {
584+ Point p = newViewport.getViewPosition();
585+ if (scrollpane.getComponentOrientation().isLeftToRight()) {
586+ p.x = Math.max(p.x, 0);
587+ } else {
588+ int max = newViewport.getViewSize().width;
589+ int extent = newViewport.getExtentSize().width;
590+ if (extent > max) {
591+ p.x = max - extent;
592+ } else {
593+ p.x = Math.max(0, Math.min(max - extent, p.x));
594+ }
595+ }
596+ p.y = Math.max(p.y, 0);
597+ newViewport.setViewPosition(p);
598+ newViewport.addChangeListener(viewportChangeListener);
599+ }
600+ }
601+
602+
603+ protected void updateRowHeader(PropertyChangeEvent e)
604+ {
605+ JViewport newRowHead = (JViewport)(e.getNewValue());
606+ if (newRowHead != null) {
607+ JViewport viewport = scrollpane.getViewport();
608+ Point p = newRowHead.getViewPosition();
609+ p.y = (viewport != null) ? viewport.getViewPosition().y : 0;
610+ newRowHead.setViewPosition(p);
611+ }
612+ }
613+
614+
615+ protected void updateColumnHeader(PropertyChangeEvent e)
616+ {
617+ JViewport newColHead = (JViewport)(e.getNewValue());
618+ if (newColHead != null) {
619+ JViewport viewport = scrollpane.getViewport();
620+ Point p = newColHead.getViewPosition();
621+ if (viewport == null) {
622+ p.x = 0;
623+ } else {
624+ if (scrollpane.getComponentOrientation().isLeftToRight()) {
625+ p.x = viewport.getViewPosition().x;
626+ } else {
627+ p.x = Math.max(0, viewport.getViewPosition().x);
628+ }
629+ }
630+ newColHead.setViewPosition(p);
631+ scrollpane.add(newColHead, COLUMN_HEADER);
632+ }
633+ }
634+
635+ private void updateHorizontalScrollBar(PropertyChangeEvent pce) {
636+ updateScrollBar(pce, hsbChangeListener, hsbPropertyChangeListener);
637+ }
638+
639+ private void updateVerticalScrollBar(PropertyChangeEvent pce) {
640+ updateScrollBar(pce, vsbChangeListener, vsbPropertyChangeListener);
641+ }
642+
643+ private void updateScrollBar(PropertyChangeEvent pce, ChangeListener cl,
644+ PropertyChangeListener pcl) {
645+ JScrollBar sb = (JScrollBar)pce.getOldValue();
646+ if (sb != null) {
647+ if (cl != null) {
648+ sb.getModel().removeChangeListener(cl);
649+ }
650+ if (pcl != null) {
651+ sb.removePropertyChangeListener(pcl);
652+ }
653+ }
654+ sb = (JScrollBar)pce.getNewValue();
655+ if (sb != null) {
656+ if (cl != null) {
657+ sb.getModel().addChangeListener(cl);
658+ }
659+ if (pcl != null) {
660+ sb.addPropertyChangeListener(pcl);
661+ }
662+ }
663+ }
664+
665+ public class PropertyChangeHandler implements PropertyChangeListener
666+ {
667+
668+ // NOTE: This class exists only for backward compatability. All
669+ // its functionality has been moved into Handler. If you need to add
670+ // new functionality add it to the Handler, but make sure this
671+ // class calls into the Handler.
672+
673+ public void propertyChange(PropertyChangeEvent e)
674+ {
675+ getHandler().propertyChange(e);
676+ }
677+ }
678+
679+
680+
681+ /**
682+ * Creates an instance of PropertyChangeListener that's added to
683+ * the JScrollPane by installUI(). Subclasses can override this method
684+ * to return a custom PropertyChangeListener, e.g.
685+ * <pre>
686+ * class MyScrollPaneUI extends BasicScrollPaneUI {
687+ * protected PropertyChangeListener <b>createPropertyChangeListener</b>() {
688+ * return new MyPropertyChangeListener();
689+ * }
690+ * public class MyPropertyChangeListener extends PropertyChangeListener {
691+ * public void propertyChange(PropertyChangeEvent e) {
692+ * if (e.getPropertyName().equals("viewport")) {
693+ * // do some extra work when the viewport changes
694+ * }
695+ * super.propertyChange(e);
696+ * }
697+ * }
698+ * }
699+ * </pre>
700+ *
701+ * @see java.beans.PropertyChangeListener
702+ * @see #installUI
703+ */
704+ protected PropertyChangeListener createPropertyChangeListener() {
705+ return getHandler();
706+ }
707+
708+
709+ private static class Actions extends UIAction {
710+ private static final String SCROLL_UP = "scrollUp";
711+ private static final String SCROLL_DOWN = "scrollDown";
712+ private static final String SCROLL_HOME = "scrollHome";
713+ private static final String SCROLL_END = "scrollEnd";
714+ private static final String UNIT_SCROLL_UP = "unitScrollUp";
715+ private static final String UNIT_SCROLL_DOWN = "unitScrollDown";
716+ private static final String SCROLL_LEFT = "scrollLeft";
717+ private static final String SCROLL_RIGHT = "scrollRight";
718+ private static final String UNIT_SCROLL_LEFT = "unitScrollLeft";
719+ private static final String UNIT_SCROLL_RIGHT = "unitScrollRight";
720+
721+
722+ Actions(String key) {
723+ super(key);
724+ }
725+
726+ public void actionPerformed(ActionEvent e) {
727+ JScrollPane scrollPane = (JScrollPane)e.getSource();
728+ boolean ltr = scrollPane.getComponentOrientation().isLeftToRight();
729+ String key = getName();
730+
731+ if (key == SCROLL_UP) {
732+ scroll(scrollPane, SwingConstants.VERTICAL, -1, true);
733+ }
734+ else if (key == SCROLL_DOWN) {
735+ scroll(scrollPane, SwingConstants.VERTICAL, 1, true);
736+ }
737+ else if (key == SCROLL_HOME) {
738+ scrollHome(scrollPane);
739+ }
740+ else if (key == SCROLL_END) {
741+ scrollEnd(scrollPane);
742+ }
743+ else if (key == UNIT_SCROLL_UP) {
744+ scroll(scrollPane, SwingConstants.VERTICAL, -1, false);
745+ }
746+ else if (key == UNIT_SCROLL_DOWN) {
747+ scroll(scrollPane, SwingConstants.VERTICAL, 1, false);
748+ }
749+ else if (key == SCROLL_LEFT) {
750+ scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? -1 : 1,
751+ true);
752+ }
753+ else if (key == SCROLL_RIGHT) {
754+ scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? 1 : -1,
755+ true);
756+ }
757+ else if (key == UNIT_SCROLL_LEFT) {
758+ scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? -1 : 1,
759+ false);
760+ }
761+ else if (key == UNIT_SCROLL_RIGHT) {
762+ scroll(scrollPane, SwingConstants.HORIZONTAL, ltr ? 1 : -1,
763+ false);
764+ }
765+ }
766+
767+ private void scrollEnd(JScrollPane scrollpane) {
768+ JViewport vp = scrollpane.getViewport();
769+ Component view;
770+ if (vp != null && (view = vp.getView()) != null) {
771+ Rectangle visRect = vp.getViewRect();
772+ Rectangle bounds = view.getBounds();
773+ if (scrollpane.getComponentOrientation().isLeftToRight()) {
774+ vp.setViewPosition(new Point(bounds.width - visRect.width,
775+ bounds.height - visRect.height));
776+ } else {
777+ vp.setViewPosition(new Point(0,
778+ bounds.height - visRect.height));
779+ }
780+ }
781+ }
782+
783+ private void scrollHome(JScrollPane scrollpane) {
784+ JViewport vp = scrollpane.getViewport();
785+ Component view;
786+ if (vp != null && (view = vp.getView()) != null) {
787+ if (scrollpane.getComponentOrientation().isLeftToRight()) {
788+ vp.setViewPosition(new Point(0, 0));
789+ } else {
790+ Rectangle visRect = vp.getViewRect();
791+ Rectangle bounds = view.getBounds();
792+ vp.setViewPosition(new Point(bounds.width - visRect.width, 0));
793+ }
794+ }
795+ }
796+
797+ private void scroll(JScrollPane scrollpane, int orientation,
798+ int direction, boolean block) {
799+ JViewport vp = scrollpane.getViewport();
800+ Component view;
801+ if (vp != null && (view = vp.getView()) != null) {
802+ Rectangle visRect = vp.getViewRect();
803+ Dimension vSize = view.getSize();
804+ int amount;
805+
806+ if (view instanceof Scrollable) {
807+ if (block) {
808+ amount = ((Scrollable)view).getScrollableBlockIncrement
809+ (visRect, orientation, direction);
810+ }
811+ else {
812+ amount = ((Scrollable)view).getScrollableUnitIncrement
813+ (visRect, orientation, direction);
814+ }
815+ }
816+ else {
817+ if (block) {
818+ if (orientation == SwingConstants.VERTICAL) {
819+ amount = visRect.height;
820+ }
821+ else {
822+ amount = visRect.width;
823+ }
824+ }
825+ else {
826+ amount = 10;
827+ }
828+ }
829+ if (orientation == SwingConstants.VERTICAL) {
830+ visRect.y += (amount * direction);
831+ if ((visRect.y + visRect.height) > vSize.height) {
832+ visRect.y = Math.max(0, vSize.height - visRect.height);
833+ }
834+ else if (visRect.y < 0) {
835+ visRect.y = 0;
836+ }
837+ }
838+ else {
839+ if (scrollpane.getComponentOrientation().isLeftToRight()) {
840+ visRect.x += (amount * direction);
841+ if ((visRect.x + visRect.width) > vSize.width) {
842+ visRect.x = Math.max(0, vSize.width - visRect.width);
843+ } else if (visRect.x < 0) {
844+ visRect.x = 0;
845+ }
846+ } else {
847+ visRect.x -= (amount * direction);
848+ if (visRect.width > vSize.width) {
849+ visRect.x = vSize.width - visRect.width;
850+ } else {
851+ visRect.x = Math.max(0, Math.min(vSize.width - visRect.width, visRect.x));
852+ }
853+ }
854+ }
855+ vp.setViewPosition(visRect.getLocation());
856+ }
857+ }
858+ }
859+
860+
861+ class Handler implements ChangeListener, PropertyChangeListener, MouseWheelListener {
862+ //
863+ // MouseWheelListener
864+ //
865+ public void mouseWheelMoved(MouseWheelEvent e) {
866+ if (scrollpane.isWheelScrollingEnabled() &&
867+ e.getWheelRotation() != 0) {
868+ JScrollBar toScroll = scrollpane.getVerticalScrollBar();
869+ int direction = e.getWheelRotation() < 0 ? -1 : 1;
870+ int orientation = SwingConstants.VERTICAL;
871+
872+ // find which scrollbar to scroll, or return if none
873+ if (toScroll == null || !toScroll.isVisible()) {
874+ toScroll = scrollpane.getHorizontalScrollBar();
875+ if (toScroll == null || !toScroll.isVisible()) {
876+ return;
877+ }
878+ orientation = SwingConstants.HORIZONTAL;
879+ }
880+
881+ e.consume();
882+
883+ if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
884+ JViewport vp = scrollpane.getViewport();
885+ if (vp == null) { return; }
886+ Component comp = vp.getView();
887+ int units = Math.abs(e.getUnitsToScroll());
888+
889+ // When the scrolling speed is set to maximum, it's possible
890+ // for a single wheel click to scroll by more units than
891+ // will fit in the visible area. This makes it
892+ // hard/impossible to get to certain parts of the scrolling
893+ // Component with the wheel. To make for more accurate
894+ // low-speed scrolling, we limit scrolling to the block
895+ // increment if the wheel was only rotated one click.
896+ boolean limitScroll = Math.abs(e.getWheelRotation()) == 1;
897+
898+ // Check if we should use the visibleRect trick
899+ Object fastWheelScroll = toScroll.getClientProperty(
900+ "JScrollBar.fastWheelScrolling");
901+ if (Boolean.TRUE == fastWheelScroll &&
902+ comp instanceof Scrollable) {
903+ // 5078454: Under maximum acceleration, we may scroll
904+ // by many 100s of units in ~1 second.
905+ //
906+ // BasicScrollBarUI.scrollByUnits() can bog down the EDT
907+ // with repaints in this situation. However, the
908+ // Scrollable interface allows us to pass in an
909+ // arbitrary visibleRect. This allows us to accurately
910+ // calculate the total scroll amount, and then update
911+ // the GUI once. This technique provides much faster
912+ // accelerated wheel scrolling.
913+ Scrollable scrollComp = (Scrollable) comp;
914+ Rectangle viewRect = vp.getViewRect();
915+ int startingX = viewRect.x;
916+ boolean leftToRight =
917+ comp.getComponentOrientation().isLeftToRight();
918+ int scrollMin = toScroll.getMinimum();
919+ int scrollMax = toScroll.getMaximum() -
920+ toScroll.getModel().getExtent();
921+
922+ if (limitScroll) {
923+ int blockIncr =
924+ scrollComp.getScrollableBlockIncrement(viewRect,
925+ orientation,
926+ direction);
927+ if (direction < 0) {
928+ scrollMin = Math.max(scrollMin,
929+ toScroll.getValue() - blockIncr);
930+ }
931+ else {
932+ scrollMax = Math.min(scrollMax,
933+ toScroll.getValue() + blockIncr);
934+ }
935+ }
936+
937+ for (int i = 0; i < units; i++) {
938+ int unitIncr =
939+ scrollComp.getScrollableUnitIncrement(viewRect,
940+ orientation, direction);
941+ // Modify the visible rect for the next unit, and
942+ // check to see if we're at the end already.
943+ if (orientation == SwingConstants.VERTICAL) {
944+ if (direction < 0) {
945+ viewRect.y -= unitIncr;
946+ if (viewRect.y <= scrollMin) {
947+ viewRect.y = scrollMin;
948+ break;
949+ }
950+ }
951+ else { // (direction > 0
952+ viewRect.y += unitIncr;
953+ if (viewRect.y >= scrollMax) {
954+ viewRect.y = scrollMax;
955+ break;
956+ }
957+ }
958+ }
959+ else {
960+ // Scroll left
961+ if ((leftToRight && direction < 0) ||
962+ (!leftToRight && direction > 0)) {
963+ viewRect.x -= unitIncr;
964+ if (leftToRight) {
965+ if (viewRect.x < scrollMin) {
966+ viewRect.x = scrollMin;
967+ break;
968+ }
969+ }
970+ }
971+ // Scroll right
972+ else if ((leftToRight && direction > 0) ||
973+ (!leftToRight && direction < 0)) {
974+ viewRect.x += unitIncr;
975+ if (leftToRight) {
976+ if (viewRect.x > scrollMax) {
977+ viewRect.x = scrollMax;
978+ break;
979+ }
980+ }
981+ }
982+ else {
983+ assert false : "Non-sensical ComponentOrientation / scroll direction";
984+ }
985+ }
986+ }
987+ // Set the final view position on the ScrollBar
988+ if (orientation == SwingConstants.VERTICAL) {
989+ toScroll.setValue(viewRect.y);
990+ }
991+ else {
992+ if (leftToRight) {
993+ toScroll.setValue(viewRect.x);
994+ }
995+ else {
996+ // rightToLeft scrollbars are oriented with
997+ // minValue on the right and maxValue on the
998+ // left.
999+ int newPos = toScroll.getValue() -
1000+ (viewRect.x - startingX);
1001+ if (newPos < scrollMin) {
1002+ newPos = scrollMin;
1003+ }
1004+ else if (newPos > scrollMax) {
1005+ newPos = scrollMax;
1006+ }
1007+ toScroll.setValue(newPos);
1008+ }
1009+ }
1010+ }
1011+ else {
1012+ // Viewport's view is not a Scrollable, or fast wheel
1013+ // scrolling is not enabled.
1014+ BasicScrollBarUI.scrollByUnits(toScroll, direction,
1015+ units, limitScroll);
1016+ }
1017+ }
1018+ else if (e.getScrollType() ==
1019+ MouseWheelEvent.WHEEL_BLOCK_SCROLL) {
1020+ BasicScrollBarUI.scrollByBlock(toScroll, direction);
1021+ }
1022+ }
1023+ }
1024+
1025+ //
1026+ // ChangeListener: This is added to the vieport, and hsb/vsb models.
1027+ //
1028+ public void stateChanged(ChangeEvent e) {
1029+ JViewport viewport = scrollpane.getViewport();
1030+
1031+ if (viewport != null) {
1032+ if (e.getSource() == viewport) {
1033+ syncScrollPaneWithViewport();
1034+ }
1035+ else {
1036+ JScrollBar hsb = scrollpane.getHorizontalScrollBar();
1037+ if (hsb != null && e.getSource() == hsb.getModel()) {
1038+ hsbStateChanged(viewport, e);
1039+ }
1040+ else {
1041+ JScrollBar vsb = scrollpane.getVerticalScrollBar();
1042+ if (vsb != null && e.getSource() == vsb.getModel()) {
1043+ vsbStateChanged(viewport, e);
1044+ }
1045+ }
1046+ }
1047+ }
1048+ }
1049+
1050+ private void vsbStateChanged(JViewport viewport, ChangeEvent e) {
1051+ BoundedRangeModel model = (BoundedRangeModel)(e.getSource());
1052+ Point p = viewport.getViewPosition();
1053+ p.y = model.getValue();
1054+ viewport.setViewPosition(p);
1055+ }
1056+
1057+ private void hsbStateChanged(JViewport viewport, ChangeEvent e) {
1058+ BoundedRangeModel model = (BoundedRangeModel)(e.getSource());
1059+ Point p = viewport.getViewPosition();
1060+ int value = model.getValue();
1061+ if (scrollpane.getComponentOrientation().isLeftToRight()) {
1062+ p.x = value;
1063+ } else {
1064+ int max = viewport.getViewSize().width;
1065+ int extent = viewport.getExtentSize().width;
1066+ int oldX = p.x;
1067+
1068+ /* Set new X coordinate based on "value".
1069+ */
1070+ p.x = max - extent - value;
1071+
1072+ /* If setValue() was called before "extent" was fixed,
1073+ * turn setValueCalled flag on.
1074+ */
1075+ if ((extent == 0) && (value != 0) && (oldX == max)) {
1076+ setValueCalled = true;
1077+ } else {
1078+ /* When a pane without a horizontal scroll bar was
1079+ * reduced and the bar appeared, the viewport should
1080+ * show the right side of the view.
1081+ */
1082+ if ((extent != 0) && (oldX < 0) && (p.x == 0)) {
1083+ p.x += value;
1084+ }
1085+ }
1086+ }
1087+ viewport.setViewPosition(p);
1088+ }
1089+
1090+ //
1091+ // PropertyChangeListener: This is installed on both the JScrollPane
1092+ // and the horizontal/vertical scrollbars.
1093+ //
1094+
1095+ // Listens for changes in the model property and reinstalls the
1096+ // horizontal/vertical PropertyChangeListeners.
1097+ public void propertyChange(PropertyChangeEvent e) {
1098+ if (e.getSource() == scrollpane) {
1099+ scrollPanePropertyChange(e);
1100+ }
1101+ else {
1102+ sbPropertyChange(e);
1103+ }
1104+ }
1105+
1106+ private void scrollPanePropertyChange(PropertyChangeEvent e) {
1107+ String propertyName = e.getPropertyName();
1108+
1109+ if (propertyName == "verticalScrollBarDisplayPolicy") {
1110+ updateScrollBarDisplayPolicy(e);
1111+ }
1112+ else if (propertyName == "horizontalScrollBarDisplayPolicy") {
1113+ updateScrollBarDisplayPolicy(e);
1114+ }
1115+ else if (propertyName == "viewport") {
1116+ updateViewport(e);
1117+ }
1118+ else if (propertyName == "rowHeader") {
1119+ updateRowHeader(e);
1120+ }
1121+ else if (propertyName == "columnHeader") {
1122+ updateColumnHeader(e);
1123+ }
1124+ else if (propertyName == "verticalScrollBar") {
1125+ updateVerticalScrollBar(e);
1126+ }
1127+ else if (propertyName == "horizontalScrollBar") {
1128+ updateHorizontalScrollBar(e);
1129+ }
1130+ else if (propertyName == "componentOrientation") {
1131+ scrollpane.revalidate();
1132+ scrollpane.repaint();
1133+ }
1134+ }
1135+
1136+ // PropertyChangeListener for the horizontal and vertical scrollbars.
1137+ private void sbPropertyChange(PropertyChangeEvent e) {
1138+ String propertyName = e.getPropertyName();
1139+ Object source = e.getSource();
1140+
1141+ if ("model" == propertyName) {
1142+ JScrollBar sb = scrollpane.getVerticalScrollBar();
1143+ BoundedRangeModel oldModel = (BoundedRangeModel)e.
1144+ getOldValue();
1145+ ChangeListener cl = null;
1146+
1147+ if (source == sb) {
1148+ cl = vsbChangeListener;
1149+ }
1150+ else if (source == scrollpane.getHorizontalScrollBar()) {
1151+ sb = scrollpane.getHorizontalScrollBar();
1152+ cl = hsbChangeListener;
1153+ }
1154+ if (cl != null) {
1155+ if (oldModel != null) {
1156+ oldModel.removeChangeListener(cl);
1157+ }
1158+ if (sb.getModel() != null) {
1159+ sb.getModel().addChangeListener(cl);
1160+ }
1161+ }
1162+ }
1163+ else if ("componentOrientation" == propertyName) {
1164+ if (source == scrollpane.getHorizontalScrollBar()) {
1165+ JScrollBar hsb = scrollpane.getHorizontalScrollBar();
1166+ JViewport viewport = scrollpane.getViewport();
1167+ Point p = viewport.getViewPosition();
1168+ if (scrollpane.getComponentOrientation().isLeftToRight()) {
1169+ p.x = hsb.getValue();
1170+ } else {
1171+ p.x = viewport.getViewSize().width - viewport.getExtentSize().width - hsb.getValue();
1172+ }
1173+ viewport.setViewPosition(p);
1174+ }
1175+ }
1176+ }
1177+ }
1178+}