001: /*
002: * Copyright 2000,2005 wingS development team.
003: *
004: * This file is part of wingS (http://wingsframework.org).
005: *
006: * wingS is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * Please see COPYING for the complete licence.
012: */
013: package org.wings;
014:
015: import java.awt.Adjustable;
016: import java.awt.LayoutManager;
017: import java.awt.Rectangle;
018:
019: import javax.swing.BoundedRangeModel;
020: import javax.swing.event.ChangeEvent;
021: import javax.swing.event.ChangeListener;
022: import javax.swing.event.EventListenerList;
023:
024: import org.wings.event.SViewportChangeEvent;
025: import org.wings.event.SViewportChangeListener;
026: import org.wings.plaf.ScrollPaneCG;
027:
028: /**
029: * A pane which allows to add {@link Scrollable} components on this pane
030: * and display only a viewport of it. Can be used to scroll graphically
031: * (default) or pages (using {@link SPageScroller} components.).
032: *
033: * @author <a href="mailto:haaf@mercatis.de">Armin Haaf</a>
034: */
035: public class SScrollPane extends SContainer implements
036: javax.swing.ScrollPaneConstants {
037:
038: public static final int MODE_SCROLLING = 0;
039: public static final int MODE_COMPLETE = 1;
040: public static final int MODE_PAGING = 2;
041:
042: /**
043: * The element which should be scrolled.
044: */
045: protected Scrollable scrollable;
046:
047: protected Adjustable verticalScrollBar = null;
048:
049: protected Adjustable horizontalScrollBar = null;
050:
051: protected int horizontalScrollBarPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED;
052:
053: protected int verticalScrollBarPolicy = VERTICAL_SCROLLBAR_AS_NEEDED;
054:
055: protected int horizontalExtent = 10;
056:
057: protected int verticalExtent = 10;
058:
059: protected int mode = MODE_SCROLLING;
060:
061: /**
062: * While the (horizontal) maximum of columns displayed by this scrollpane
063: * will never be greater than the number of available columns in the model
064: * of the contained scrollable, the (vertical) maximum of rows displayed by
065: * this scrollpane CAN be greater than the number of available rows in the
066: * model of the contained scrollable. For example this might be true if ...
067: * - MODE == SCROLLING and this scrollpane's vertical extent was set to
068: * something greater than the number of available rows in the model, or
069: * - MODE == PAGING and there are not enough rows in the model in order
070: * to fill up the last page so that the full vertical extent is reached.
071: * In such cases the scrollable's CG fills the difference with empty lines.
072: * The "virtualViewportHeight" equals der number of available rows in the
073: * scrollable's model (typically "scrollable.getScrollableViewport()") PLUS
074: * the number of empty lines needed to fill the viewport until the vertical
075: * extent of this scrollpane is reached.
076: * If MODE == COMPLETE this variable equals the number of available rows.
077: */
078: protected int virtualViewportHeight;
079:
080: /**
081: * Holds the viewport that the scrollable had before adding it to this
082: * scrollpane. The scrollable's viewport is reset to this value, if it
083: * is removed from the this scrollpane.
084: */
085: protected Rectangle backupViewport;
086:
087: protected SViewportSynchronizationModel horizontalModel = new SViewportSynchronizationModel(
088: true);
089:
090: protected SViewportSynchronizationModel verticalModel = new SViewportSynchronizationModel(
091: false);
092:
093: public SScrollPane() {
094: super (new SScrollPaneLayout());
095: setHorizontalScrollBar(new SScrollBar(SConstants.HORIZONTAL));
096: setVerticalScrollBar(new SScrollBar(SConstants.VERTICAL));
097: }
098:
099: public SScrollPane(SComponent c) {
100: this ();
101: setViewportView(c);
102: }
103:
104: /**
105: * Sets the element which should be scrolled.
106: *
107: * @param c the element which should be scrolled.
108: */
109: protected void setScrollable(SComponent c) {
110: if (scrollable != null) {
111: // reset the scrollable's viewport to the one
112: // it had before adding it to this scrollpane
113: scrollable.setViewportSize(backupViewport);
114: }
115:
116: if (c instanceof Scrollable) {
117: scrollable = (Scrollable) c;
118: horizontalModel.setScrollable(scrollable);
119: verticalModel.setScrollable(scrollable);
120:
121: // keep the scrollable's original viewport - the
122: // one it had before adding it to this scrollpane
123: backupViewport = scrollable.getViewportSize();
124:
125: // apply new viewport to scrollable
126: setInitialViewportSize();
127: } else {
128: scrollable = null;
129: }
130:
131: reload();
132: }
133:
134: /**
135: * Returns the element which should be scrolled.
136: *
137: * @return the element which should be scrolled.
138: */
139: public final Scrollable getScrollable() {
140: return scrollable;
141: }
142:
143: /**
144: * Sets the scrollable.
145: * If there is already one, it will be removed first.
146: *
147: * @param view the component to add to the viewport
148: */
149: public void setViewportView(SComponent view) {
150: add(view, SScrollPaneLayout.VIEWPORT);
151: }
152:
153: /**
154: * Only {@link Scrollable scrollables} are allowed here!
155: */
156: public SComponent addComponent(SComponent c, Object constraint,
157: int index) {
158: if (c instanceof Scrollable
159: || constraint == SScrollPaneLayout.VIEWPORT) {
160: super .addComponent(c, SScrollPaneLayout.VIEWPORT, index);
161: setScrollable(c);
162: } else {
163: super .addComponent(c, constraint, index);
164: }
165: return c;
166: }
167:
168: protected SComponent addMe(SComponent c, Object constraint,
169: int index) {
170: return super .addComponent(c, constraint, index);
171: }
172:
173: public int getMode() {
174: return mode;
175: }
176:
177: public void setMode(int mode) {
178: reloadIfChange(this .mode, mode);
179: this .mode = mode;
180: setInitialViewportSize();
181: }
182:
183: public void setCG(ScrollPaneCG cg) {
184: super .setCG(cg);
185: }
186:
187: /**
188: * Returns the horizontal scroll bar.
189: *
190: * @return the scrollbar that controls the viewports horizontal view position
191: */
192: public Adjustable getHorizontalScrollBar() {
193: return horizontalScrollBar;
194: }
195:
196: /**
197: * Sets the horizontal scroll bar.
198: *
199: * @param sb the scrollbar that controls the viewports horizontal view position
200: */
201: public void setHorizontalScrollBar(Adjustable sb) {
202: setHorizontalScrollBar(sb, SScrollPaneLayout.SOUTH);
203: }
204:
205: /**
206: * Sets the horizontal scrollbar.
207: *
208: * @param sb the scrollbar that controls the viewports horizontal view position
209: * @param constraint the constraint for the {@link LayoutManager} of this {@link SContainer}.
210: * The {@link LayoutManager} is per default {@link SScrollPaneLayout}.
211: */
212: public void setHorizontalScrollBar(Adjustable sb, String constraint) {
213: if (horizontalScrollBar != null) {
214: if (horizontalScrollBar instanceof SAbstractAdjustable)
215: ((SAbstractAdjustable) horizontalScrollBar)
216: .setModel(new SDefaultBoundedRangeModel());
217:
218: if (horizontalScrollBar instanceof SComponent)
219: super .remove((SComponent) horizontalScrollBar);
220: }
221:
222: horizontalScrollBar = sb;
223:
224: if (horizontalScrollBar != null) {
225: if (horizontalScrollBar instanceof SComponent)
226: super .addComponent((SComponent) horizontalScrollBar,
227: constraint, getComponentCount());
228:
229: if (horizontalScrollBar instanceof SAbstractAdjustable) {
230: SAbstractAdjustable scrollbar = (SAbstractAdjustable) horizontalScrollBar;
231: if (scrollbar.getOrientation() == SConstants.HORIZONTAL)
232: scrollbar.setModel(horizontalModel);
233: else
234: scrollbar.setModel(verticalModel);
235: }
236:
237: adoptScrollBarVisibility(horizontalScrollBar,
238: horizontalScrollBarPolicy);
239: }
240:
241: reload();
242: }
243:
244: /**
245: * Returns the horizontal scroll bar policy value.
246: *
247: * @return the horizontal scrollbar policy.
248: * @see #setHorizontalScrollBarPolicy(int)
249: */
250: public final int getHorizontalScrollBarPolicy() {
251: return horizontalScrollBarPolicy;
252: }
253:
254: /**
255: * Returns the vertical scrollbar.
256: *
257: * @return the scrollbar that controls the viewports vertical view position
258: */
259: public final Adjustable getVerticalScrollBar() {
260: return verticalScrollBar;
261: }
262:
263: /**
264: * Sets the vertical scroll bar.
265: *
266: * @param sb the scrollbar that controls the viewports vertical view position
267: */
268: public void setVerticalScrollBar(Adjustable sb) {
269: setVerticalScrollBar(sb, SScrollPaneLayout.EAST);
270: }
271:
272: /**
273: * Sets the vertical scroll bar.
274: *
275: * @param sb the scrollbar that controls the viewports vertical view position
276: * @param constraint the constraint for the {@link LayoutManager} of this {@link SContainer}.
277: * The {@link LayoutManager} is per default {@link SScrollPaneLayout}.
278: */
279: public void setVerticalScrollBar(Adjustable sb, String constraint) {
280: if (verticalScrollBar != null) {
281: if (verticalScrollBar instanceof SAbstractAdjustable)
282: ((SAbstractAdjustable) verticalScrollBar)
283: .setModel(new SDefaultBoundedRangeModel());
284:
285: if (verticalScrollBar instanceof SComponent)
286: super .remove((SComponent) verticalScrollBar);
287: }
288:
289: verticalScrollBar = sb;
290:
291: if (verticalScrollBar != null) {
292: if (verticalScrollBar instanceof SComponent)
293: super .addComponent((SComponent) verticalScrollBar,
294: constraint, getComponentCount());
295:
296: if (verticalScrollBar instanceof SAbstractAdjustable) {
297: SAbstractAdjustable scrollbar = (SAbstractAdjustable) verticalScrollBar;
298: if (scrollbar.getOrientation() == SConstants.HORIZONTAL)
299: scrollbar.setModel(horizontalModel);
300: else
301: scrollbar.setModel(verticalModel);
302: }
303:
304: adoptScrollBarVisibility(verticalScrollBar,
305: verticalScrollBarPolicy);
306: }
307:
308: reload();
309: }
310:
311: /**
312: * Returns the vertical scroll bar policy value.
313: *
314: * @return the vertical scrollbar policy.
315: * @see #setVerticalScrollBarPolicy(int)
316: */
317: public final int getVerticalScrollBarPolicy() {
318: return verticalScrollBarPolicy;
319: }
320:
321: /**
322: * Determines when the horizontal scrollbar appears in the scrollpane.
323: * The options are:
324: * <li><code>SScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED</code></li>
325: * <li><code>SScrollPane.HORIZONTAL_SCROLLBAR_NEVER</code></li>
326: * <li><code>SScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS</code></li>
327: */
328: public void setHorizontalScrollBarPolicy(int policy) {
329: if (policy != horizontalScrollBarPolicy) {
330: horizontalScrollBarPolicy = policy;
331: adoptScrollBarVisibility(horizontalScrollBar, policy);
332: reload();
333: }
334: }
335:
336: /**
337: * Determines when the vertical scrollbar appears in the scrollpane.
338: * The options are:
339: * <li><code>SScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED</code></li>
340: * <li><code>SScrollPane.VERTICAL_SCROLLBAR_NEVER</code></li>
341: * <li><code>SScrollPane.VERTICAL_SCROLLBAR_ALWAYS</code></li>
342: */
343: public void setVerticalScrollBarPolicy(int policy) {
344: if (policy != verticalScrollBarPolicy) {
345: verticalScrollBarPolicy = policy;
346: adoptScrollBarVisibility(verticalScrollBar, policy);
347: reload();
348: }
349: }
350:
351: public void setHorizontalExtent(int horizontalExtent) {
352: reloadIfChange(this .horizontalExtent, horizontalExtent);
353: this .horizontalExtent = horizontalExtent;
354: horizontalModel.setExtent(horizontalExtent);
355: }
356:
357: public final int getHorizontalExtent() {
358: return horizontalExtent;
359: }
360:
361: public void setVerticalExtent(int verticalExtent) {
362: reloadIfChange(this .verticalExtent, verticalExtent);
363: this .verticalExtent = verticalExtent;
364: verticalModel.setExtent(verticalExtent);
365: }
366:
367: public final int getVerticalExtent() {
368: return verticalExtent;
369: }
370:
371: public void scrollRectToVisible(Rectangle aRect) {
372: Rectangle viewport = scrollable.getScrollableViewportSize();
373:
374: // This should never happen. If it happen we got a serious
375: // problem, because we cannot determine what to scroll...
376: if (viewport == null) {
377: return;
378: }
379:
380: Adjustable hbar = getHorizontalScrollBar();
381: if (hbar != null
382: && getHorizontalScrollBarPolicy() != HORIZONTAL_SCROLLBAR_NEVER) {
383: int nval = scrollValue(hbar.getValue(),
384: getHorizontalExtent(), aRect.x, aRect.width, hbar
385: .getUnitIncrement());
386: if (nval != hbar.getValue()) {
387: hbar.setValue(nval);
388: }
389: }
390:
391: Adjustable vbar = getVerticalScrollBar();
392: if (vbar != null
393: && getVerticalScrollBarPolicy() != VERTICAL_SCROLLBAR_NEVER) {
394: int nval = scrollValue(vbar.getValue(),
395: getVerticalExtent(), aRect.y, aRect.height, vbar
396: .getUnitIncrement());
397: if (nval != vbar.getValue()) {
398: vbar.setValue(nval);
399: }
400: }
401: }
402:
403: /**
404: * Calculate the best new position to show the given range.
405: *
406: * @param pos the current position
407: * @param size the current visible amount
408: * @param rpos the start-position of the range to expose
409: * @param rsize the size of the range to expose
410: * @param inc the unit-increment to advance pos
411: * @return pos the new position
412: */
413: protected int scrollValue(int pos, int size, int rpos, int rsize,
414: int inc) {
415: if (pos <= rpos && (pos + size) >= (rpos + rsize)) {
416: // nothing to do
417: return pos;
418: }
419:
420: if (pos > rpos) {
421: // scroll backward - ignore rsize, either it fits or it doesn't,
422: // just make sure the difference between pos and rpos is as
423: // small as possible.
424: while (pos > rpos) {
425: pos -= inc;
426: }
427: } else {
428: // scroll forward
429: while ((pos + size) < (rpos + rsize) && (pos + inc) <= rpos) {
430: pos += inc;
431: }
432: }
433: return pos;
434: }
435:
436: private void setInitialViewportSize() {
437: if (scrollable == null)
438: return;
439:
440: if (mode == MODE_COMPLETE) {
441: scrollable.setViewportSize(scrollable
442: .getScrollableViewportSize());
443: } else {
444: scrollable.setViewportSize(new Rectangle(0, 0,
445: horizontalExtent, verticalExtent));
446: adoptScrollBarVisibility(horizontalScrollBar,
447: horizontalScrollBarPolicy);
448: adoptScrollBarVisibility(verticalScrollBar,
449: verticalScrollBarPolicy);
450: }
451: }
452:
453: protected void adoptScrollBarVisibility(Adjustable scrollbar,
454: int policy) {
455: if (scrollbar != null && scrollable != null) {
456: Rectangle maxVp = scrollable.getScrollableViewportSize();
457: Rectangle curVp = scrollable.getViewportSize();
458: if (maxVp != null && curVp != null) {
459: boolean newVisibility;
460: if (scrollbar.getOrientation() == SConstants.HORIZONTAL) {
461: newVisibility = isScrollBarVisible(policy,
462: maxVp.width, curVp.width);
463: } else {
464: newVisibility = isScrollBarVisible(policy,
465: maxVp.height, curVp.height);
466: }
467: ((SComponent) scrollbar).setVisible(newVisibility);
468: }
469: }
470: }
471:
472: private boolean isScrollBarVisible(int policy, int maxRecords,
473: int maxDisplayed) {
474: return isPolicyAlways(policy)
475: || (isPolicyAsNeeded(policy) && maxRecords > maxDisplayed);
476: }
477:
478: private boolean isPolicyAlways(int policy) {
479: return policy == HORIZONTAL_SCROLLBAR_ALWAYS
480: || policy == VERTICAL_SCROLLBAR_ALWAYS;
481: }
482:
483: private boolean isPolicyAsNeeded(int policy) {
484: return policy == HORIZONTAL_SCROLLBAR_AS_NEEDED
485: || policy == VERTICAL_SCROLLBAR_AS_NEEDED;
486: }
487:
488: /**
489: * A model synchronizing the scrollbar settings with the viewport of the given scrollable.
490: */
491: class SViewportSynchronizationModel implements SBoundedRangeModel,
492: SViewportChangeListener {
493:
494: private boolean horizontal;
495: private Scrollable scrollable;
496: private boolean isAdjusting = false;
497: private boolean delayEvents = false;
498:
499: /**
500: * Indicates if we have got a delayed Event
501: */
502: protected boolean gotDelayedEvent = false;
503:
504: /**
505: * Only one <code>ChangeEvent</code> is needed per model instance
506: * since the event's only (read-only) state is the source property.
507: */
508: protected transient ChangeEvent changeEvent = null;
509:
510: /**
511: * The listeners waiting for model or viewport changes respectively.
512: */
513: protected EventListenerList listenerList = new EventListenerList();
514:
515: /**
516: * Constructs a SViewportSynchronizationModel for either a horizontal or
517: * vertical scrollbar that has to be synchronized with the scrollable.
518: */
519: public SViewportSynchronizationModel(boolean horizontal) {
520: this .horizontal = horizontal;
521: }
522:
523: public Scrollable getScrollable() {
524: return scrollable;
525: }
526:
527: public void setScrollable(Scrollable scrollable) {
528: if (this .scrollable != null)
529: this .scrollable.removeViewportChangeListener(this );
530:
531: this .scrollable = scrollable;
532:
533: if (this .scrollable != null)
534: this .scrollable.addViewportChangeListener(this );
535: }
536:
537: public int getValue() {
538: if (!isViewportAvailable())
539: return 0;
540: Rectangle curVp = scrollable.getViewportSize();
541:
542: if (horizontal)
543: return curVp.x;
544: else
545: return curVp.y;
546: }
547:
548: public void setValue(int newValue) {
549: if (!isViewportAvailable())
550: return;
551: Rectangle curVp = scrollable.getViewportSize();
552: Rectangle maxVp = scrollable.getScrollableViewportSize();
553:
554: Rectangle newVp = (Rectangle) curVp.clone();
555:
556: if (horizontal) {
557: // Check range in order to prevent unnecessary update of views.
558: // This is primarily useful to prevent reloads in case the user
559: // wants to scroll further left/right than it's actually possible.
560: newValue = Math
561: .min(maxVp.width - curVp.width, newValue);
562: newValue = Math.max(0, newValue);
563: if (curVp.x != newValue) {
564: newVp.x = newValue;
565: updateViews(newVp);
566: }
567: } else {
568: // Check range in order to prevent unnecessary update of views.
569: // This is primarily useful to prevent reloads in case the user
570: // wants to scroll further up/down than it's actually possible.
571: newValue = Math.min(virtualViewportHeight
572: - curVp.height, newValue);
573: newValue = Math.max(0, newValue);
574: if (curVp.y != newValue) {
575: newVp.y = newValue;
576: updateViews(newVp);
577: }
578: }
579: }
580:
581: public int getExtent() {
582: if (!isViewportAvailable())
583: return 10;
584: Rectangle curVp = scrollable.getViewportSize();
585:
586: if (horizontal)
587: return curVp.width;
588: else
589: return curVp.height;
590: }
591:
592: public void setExtent(int newExtent) {
593: if (!isViewportAvailable())
594: return;
595: Rectangle curVp = scrollable.getViewportSize();
596:
597: Rectangle newVp = (Rectangle) curVp.clone();
598:
599: if (horizontal && curVp.width != newExtent) {
600: // Keep extent in sync with scrollpane
601: if (horizontalExtent != newExtent) {
602: horizontalExtent = newExtent;
603: SScrollPane.this .reload();
604: }
605: newVp.width = newExtent;
606: updateViews(newVp);
607: } else if (curVp.height != newExtent) {
608: // Keep extent in sync with scrollpane
609: if (verticalExtent != newExtent) {
610: verticalExtent = newExtent;
611: SScrollPane.this .reload();
612: }
613: newVp.height = newExtent;
614: updateViews(newVp);
615: }
616: }
617:
618: public int getMinimum() {
619: return 0;
620: }
621:
622: public void setMinimum(int newMinimum) {
623: // minimum should always be zero
624: }
625:
626: public int getMaximum() {
627: if (!isScrollableViewportAvailable())
628: return 100;
629: Rectangle maxVp = scrollable.getScrollableViewportSize();
630:
631: // The horizontal maximum should never be greater than the
632: // number of available columns in the scrollable's model.
633: // In contrast, the vertical maximum CAN be greater than the
634: // number of available rows in the scrollable's model, i.e.
635: // if this scrollpane's vertical extent was set to something
636: // greater than the number of available rows. In such cases
637: // the scrollable's CG fills the difference with empty lines.
638: if (horizontal)
639: return maxVp.width;
640: else
641: return virtualViewportHeight;
642: }
643:
644: public void setMaximum(int newMaximum) {
645: if (!isScrollableViewportAvailable())
646: return;
647: Rectangle maxVp = scrollable.getScrollableViewportSize();
648:
649: if (horizontal && maxVp.width != newMaximum) {
650: maxVp.width = newMaximum;
651: updateViews();
652: } else if (maxVp.height != newMaximum) {
653: maxVp.height = newMaximum;
654: updateViews();
655: }
656: }
657:
658: public boolean getValueIsAdjusting() {
659: return isAdjusting;
660: }
661:
662: public void setValueIsAdjusting(boolean b) {
663: isAdjusting = b;
664: }
665:
666: public void setRangeProperties(int value, int extent, int min,
667: int max, boolean adjusting) {
668: setValue(value);
669: setExtent(extent);
670: setMaximum(max);
671: setValueIsAdjusting(adjusting);
672: }
673:
674: public boolean getDelayEvents() {
675: return delayEvents;
676: }
677:
678: public void setDelayEvents(boolean b) {
679: delayEvents = b;
680: }
681:
682: public void fireDelayedIntermediateEvents() {
683: // there are no intermediate events to fire
684: }
685:
686: public void fireDelayedFinalEvents() {
687: if (!delayEvents && gotDelayedEvent) {
688: // Reloads scrollbar
689: fireStateChanged();
690: gotDelayedEvent = false;
691: }
692: }
693:
694: public void viewportChanged(SViewportChangeEvent e) {
695: if (mode == MODE_COMPLETE) {
696: // In this mode we don't have to do anything special like adjusting
697: // values or printing empty lines. We always want so see everything
698: // - not more and not less!
699: scrollable.setViewportSize(scrollable
700: .getScrollableViewportSize());
701: } else if (horizontal == e.isHorizontalChange()) {
702: // If the event was for THIS and not the other model ...
703: Rectangle maxVp = scrollable
704: .getScrollableViewportSize();
705: Rectangle curVp = scrollable.getViewportSize();
706:
707: if (maxVp != null && curVp != null) {
708:
709: SComponent scrollbar;
710: boolean newVisibility;
711:
712: if (horizontal) {
713: // Do not show more than we want or more than we have.
714: curVp.width = Math.min(horizontalExtent,
715: maxVp.width);
716:
717: // Check range! This is primarily useful to prevent the
718: // indices in the CGs to be out of bounds. An application
719: // developer might accidentally set such a wrong viewport.
720: curVp.x = Math.min(maxVp.width - curVp.width,
721: curVp.x);
722: curVp.x = Math.max(0, curVp.x);
723:
724: // Determine the new visibility of the horizontal scrollbar
725: scrollbar = (SComponent) horizontalScrollBar;
726: newVisibility = isScrollBarVisible(
727: horizontalScrollBarPolicy, maxVp.width,
728: curVp.width);
729: } else {
730: // Set the "virtualViewportHeight"
731: if (mode == MODE_PAGING) {
732: // Determine the number of empty cells that are needed in order to fill the last page
733: int emptyCells = (verticalExtent - (maxVp.height % verticalExtent))
734: % verticalExtent;
735: virtualViewportHeight = maxVp.height
736: + emptyCells;
737: } else
738: virtualViewportHeight = Math.max(
739: verticalExtent, maxVp.height);
740:
741: // Check range! This is primarily useful to prevent the
742: // indices in the CGs to be out of bounds. An application
743: // developer might accidentally set such a wrong viewport.
744: curVp.y = Math.min(virtualViewportHeight
745: - curVp.height, curVp.y);
746: curVp.y = Math.max(0, curVp.y);
747:
748: // Determine the new visibility of the vertical scrollbar
749: scrollbar = (SComponent) verticalScrollBar;
750: newVisibility = isScrollBarVisible(
751: verticalScrollBarPolicy, maxVp.height,
752: curVp.height);
753: }
754:
755: if (scrollbar != null) {
756: // Prevent the scrollbar(s) from an unnecessary reload
757: if (!scrollbar.isVisible()
758: && newVisibility == false) {
759: return;
760: }
761: // Apply the scrollbar's new visibility
762: scrollbar.setVisible(newVisibility);
763: }
764:
765: if (delayEvents) {
766: gotDelayedEvent = true;
767: } else {
768: // Reloads scrollbar
769: fireStateChanged();
770: }
771: }
772: }
773: }
774:
775: /**
776: * Adds a <code>ChangeListener</code>.
777: *
778: * @param l the <code>ChangeListener</code> to add
779: * @see #removeChangeListener
780: * @see BoundedRangeModel#addChangeListener
781: */
782: public void addChangeListener(ChangeListener l) {
783: listenerList.add(ChangeListener.class, l);
784: }
785:
786: /**
787: * Removes a <code>ChangeListener</code>.
788: *
789: * @param l the <code>ChangeListener</code> to remove
790: * @see #addChangeListener
791: * @see BoundedRangeModel#removeChangeListener
792: */
793: public void removeChangeListener(ChangeListener l) {
794: listenerList.remove(ChangeListener.class, l);
795: }
796:
797: /**
798: * Runs each <code>ChangeListener</code>'s <code>stateChanged</code> method.
799: *
800: * @see #setRangeProperties
801: * @see EventListenerList
802: */
803: protected void fireStateChanged() {
804: Object[] listeners = listenerList.getListenerList();
805: for (int i = listeners.length - 2; i >= 0; i -= 2) {
806: if (listeners[i] == ChangeListener.class) {
807: if (changeEvent == null) {
808: changeEvent = new ChangeEvent(scrollable);
809: }
810: ((ChangeListener) listeners[i + 1])
811: .stateChanged(changeEvent);
812: }
813: }
814: }
815:
816: private void updateViews(Rectangle newVp) {
817: // Reload scrollbar and scrollable in order to display the changes
818: viewportChanged(new SViewportChangeEvent(scrollable,
819: horizontal));
820: //((SComponent) scrollable).reload();
821: scrollable.setViewportSize(newVp);
822: }
823:
824: private void updateViews() {
825: // Reload scrollbar and scrollable in order to display the changes
826: viewportChanged(new SViewportChangeEvent(scrollable,
827: horizontal));
828: ((SComponent) scrollable).reload();
829: }
830:
831: private boolean isViewportAvailable() {
832: return scrollable != null
833: && scrollable.getViewportSize() != null;
834: }
835:
836: private boolean isScrollableViewportAvailable() {
837: return scrollable != null
838: && scrollable.getScrollableViewportSize() != null;
839: }
840: }
841: }
|