001: /*
002: * @(#)FlatScrollPane.java 12/13/2006
003: *
004: * Copyright 2002 - 2006 JIDE Software Inc. All rights reserved.
005: */
006:
007: package com.jidesoft.swing;
008:
009: import com.jidesoft.icons.JideIconsFactory;
010:
011: import javax.swing.*;
012: import javax.swing.event.ChangeEvent;
013: import javax.swing.event.ChangeListener;
014: import javax.swing.plaf.ScrollBarUI;
015: import javax.swing.plaf.UIResource;
016: import java.awt.*;
017: import java.awt.event.ActionEvent;
018: import java.awt.event.ActionListener;
019: import java.awt.event.MouseEvent;
020: import java.awt.event.MouseListener;
021: import java.awt.event.MouseWheelEvent;
022: import java.awt.event.MouseWheelListener;
023:
024: /**
025: * <code>SimpleScrollPane</code> is a special scroll pane. There is no scroll bar.
026: * It just uses four scroll buttons to do the scrolling.
027: */
028: public class SimpleScrollPane extends JScrollPane implements
029: ChangeListener, MouseWheelListener {
030:
031: private AbstractButton _scrollUpButton;
032: private AbstractButton _scrollDownButton;
033:
034: private AbstractButton _scrollLeftButton;
035: private AbstractButton _scrollRightButton;
036:
037: private int _horizontalUnitIncrement = 10;
038: private boolean _horizontalUnitIncrementSet = false;
039:
040: private int _verticalUnitIncrement = 10;
041: private boolean _verticalUnitIncrementSet = false;
042:
043: private int _repeatDelay = 50;
044: private boolean _scrollOnRollover = true;
045:
046: public static final String SCROLL_UP_BUTTON = "SCROLL_UP_BUTTON";
047: public static final String SCROLL_DOWN_BUTTON = "SCROLL_DOWN_BUTTON";
048: public static final String SCROLL_LEFT_BUTTON = "SCROLL_LEFT_BUTTON";
049: public static final String SCROLL_RIGHT_BUTTON = "SCROLL_RIGHT_BUTTON";
050:
051: /**
052: * Creates a <code>JideScrollPane</code> that displays the view
053: * component in a viewport
054: * whose view position can be controlled with a pair of scrollbars.
055: * The scrollbar policies specify when the scrollbars are displayed,
056: * For example, if <code>vsbPolicy</code> is
057: * <code>VERTICAL_SCROLLBAR_AS_NEEDED</code>
058: * then the vertical scrollbar only appears if the view doesn't fit
059: * vertically. The available policy settings are listed at
060: * {@link #setVerticalScrollBarPolicy} and
061: * {@link #setHorizontalScrollBarPolicy}.
062: *
063: * @param view the component to display in the scrollpanes viewport
064: * @param vsbPolicy an integer that specifies the vertical
065: * scrollbar policy
066: * @param hsbPolicy an integer that specifies the horizontal
067: * scrollbar policy
068: * @see #setViewportView
069: */
070: public SimpleScrollPane(Component view, int vsbPolicy, int hsbPolicy) {
071: setLayout(new SimpleScrollPaneLayout.UIResource());
072: setVerticalScrollBarPolicy(vsbPolicy);
073: setHorizontalScrollBarPolicy(hsbPolicy);
074: setViewport(createViewport());
075: setScrollUpButton(createScrollButton(SwingConstants.NORTH));
076: setScrollDownButton(createScrollButton(SwingConstants.SOUTH));
077: setScrollLeftButton(createScrollButton(SwingConstants.WEST));
078: setScrollRightButton(createScrollButton(SwingConstants.EAST));
079: if (null != view) {
080: setViewportView(view);
081: }
082: updateButtonState();
083: setOpaque(true);
084: setFocusable(false);
085: if (getHorizontalScrollBar() != null) {
086: getHorizontalScrollBar().setVisible(false);
087: getHorizontalScrollBar().setFocusable(false);
088: }
089: if (getVerticalScrollBar() != null) {
090: getVerticalScrollBar().setVisible(false);
091: getVerticalScrollBar().setFocusable(false);
092: }
093: updateUI();
094:
095: if (!getComponentOrientation().isLeftToRight()) {
096: viewport.setViewPosition(new Point(Integer.MAX_VALUE, 0));
097: }
098:
099: if (this .isWheelScrollingEnabled())
100: this .addMouseWheelListener(this );
101: }
102:
103: /**
104: * Creates a <code>JideScrollPane</code> that displays the
105: * contents of the specified
106: * component, where both horizontal and vertical scrollbars appear
107: * whenever the component's contents are larger than the view.
108: *
109: * @param view the component to display in the scrollpane's viewport
110: * @see #setViewportView
111: */
112: public SimpleScrollPane(Component view) {
113: this (view, VERTICAL_SCROLLBAR_AS_NEEDED,
114: HORIZONTAL_SCROLLBAR_AS_NEEDED);
115: }
116:
117: /**
118: * Creates an empty (no viewport view) <code>JideScrollPane</code>
119: * with specified
120: * scrollbar policies. The available policy settings are listed at
121: * {@link #setVerticalScrollBarPolicy} and
122: * {@link #setHorizontalScrollBarPolicy}.
123: *
124: * @param vsbPolicy an integer that specifies the vertical
125: * scrollbar policy
126: * @param hsbPolicy an integer that specifies the horizontal
127: * scrollbar policy
128: * @see #setViewportView
129: */
130: public SimpleScrollPane(int vsbPolicy, int hsbPolicy) {
131: this (null, vsbPolicy, hsbPolicy);
132: }
133:
134: /**
135: * Creates an empty (no viewport view) <code>JideScrollPane</code>
136: * where both horizontal and vertical scrollbars appear when needed.
137: */
138: public SimpleScrollPane() {
139: this (null, VERTICAL_SCROLLBAR_AS_NEEDED,
140: HORIZONTAL_SCROLLBAR_AS_NEEDED);
141: }
142:
143: @Override
144: public void updateUI() {
145: super .updateUI();
146: LookAndFeel.installBorder(this , "JideScrollPane.border");
147: getViewport().addChangeListener(this );
148: }
149:
150: public void stateChanged(ChangeEvent e) {
151: if (e.getSource() == getViewport()) {
152: updateButtonState();
153: }
154: }
155:
156: public AbstractButton getScrollUpButton() {
157: return _scrollUpButton;
158: }
159:
160: public void setScrollUpButton(AbstractButton scrollUpButton) {
161: AbstractButton old = getScrollUpButton();
162: _scrollUpButton = scrollUpButton;
163: add(_scrollUpButton, SCROLL_UP_BUTTON);
164: firePropertyChange("scrollUpButton", old, _scrollUpButton);
165:
166: revalidate();
167: repaint();
168: }
169:
170: public AbstractButton getScrollDownButton() {
171: return _scrollDownButton;
172: }
173:
174: public void setScrollDownButton(AbstractButton scrollDownButton) {
175: AbstractButton old = getScrollDownButton();
176: _scrollDownButton = scrollDownButton;
177: add(_scrollDownButton, SCROLL_DOWN_BUTTON);
178: firePropertyChange("scrollDownButton", old, _scrollDownButton);
179:
180: revalidate();
181: repaint();
182: }
183:
184: public AbstractButton getScrollLeftButton() {
185: return _scrollLeftButton;
186: }
187:
188: public void setScrollLeftButton(AbstractButton scrollLeftButton) {
189: AbstractButton old = getScrollLeftButton();
190: _scrollLeftButton = scrollLeftButton;
191: add(_scrollLeftButton, SCROLL_LEFT_BUTTON);
192: firePropertyChange("scrollLeftButton", old, _scrollLeftButton);
193:
194: revalidate();
195: repaint();
196: }
197:
198: public AbstractButton getScrollRightButton() {
199: return _scrollRightButton;
200: }
201:
202: public void setScrollRightButton(AbstractButton scrollRightButton) {
203: AbstractButton old = getScrollRightButton();
204: _scrollRightButton = scrollRightButton;
205: add(_scrollRightButton, SCROLL_RIGHT_BUTTON);
206: firePropertyChange("scrollRightButton", old, _scrollRightButton);
207:
208: revalidate();
209: repaint();
210: }
211:
212: /**
213: * The scroll button for SimpleScrollPane. You can extend this class to create your own buttons.
214: */
215: public class ScrollButton extends JideButton implements
216: MouseListener, ActionListener, UIResource {
217: private int _type;
218: private Timer _timer;
219:
220: /**
221: * Creates a ScrollButton.
222: *
223: * @param type one of the four values - NORTH, SOUTH, WEST, EAST as defined in SwingConstants.
224: */
225: public ScrollButton(int type) {
226: _type = type;
227: switch (type) {
228: case SwingConstants.NORTH:
229: setIcon(JideIconsFactory
230: .getImageIcon(JideIconsFactory.Arrow.UP));
231: break;
232: case SwingConstants.SOUTH:
233: setIcon(JideIconsFactory
234: .getImageIcon(JideIconsFactory.Arrow.DOWN));
235: break;
236: case SwingConstants.WEST:
237: setIcon(JideIconsFactory
238: .getImageIcon(JideIconsFactory.Arrow.LEFT));
239: break;
240: case SwingConstants.EAST:
241: setIcon(JideIconsFactory
242: .getImageIcon(JideIconsFactory.Arrow.RIGHT));
243: break;
244: }
245: addActionListener(this );
246: addMouseListener(this );
247: setPreferredSize(new Dimension(10, 10));
248: setMinimumSize(new Dimension(10, 10));
249: }
250:
251: public void actionPerformed(ActionEvent e) {
252: scroll(getViewport(), _type);
253: updateButtonState();
254: }
255:
256: public void mouseClicked(MouseEvent e) {
257: }
258:
259: public void mousePressed(MouseEvent e) {
260: if (!isScrollOnRollover()) {
261: startTimer(e, 500);
262: } else {
263: updateTimer(e);
264: }
265: }
266:
267: public void mouseReleased(MouseEvent e) {
268: if (!isScrollOnRollover()) {
269: stopTimer();
270: } else {
271: updateTimer(e);
272: }
273: }
274:
275: public void mouseEntered(MouseEvent e) {
276: if (isScrollOnRollover()) {
277: startTimer(e, 500);
278: }
279: }
280:
281: private void updateTimer(MouseEvent e) {
282: if (_timer != null) {
283: _timer.setDelay(getDelay(e));
284: }
285: }
286:
287: private void startTimer(MouseEvent e, int initDelay) {
288: stopTimer();
289: _timer = new Timer(getDelay(e), this );
290: _timer.setInitialDelay(initDelay);
291: _timer.start();
292: }
293:
294: private void stopTimer() {
295: if (_timer != null) {
296: _timer.stop();
297: _timer = null;
298: }
299: }
300:
301: private int getDelay(MouseEvent e) {
302: if (isScrollOnRollover()) {
303: return SwingUtilities.isLeftMouseButton(e) ? getRepeatDelay()
304: : getRepeatDelay() * 2;
305: } else {
306: return getRepeatDelay();
307: }
308: }
309:
310: public void mouseExited(MouseEvent e) {
311: if (isScrollOnRollover()) {
312: stopTimer();
313: }
314: }
315: }
316:
317: /**
318: * Creates the scroll button. You can override this method to change the attributes on the button. For example, you can do this to create a bigger scroll button.
319: * <code><pre>
320: * SimpleScrollPane pane = new SimpleScrollPane(){
321: * protected AbstractButton createScrollButton(int type) {
322: * AbstractButton scrollButton = super.createScrollButton(type);
323: * scrollButton.setPreferredSize(new Dimension(20, 20));
324: * return scrollButton;
325: * }
326: * };
327: * </pre></code>
328: *
329: * @param type the type of the scroll button. It could be {@link javax.swing.SwingConstants#NORTH},
330: * {@link javax.swing.SwingConstants#SOUTH}, {@link javax.swing.SwingConstants#WEST} or {@link javax.swing.SwingConstants#EAST} .
331: * @return the scroll button.
332: */
333: protected AbstractButton createScrollButton(int type) {
334: return new ScrollButton(type);
335: }
336:
337: protected void updateButtonState() {
338: Point p = viewport.getViewPosition();
339: _scrollUpButton.setEnabled(p.y != 0);
340: _scrollDownButton
341: .setEnabled(p.y != viewport.getViewSize().height
342: - viewport.getViewRect().height);
343: _scrollLeftButton.setEnabled(p.x != 0);
344: _scrollRightButton
345: .setEnabled(p.x != viewport.getViewSize().width
346: - viewport.getViewRect().width);
347: revalidate();
348: repaint();
349: }
350:
351: public void scroll(JViewport viewport, int type) {
352: Point p = viewport.getViewPosition();
353:
354: JViewport vp = getViewport();
355: switch (type) {
356: case SwingConstants.NORTH:
357: if (!_verticalUnitIncrementSet && (vp != null)
358: && (vp.getView() instanceof Scrollable)) {
359: Scrollable view = (Scrollable) (vp.getView());
360: Rectangle vr = vp.getViewRect();
361: p.y -= view.getScrollableUnitIncrement(vr,
362: SwingConstants.VERTICAL, -1);
363: } else {
364: p.y -= getVerticalUnitIncrement();
365: }
366: if (p.y < 0) {
367: p.y = 0;
368: }
369: break;
370: case SwingConstants.SOUTH:
371: if (!_verticalUnitIncrementSet && (vp != null)
372: && (vp.getView() instanceof Scrollable)) {
373: Scrollable view = (Scrollable) (vp.getView());
374: Rectangle vr = vp.getViewRect();
375: p.y += view.getScrollableUnitIncrement(vr,
376: SwingConstants.VERTICAL, 1);
377: } else {
378: p.y += getVerticalUnitIncrement();
379: }
380: if (p.y + viewport.getViewRect().height > viewport
381: .getViewSize().height) {
382: p.y = viewport.getViewSize().height
383: - viewport.getViewRect().height;
384: }
385: break;
386: case SwingConstants.WEST:
387: if (!_horizontalUnitIncrementSet && (vp != null)
388: && (vp.getView() instanceof Scrollable)) {
389: Scrollable view = (Scrollable) (vp.getView());
390: Rectangle vr = vp.getViewRect();
391: p.x -= view.getScrollableUnitIncrement(vr,
392: SwingConstants.HORIZONTAL, -1);
393: } else {
394: p.x -= getHorizontalUnitIncrement();
395: }
396: if (p.x < 0) {
397: p.x = 0;
398: }
399: break;
400: case SwingConstants.EAST:
401: if (!_horizontalUnitIncrementSet && (vp != null)
402: && (vp.getView() instanceof Scrollable)) {
403: Scrollable view = (Scrollable) (vp.getView());
404: Rectangle vr = vp.getViewRect();
405: p.x += view.getScrollableUnitIncrement(vr,
406: SwingConstants.HORIZONTAL, 1);
407: } else {
408: p.x += getHorizontalUnitIncrement();
409: }
410: if (p.x + viewport.getViewRect().width > viewport
411: .getViewSize().width) {
412: p.x = viewport.getViewSize().width
413: - viewport.getViewRect().width;
414: }
415: break;
416: }
417:
418: viewport.setViewPosition(p);
419: }
420:
421: @Override
422: public Rectangle getViewportBorderBounds() {
423: Rectangle borderR = new Rectangle(getSize());
424:
425: Insets insets = getInsets();
426: borderR.x = insets.left;
427: borderR.y = insets.top;
428: borderR.width -= insets.left + insets.right;
429: borderR.height -= insets.top + insets.bottom;
430:
431: if (_scrollUpButton != null && _scrollUpButton.isVisible()) {
432: borderR.y += _scrollUpButton.getHeight();
433: borderR.height -= _scrollUpButton.getHeight();
434: }
435:
436: if (_scrollLeftButton != null && _scrollLeftButton.isVisible()) {
437: borderR.x += _scrollLeftButton.getWidth();
438: borderR.width -= _scrollLeftButton.getWidth();
439: }
440:
441: if (_scrollDownButton != null && _scrollDownButton.isVisible()) {
442: borderR.height -= _scrollDownButton.getHeight();
443: }
444:
445: if (_scrollRightButton != null
446: && _scrollRightButton.isVisible()) {
447: borderR.width -= _scrollRightButton.getWidth();
448: }
449:
450: return borderR;
451: }
452:
453: public int getHorizontalUnitIncrement() {
454: return _horizontalUnitIncrement;
455: }
456:
457: public void setHorizontalUnitIncrement(int horizontalUnitIncrement) {
458: _horizontalUnitIncrementSet = true;
459: if (horizontalUnitIncrement != _horizontalUnitIncrement) {
460: int old = _horizontalUnitIncrement;
461: _horizontalUnitIncrement = horizontalUnitIncrement;
462: firePropertyChange("horizontalUnitIncrement", old,
463: _horizontalUnitIncrement);
464: }
465: }
466:
467: public int getVerticalUnitIncrement() {
468: return _verticalUnitIncrement;
469: }
470:
471: public void setVerticalUnitIncrement(int verticalUnitIncrement) {
472: _verticalUnitIncrementSet = true;
473: if (verticalUnitIncrement != _verticalUnitIncrement) {
474: int old = _verticalUnitIncrement;
475: _verticalUnitIncrement = verticalUnitIncrement;
476: firePropertyChange("verticalUnitIncrement", old,
477: _verticalUnitIncrement);
478: }
479: }
480:
481: /**
482: * Checks if the scroll button scrolls on rollover.
483: *
484: * @return true if it scrolls on rollover.
485: */
486: public boolean isScrollOnRollover() {
487: return _scrollOnRollover;
488: }
489:
490: /**
491: * Sets scroll on rollover. If true, the scrolling will start when mouse is placed above the scroll button.
492: * If false, the scrolling will start only when you click or press and hold the mouse button.
493: *
494: * @param scrollOnRollover true or false.
495: */
496: public void setScrollOnRollover(boolean scrollOnRollover) {
497: if (_scrollOnRollover != scrollOnRollover) {
498: boolean old = _scrollOnRollover;
499: _scrollOnRollover = scrollOnRollover;
500: firePropertyChange("scrollOnRollover", old,
501: _scrollOnRollover);
502: }
503: }
504:
505: /**
506: * Gets the delay in ms between each unit scrolling.
507: *
508: * @return the delay.
509: */
510: public int getRepeatDelay() {
511: return _repeatDelay;
512: }
513:
514: /**
515: * Sets the delay in ms betwen each unit scrolling. By default, it's 50. The big
516: * the nubmer, the slow the scrolling.
517: *
518: * @param repeatDelay thenew repeat delay.
519: */
520: public void setRepeatDelay(int repeatDelay) {
521: if (repeatDelay != _repeatDelay) {
522: int old = _repeatDelay;
523: _repeatDelay = repeatDelay;
524: firePropertyChange("repeatDelay", old, _repeatDelay);
525: }
526: }
527:
528: public void mouseWheelMoved(MouseWheelEvent e) {
529: if (this .isWheelScrollingEnabled() && e.getScrollAmount() != 0) {
530: boolean scrollingUp = (e.getWheelRotation() >= 0);
531: int direction = SwingConstants.CENTER;
532:
533: if (!this .isButtonVisible(scrollingUp))
534: return;
535:
536: direction = this .getScrollDirection(scrollingUp);
537: if (direction != SwingConstants.CENTER)
538: this .scroll(this .getViewport(), direction);
539: }
540: }
541:
542: private boolean isButtonVisible(boolean scrollingUp) {
543: if (scrollingUp)
544: return (((_scrollUpButton != null) && _scrollUpButton
545: .isVisible()) || ((_scrollLeftButton != null) && _scrollLeftButton
546: .isVisible()));
547: else
548: return (((_scrollDownButton != null) && _scrollDownButton
549: .isVisible()) || ((_scrollRightButton != null) && _scrollRightButton
550: .isVisible()));
551: }
552:
553: private int getScrollDirection(boolean scrollingUp) {
554: if (scrollingUp) {
555: if ((_scrollUpButton != null)
556: && _scrollUpButton.isVisible())
557: return SwingConstants.SOUTH;
558: if ((_scrollLeftButton != null)
559: && _scrollLeftButton.isVisible())
560: return SwingConstants.EAST;
561: } else {
562: if ((_scrollDownButton != null)
563: && _scrollDownButton.isVisible())
564: return SwingConstants.NORTH;
565: if ((_scrollRightButton != null)
566: && _scrollRightButton.isVisible())
567: return SwingConstants.WEST;
568: }
569:
570: return SwingConstants.CENTER;
571: }
572:
573: public void setWheelScrollingEnabled(boolean handleWheel) {
574: if (handleWheel && !isWheelScrollingEnabled())
575: this.addMouseWheelListener(this);
576: if (!handleWheel && isWheelScrollingEnabled())
577: this.removeMouseWheelListener(this);
578: super.setWheelScrollingEnabled(handleWheel);
579: }
580: }
|