001 /* JScrollPane.java --
002 Copyright (C) 2002, 2004, 2005 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;
040
041 import java.awt.Component;
042 import java.awt.ComponentOrientation;
043 import java.awt.Insets;
044 import java.awt.LayoutManager;
045 import java.awt.Rectangle;
046 import java.beans.PropertyChangeEvent;
047 import java.beans.PropertyChangeListener;
048
049 import javax.accessibility.Accessible;
050 import javax.accessibility.AccessibleContext;
051 import javax.swing.border.Border;
052 import javax.swing.event.ChangeEvent;
053 import javax.swing.event.ChangeListener;
054 import javax.swing.plaf.ScrollPaneUI;
055 import javax.swing.plaf.UIResource;
056
057 /**
058 * A component that embeds another component and enables it to be scrolled
059 * both in horizontal and vertical direction.
060 *
061 * <table>
062 * <tr><th>Property </th><th>Stored in </th><th>Bound?</th></tr>
063 * <tr><td>columnHeader </td><td>scrollPane </td><td>yes </td></tr>
064 * <tr><td>columnHeaderView </td><td>columnHeader </td><td>no </td></tr>
065 * <tr><td>componentOrientation </td><td>scrollPane </td><td>yes </td></tr>
066 * <tr><td>horizontalScrollBar </td><td>scrollPane </td><td>yes </td></tr>
067 * <tr><td>horizontalScrollBarPolicy </td><td>scrollPane </td><td>yes </td></tr>
068 * <tr><td>layout </td><td>scrollPane </td><td>yes </td></tr>
069 * <tr><td>rowHeader </td><td>scrollPane </td><td>yes </td></tr>
070 * <tr><td>rowHeaderView </td><td>rowHeader </td><td>no </td></tr>
071 * <tr><td>validateRoot </td><td>scrollPane </td><td>no </td></tr>
072 * <tr><td>verticalScrollBar </td><td>scrollPane </td><td>yes </td></tr>
073 * <tr><td>verticalScrollBarPolicy </td><td>scrollPane </td><td>yes </td></tr>
074 * <tr><td>viewport </td><td>scrollPane </td><td>yes </td></tr>
075 * <tr><td>viewportBorder </td><td>scrollPane </td><td>yes </td></tr>
076 * <tr><td>viewportBorderBounds </td><td>scrollPane </td><td>no </td></tr>
077 * <tr><td>viewportView </td><td>viewport </td><td>no </td></tr>
078 * <tr><td>wheelScrollingEnabled </td><td>scrollPane </td><td>yes </td></tr>
079 * </table>
080 */
081 public class JScrollPane extends JComponent
082 implements Accessible, ScrollPaneConstants
083 {
084 /**
085 * Provides accessibility support for the <code>JScrollPane</code>.
086 *
087 * @author Roman Kennke (kennke@aicas.com)
088 */
089 protected class AccessibleJScrollPane extends AccessibleJComponent
090 implements ChangeListener, PropertyChangeListener
091 {
092
093 /**
094 * The viewport of the underlying scrollpane.
095 */
096 protected JViewport viewPort;
097
098 /**
099 * Creates a new <code>AccessibleJScrollPane</code> object. This
100 * initializes the <code>viewport</code> field with the current viewport
101 * from the scrollpane associated with this
102 * <code>AccessibleJScrollPane</code>.
103 */
104 public AccessibleJScrollPane()
105 {
106 viewPort = getViewport();
107 viewPort.addChangeListener(this);
108 viewPort.addPropertyChangeListener(this);
109 }
110
111 /**
112 * Receives notification when the state of the viewport changes.
113 *
114 * @param event the change event
115 */
116 public void stateChanged(ChangeEvent event)
117 {
118 // TODO: Figure out what should be done here, if anything.
119 }
120
121 /**
122 * Receives notification if any of the viewport's bound properties changes.
123 *
124 * @param e the propery change event
125 */
126 public void propertyChange(PropertyChangeEvent e)
127 {
128 // TODO: Figure out what should be done here, if anything.
129 }
130
131 /**
132 * Resets the <code>viewPort</code> field when the scrollpane's viewport
133 * changes. This method is called by
134 * {@link JScrollPane#setViewport(JViewport)} in order to update the
135 * <code>viewPort</code> field and set up the listeners on this viewport
136 * correctly.
137 */
138 public void resetViewPort()
139 {
140 viewPort.removeChangeListener(this);
141 viewPort.removePropertyChangeListener(this);
142 viewPort = getViewport();
143 viewPort.addChangeListener(this);
144 viewPort.addPropertyChangeListener(this);
145 }
146 }
147
148 private static final long serialVersionUID = 5203525440012340014L;
149
150 protected JViewport columnHeader;
151 protected JViewport rowHeader;
152
153 protected Component lowerLeft;
154 protected Component lowerRight;
155 protected Component upperLeft;
156 protected Component upperRight;
157
158 protected JScrollBar horizontalScrollBar;
159 protected int horizontalScrollBarPolicy;
160 protected JScrollBar verticalScrollBar;
161 protected int verticalScrollBarPolicy;
162
163 protected JViewport viewport;
164
165 private Border viewportBorder;
166
167 private boolean wheelScrollingEnabled;
168
169 public JViewport getColumnHeader()
170 {
171 return columnHeader;
172 }
173
174 public Component getCorner(String key)
175 {
176 if (getComponentOrientation()
177 == ComponentOrientation.LEFT_TO_RIGHT)
178 {
179 if (key == LOWER_LEADING_CORNER)
180 key = LOWER_LEFT_CORNER;
181 else if (key == LOWER_TRAILING_CORNER)
182 key = LOWER_RIGHT_CORNER;
183 else if (key == UPPER_LEADING_CORNER)
184 key = UPPER_LEFT_CORNER;
185 else if (key == UPPER_TRAILING_CORNER)
186 key = UPPER_RIGHT_CORNER;
187 }
188 else if (getComponentOrientation()
189 == ComponentOrientation.RIGHT_TO_LEFT)
190 {
191 if (key == LOWER_LEADING_CORNER)
192 key = LOWER_RIGHT_CORNER;
193 else if (key == LOWER_TRAILING_CORNER)
194 key = LOWER_LEFT_CORNER;
195 else if (key == UPPER_LEADING_CORNER)
196 key = UPPER_RIGHT_CORNER;
197 else if (key == UPPER_TRAILING_CORNER)
198 key = UPPER_LEFT_CORNER;
199 }
200
201 if (key == LOWER_RIGHT_CORNER)
202 return lowerRight;
203 else if (key == UPPER_RIGHT_CORNER)
204 return upperRight;
205 else if (key == LOWER_LEFT_CORNER)
206 return lowerLeft;
207 else if (key == UPPER_LEFT_CORNER)
208 return upperLeft;
209 return null;
210 }
211
212 public JScrollBar getHorizontalScrollBar()
213 {
214 return horizontalScrollBar;
215 }
216
217 public int getHorizontalScrollBarPolicy()
218 {
219 return horizontalScrollBarPolicy;
220 }
221
222 public JViewport getRowHeader()
223 {
224 return rowHeader;
225 }
226
227 public JScrollBar getVerticalScrollBar()
228 {
229 return verticalScrollBar;
230 }
231
232 public int getVerticalScrollBarPolicy()
233 {
234 return verticalScrollBarPolicy;
235 }
236
237 public JViewport getViewport()
238 {
239 return viewport;
240 }
241
242 public Border getViewportBorder()
243 {
244 return viewportBorder;
245 }
246
247 public Rectangle getViewportBorderBounds()
248 {
249 if (viewportBorder == null)
250 {
251 if (getViewport() == null)
252 return new Rectangle(0, 0, 0, 0);
253 else
254 return getViewport().getBounds();
255 }
256 else
257 {
258 Insets i = viewportBorder.getBorderInsets(getViewport());
259 if (getViewport() == null)
260 return new Rectangle(0, 0, i.left + i.right, i.top + i.bottom);
261 else
262 {
263 Rectangle b = getViewport().getBounds();
264 return new Rectangle(b.x - i.left,
265 b.y - i.top,
266 b.width + i.left + i.right,
267 b.height + i.top + i.bottom);
268 }
269 }
270 }
271
272 public boolean isWheelScrollingEnabled()
273 {
274 return wheelScrollingEnabled;
275 }
276
277
278
279 private void sync()
280 {
281 LayoutManager m = super.getLayout();
282 if (m != null && m instanceof ScrollPaneLayout)
283 {
284 ScrollPaneLayout sl = (ScrollPaneLayout) m;
285 sl.syncWithScrollPane(this);
286 }
287 }
288
289 private void removeNonNull(Component c)
290 {
291 if (c != null)
292 remove(c);
293 }
294
295 private void addNonNull(Component c, Object constraints)
296 {
297 if (c != null)
298 add(c, constraints);
299 }
300
301 public void setComponentOrientation(ComponentOrientation co)
302 {
303 ComponentOrientation old = super.getComponentOrientation();
304 super.setComponentOrientation(co);
305 firePropertyChange("componentOrientation", old, co);
306 sync();
307 }
308
309 public void setColumnHeader(JViewport h)
310 {
311 if (columnHeader == h)
312 return;
313
314 JViewport old = columnHeader;
315 removeNonNull(old);
316 columnHeader = h;
317 addNonNull(h, JScrollPane.COLUMN_HEADER);
318 firePropertyChange("columnHeader", old, h);
319 sync();
320 }
321
322 public void setColumnHeaderView(Component c)
323 {
324 if (columnHeader == null)
325 setColumnHeader(createViewport());
326 columnHeader.setView(c);
327 sync();
328 }
329
330 public void setCorner(String key, Component c)
331 {
332 if (getComponentOrientation()
333 == ComponentOrientation.LEFT_TO_RIGHT)
334 {
335 if (key == LOWER_LEADING_CORNER)
336 key = LOWER_LEFT_CORNER;
337 else if (key == LOWER_TRAILING_CORNER)
338 key = LOWER_RIGHT_CORNER;
339 else if (key == UPPER_LEADING_CORNER)
340 key = UPPER_LEFT_CORNER;
341 else if (key == UPPER_TRAILING_CORNER)
342 key = UPPER_RIGHT_CORNER;
343 }
344 else if (getComponentOrientation()
345 == ComponentOrientation.RIGHT_TO_LEFT)
346 {
347 if (key == LOWER_LEADING_CORNER)
348 key = LOWER_RIGHT_CORNER;
349 else if (key == LOWER_TRAILING_CORNER)
350 key = LOWER_LEFT_CORNER;
351 else if (key == UPPER_LEADING_CORNER)
352 key = UPPER_RIGHT_CORNER;
353 else if (key == UPPER_TRAILING_CORNER)
354 key = UPPER_LEFT_CORNER;
355 }
356
357 if (key == LOWER_RIGHT_CORNER)
358 {
359 removeNonNull(lowerRight);
360 lowerRight = c;
361 addNonNull(c, JScrollPane.LOWER_RIGHT_CORNER);
362 }
363 else if (key == UPPER_RIGHT_CORNER)
364 {
365 removeNonNull(upperRight);
366 upperRight = c;
367 addNonNull(c, JScrollPane.UPPER_RIGHT_CORNER);
368 }
369 else if (key == LOWER_LEFT_CORNER)
370 {
371 removeNonNull(lowerLeft);
372 lowerLeft = c;
373 addNonNull(c, JScrollPane.LOWER_LEFT_CORNER);
374 }
375 else if (key == UPPER_LEFT_CORNER)
376 {
377 removeNonNull(upperLeft);
378 upperLeft = c;
379 addNonNull(c, JScrollPane.UPPER_LEFT_CORNER);
380 }
381 else
382 throw new IllegalArgumentException("unknown corner " + key);
383 sync();
384 }
385
386 public void setHorizontalScrollBar(JScrollBar h)
387 {
388 if (horizontalScrollBar == h)
389 return;
390
391 JScrollBar old = horizontalScrollBar;
392 removeNonNull(old);
393 horizontalScrollBar = h;
394 addNonNull(h, JScrollPane.HORIZONTAL_SCROLLBAR);
395 firePropertyChange("horizontalScrollBar", old, h);
396 sync();
397
398 }
399
400 public void setHorizontalScrollBarPolicy(int h)
401 {
402 if (horizontalScrollBarPolicy == h)
403 return;
404
405 if (h != HORIZONTAL_SCROLLBAR_AS_NEEDED
406 && h != HORIZONTAL_SCROLLBAR_NEVER
407 && h != HORIZONTAL_SCROLLBAR_ALWAYS)
408 throw new IllegalArgumentException("unknown horizontal scrollbar policy");
409
410 int old = horizontalScrollBarPolicy;
411 horizontalScrollBarPolicy = h;
412 firePropertyChange("horizontalScrollBarPolicy", old, h);
413 sync();
414 revalidate();
415 }
416
417 public void setLayout(LayoutManager l)
418 {
419 LayoutManager old = super.getLayout();
420 ScrollPaneLayout tmp = (ScrollPaneLayout) l;
421 super.setLayout(l);
422 tmp.syncWithScrollPane(this);
423 firePropertyChange("layout", old, l);
424 sync();
425 }
426
427 public void setRowHeader(JViewport v)
428 {
429 if (rowHeader == v)
430 return;
431
432 JViewport old = rowHeader;
433 removeNonNull(old);
434 rowHeader = v;
435 addNonNull(v, JScrollPane.ROW_HEADER);
436 firePropertyChange("rowHeader", old, v);
437 sync();
438 }
439
440 public void setRowHeaderView(Component c)
441 {
442 if (rowHeader == null)
443 setRowHeader(createViewport());
444 rowHeader.setView(c);
445 sync();
446 }
447
448 public void setVerticalScrollBar(JScrollBar v)
449 {
450 if (verticalScrollBar == v)
451 return;
452
453 JScrollBar old = verticalScrollBar;
454 removeNonNull(old);
455 verticalScrollBar = v;
456 addNonNull(v, JScrollPane.VERTICAL_SCROLLBAR);
457 firePropertyChange("verticalScrollBar", old, v);
458 sync();
459 }
460
461 public void setVerticalScrollBarPolicy(int v)
462 {
463 if (verticalScrollBarPolicy == v)
464 return;
465
466 if (v != VERTICAL_SCROLLBAR_AS_NEEDED
467 && v != VERTICAL_SCROLLBAR_NEVER
468 && v != VERTICAL_SCROLLBAR_ALWAYS)
469 throw new IllegalArgumentException("unknown vertical scrollbar policy");
470
471 int old = verticalScrollBarPolicy;
472 verticalScrollBarPolicy = v;
473 firePropertyChange("verticalScrollBarPolicy", old, v);
474 sync();
475 revalidate();
476 }
477
478 public void setWheelScrollingEnabled(boolean b)
479 {
480 if (wheelScrollingEnabled == b)
481 return;
482
483 boolean old = wheelScrollingEnabled;
484 wheelScrollingEnabled = b;
485 firePropertyChange("wheelScrollingEnabled", old, b);
486 sync();
487 }
488
489 public void setViewport(JViewport v)
490 {
491 if (viewport == v)
492 return;
493
494 JViewport old = viewport;
495 removeNonNull(old);
496 viewport = v;
497 addNonNull(v, JScrollPane.VIEWPORT);
498 revalidate();
499 repaint();
500 firePropertyChange("viewport", old, v);
501 sync();
502 if (accessibleContext != null)
503 {
504 AccessibleJScrollPane asp = (AccessibleJScrollPane) accessibleContext;
505 asp.resetViewPort();
506 }
507 }
508
509 public void setViewportBorder(Border b)
510 {
511 if (viewportBorder == b)
512 return;
513
514 Border old = viewportBorder;
515 viewportBorder = b;
516 firePropertyChange("viewportBorder", old, b);
517 sync();
518 }
519
520 public void setViewportView(Component view)
521 {
522 if (getViewport() == null)
523 {
524 setViewport(createViewport());
525 }
526
527 if (view != null)
528 {
529 getViewport().setView(view);
530 }
531 sync();
532 }
533
534 public boolean isValidateRoot()
535 {
536 return true;
537 }
538
539 /**
540 * Creates a new <code>JScrollPane</code> without a view. The scrollbar
541 * policy is set to {@link #VERTICAL_SCROLLBAR_AS_NEEDED} and
542 * {@link #HORIZONTAL_SCROLLBAR_AS_NEEDED}.
543 */
544 public JScrollPane()
545 {
546 this(null);
547 }
548
549 /**
550 * Creates a new <code>JScrollPane</code> that embeds the specified
551 * <code>view</code> component, displaying vertical and horizontal scrollbars
552 * as needed.
553 *
554 * @param view the component that is embedded inside the JScrollPane
555 */
556 public JScrollPane(Component view)
557 {
558 this(view,
559 VERTICAL_SCROLLBAR_AS_NEEDED,
560 HORIZONTAL_SCROLLBAR_AS_NEEDED);
561 }
562
563 /**
564 * Creates a new <code>JScrollPane</code> without a view; The scrollbar
565 * policies are set to <code>vsbPolicy</code> and <code>hsbPolicy</code>.
566 *
567 * @param vsbPolicy the vertical scrollbar policy to set
568 * @param hsbPolicy the vertical scrollbar policy to set
569 *
570 * @see ScrollPaneConstants#HORIZONTAL_SCROLLBAR_ALWAYS
571 * @see ScrollPaneConstants#HORIZONTAL_SCROLLBAR_AS_NEEDED
572 * @see ScrollPaneConstants#HORIZONTAL_SCROLLBAR_NEVER
573 * @see ScrollPaneConstants#VERTICAL_SCROLLBAR_ALWAYS
574 * @see ScrollPaneConstants#VERTICAL_SCROLLBAR_AS_NEEDED
575 * @see ScrollPaneConstants#VERTICAL_SCROLLBAR_NEVER
576 */
577 public JScrollPane(int vsbPolicy, int hsbPolicy)
578 {
579 this(null, vsbPolicy, hsbPolicy);
580 }
581
582 /**
583 * Creates a new <code>JScrollPane</code> that embeds the specified
584 * <code>view</code> component; The scrollbar
585 * policies are set to <code>vsbPolicy</code> and <code>hsbPolicy</code>.
586 *
587 * @param vsbPolicy the vertical scrollbar policy to set
588 * @param hsbPolicy the vertical scrollbar policy to set
589 *
590 * @see ScrollPaneConstants#HORIZONTAL_SCROLLBAR_ALWAYS
591 * @see ScrollPaneConstants#HORIZONTAL_SCROLLBAR_AS_NEEDED
592 * @see ScrollPaneConstants#HORIZONTAL_SCROLLBAR_NEVER
593 * @see ScrollPaneConstants#VERTICAL_SCROLLBAR_ALWAYS
594 * @see ScrollPaneConstants#VERTICAL_SCROLLBAR_AS_NEEDED
595 * @see ScrollPaneConstants#VERTICAL_SCROLLBAR_NEVER
596 */
597 public JScrollPane(Component view, int vsbPolicy, int hsbPolicy)
598 {
599 wheelScrollingEnabled = true;
600 setVerticalScrollBarPolicy(vsbPolicy);
601 setVerticalScrollBar(createVerticalScrollBar());
602 setHorizontalScrollBarPolicy(hsbPolicy);
603 setHorizontalScrollBar(createHorizontalScrollBar());
604 viewport = createViewport();
605 if (view != null)
606 getViewport().setView(view);
607 add(viewport,0);
608 setLayout(new ScrollPaneLayout());
609 setOpaque(false);
610 updateUI();
611 }
612
613
614 public JScrollBar createHorizontalScrollBar()
615 {
616 return new ScrollBar(SwingConstants.HORIZONTAL);
617 }
618
619 public JScrollBar createVerticalScrollBar()
620 {
621 return new ScrollBar(SwingConstants.VERTICAL);
622 }
623
624 protected JViewport createViewport()
625 {
626 return new JViewport();
627 }
628
629 public String getUIClassID()
630 {
631 return "ScrollPaneUI";
632 }
633
634 public void updateUI()
635 {
636 setUI((ScrollPaneUI) UIManager.getUI(this));
637 }
638
639 /**
640 * This method returns the scrollpane's UI delegate.
641 *
642 * @return The scrollpane's UI delegate.
643 */
644 public ScrollPaneUI getUI()
645 {
646 return (ScrollPaneUI) ui;
647 }
648
649 /**
650 * This method sets the scrollpane's UI delegate.
651 *
652 * @param ui The scrollpane's UI delegate.
653 */
654 public void setUI(ScrollPaneUI ui)
655 {
656 super.setUI(ui);
657 }
658
659 protected class ScrollBar
660 extends JScrollBar
661 implements UIResource
662 {
663 private static final long serialVersionUID = -42032395320987283L;
664
665 public ScrollBar(int orientation)
666 {
667 super(orientation);
668 }
669
670 public int getBlockIncrement(int direction)
671 {
672 Component view = JScrollPane.this.getViewport().getView();
673 if (view == null || (! (view instanceof Scrollable)))
674 return super.getBlockIncrement(direction);
675 else
676 {
677 Scrollable s = (Scrollable) view;
678 return s.getScrollableBlockIncrement(JScrollPane.this.getViewport().getViewRect(),
679 this.getOrientation(),
680 direction);
681 }
682 }
683
684 public int getUnitIncrement(int direction)
685 {
686 Component view = JScrollPane.this.getViewport().getView();
687 if (view == null || (! (view instanceof Scrollable)))
688 return super.getUnitIncrement(direction);
689 else
690 {
691 Scrollable s = (Scrollable) view;
692 return s.getScrollableUnitIncrement(JScrollPane.this.getViewport().getViewRect(),
693 this.getOrientation(),
694 direction);
695 }
696 }
697 }
698
699 /**
700 * Returns the accessible context associated with this
701 * <code>JScrollPane</code>.
702 *
703 * @return the accessible context associated with this
704 * <code>JScrollPane</code>
705 */
706 public AccessibleContext getAccessibleContext()
707 {
708 if (accessibleContext == null)
709 accessibleContext = new AccessibleJScrollPane();
710 return accessibleContext;
711 }
712 }