1:
37:
38:
39: package ;
40:
41: import ;
42:
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55:
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63:
64:
105: public class JViewport extends JComponent implements Accessible
106: {
107:
112: protected class AccessibleJViewport extends AccessibleJComponent
113: {
114:
117: protected AccessibleJViewport()
118: {
119:
120: }
121:
122:
128: public AccessibleRole getAccessibleRole()
129: {
130: return AccessibleRole.VIEWPORT;
131: }
132: }
133:
134:
139: protected class ViewListener extends ComponentAdapter implements Serializable
140: {
141: private static final long serialVersionUID = -2812489404285958070L;
142:
143:
146: protected ViewListener()
147: {
148:
149: }
150:
151:
158: public void componentResized(ComponentEvent ev)
159: {
160:
161:
162: fireStateChanged();
163: revalidate();
164: }
165: }
166:
167: public static final int SIMPLE_SCROLL_MODE = 0;
168: public static final int BLIT_SCROLL_MODE = 1;
169: public static final int BACKINGSTORE_SCROLL_MODE = 2;
170:
171: private static final long serialVersionUID = -6925142919680527970L;
172:
173:
177: private static final int defaultScrollMode;
178:
179: protected boolean scrollUnderway;
180: protected boolean isViewSizeSet;
181:
182:
187: protected boolean backingStore;
188:
189:
192: protected Image backingStoreImage;
193:
194:
198: protected Point lastPaintPosition;
199:
200: ChangeEvent changeEvent = new ChangeEvent(this);
201:
202: int scrollMode;
203:
204:
207: ViewListener viewListener;
208:
209:
213: Point cachedBlitFrom;
214:
215:
219: Point cachedBlitTo;
220:
221:
225: Dimension cachedBlitSize;
226:
227:
231: Rectangle cachedBlitPaint;
232:
233: boolean damaged = true;
234:
235:
240: boolean sizeChanged = true;
241:
242:
247: private boolean isPaintRoot = false;
248:
249:
252: static
253: {
254: String scrollModeProp =
255: SystemProperties.getProperty("gnu.swing.scrollmode", "BACKINGSTORE");
256: if (scrollModeProp.equalsIgnoreCase("simple"))
257: defaultScrollMode = SIMPLE_SCROLL_MODE;
258: else if (scrollModeProp.equalsIgnoreCase("backingstore"))
259: defaultScrollMode = BACKINGSTORE_SCROLL_MODE;
260: else
261: defaultScrollMode = BLIT_SCROLL_MODE;
262: }
263:
264: public JViewport()
265: {
266: setOpaque(true);
267: setScrollMode(defaultScrollMode);
268: updateUI();
269: setLayout(createLayoutManager());
270: lastPaintPosition = new Point();
271: cachedBlitFrom = new Point();
272: cachedBlitTo = new Point();
273: cachedBlitSize = new Dimension();
274: cachedBlitPaint = new Rectangle();
275: }
276:
277: public Dimension getExtentSize()
278: {
279: return getSize();
280: }
281:
282: public Dimension toViewCoordinates(Dimension size)
283: {
284: return size;
285: }
286:
287: public Point toViewCoordinates(Point p)
288: {
289: Point pos = getViewPosition();
290: return new Point(p.x + pos.x,
291: p.y + pos.y);
292: }
293:
294: public void setExtentSize(Dimension newSize)
295: {
296: Dimension oldExtent = getExtentSize();
297: if (! newSize.equals(oldExtent))
298: {
299: setSize(newSize);
300: fireStateChanged();
301: }
302: }
303:
304:
309: public Dimension getViewSize()
310: {
311: Dimension size;
312: Component view = getView();
313: if (view != null)
314: {
315: if (isViewSizeSet)
316: size = view.getSize();
317: else
318: size = view.getPreferredSize();
319: }
320: else
321: size = new Dimension(0, 0);
322: return size;
323: }
324:
325:
326: public void setViewSize(Dimension newSize)
327: {
328: Component view = getView();
329: if (view != null)
330: {
331: if (! newSize.equals(view.getSize()))
332: {
333: scrollUnderway = false;
334: view.setSize(newSize);
335: isViewSizeSet = true;
336: fireStateChanged();
337: }
338: }
339: }
340:
341:
346:
347: public Point getViewPosition()
348: {
349: Component view = getView();
350: if (view == null)
351: return new Point(0,0);
352: else
353: {
354: Point p = view.getLocation();
355: p.x = -p.x;
356: p.y = -p.y;
357: return p;
358: }
359: }
360:
361: public void setViewPosition(Point p)
362: {
363: Component view = getView();
364: if (view != null && ! p.equals(getViewPosition()))
365: {
366: scrollUnderway = true;
367: view.setLocation(-p.x, -p.y);
368: fireStateChanged();
369: }
370: }
371:
372: public Rectangle getViewRect()
373: {
374: return new Rectangle(getViewPosition(), getExtentSize());
375: }
376:
377:
380: public boolean isBackingStoreEnabled()
381: {
382: return scrollMode == BACKINGSTORE_SCROLL_MODE;
383: }
384:
385:
388: public void setBackingStoreEnabled(boolean b)
389: {
390: if (b && scrollMode != BACKINGSTORE_SCROLL_MODE)
391: {
392: scrollMode = BACKINGSTORE_SCROLL_MODE;
393: fireStateChanged();
394: }
395: }
396:
397: public void setScrollMode(int mode)
398: {
399: scrollMode = mode;
400: fireStateChanged();
401: }
402:
403: public int getScrollMode()
404: {
405: return scrollMode;
406: }
407:
408: public Component getView()
409: {
410: if (getComponentCount() == 0)
411: return null;
412:
413: return getComponents()[0];
414: }
415:
416: public void setView(Component v)
417: {
418: Component currView = getView();
419: if (viewListener != null && currView != null)
420: currView.removeComponentListener(viewListener);
421:
422: if (v != null)
423: {
424: if (viewListener == null)
425: viewListener = createViewListener();
426: v.addComponentListener(viewListener);
427: add(v);
428: fireStateChanged();
429: }
430: revalidate();
431: repaint();
432: }
433:
434: public void reshape(int x, int y, int w, int h)
435: {
436: if (w != getWidth() || h != getHeight())
437: sizeChanged = true;
438: super.reshape(x, y, w, h);
439: if (sizeChanged)
440: {
441: damaged = true;
442: fireStateChanged();
443: }
444: }
445:
446: public final Insets getInsets()
447: {
448: return new Insets(0, 0, 0, 0);
449: }
450:
451: public final Insets getInsets(Insets insets)
452: {
453: if (insets == null)
454: return getInsets();
455: insets.top = 0;
456: insets.bottom = 0;
457: insets.left = 0;
458: insets.right = 0;
459: return insets;
460: }
461:
462:
463:
470: public boolean isOptimizedDrawingEnabled()
471: {
472: return false;
473: }
474:
475: public void paint(Graphics g)
476: {
477: Component view = getView();
478:
479: if (view == null)
480: return;
481:
482: Rectangle viewBounds = view.getBounds();
483: Rectangle portBounds = getBounds();
484:
485: if (viewBounds.width == 0
486: || viewBounds.height == 0
487: || portBounds.width == 0
488: || portBounds.height == 0)
489: return;
490:
491: switch (getScrollMode())
492: {
493:
494: case JViewport.BACKINGSTORE_SCROLL_MODE:
495: paintBackingStore(g);
496: break;
497: case JViewport.BLIT_SCROLL_MODE:
498: paintBlit(g);
499: break;
500: case JViewport.SIMPLE_SCROLL_MODE:
501: default:
502: paintSimple(g);
503: break;
504: }
505: damaged = false;
506: }
507:
508: public void addChangeListener(ChangeListener listener)
509: {
510: listenerList.add(ChangeListener.class, listener);
511: }
512:
513: public void removeChangeListener(ChangeListener listener)
514: {
515: listenerList.remove(ChangeListener.class, listener);
516: }
517:
518: public ChangeListener[] getChangeListeners()
519: {
520: return (ChangeListener[]) getListeners(ChangeListener.class);
521: }
522:
523:
528: public String getUIClassID()
529: {
530: return "ViewportUI";
531: }
532:
533:
536: public void updateUI()
537: {
538: setUI((ViewportUI) UIManager.getUI(this));
539: }
540:
541:
546: public ViewportUI getUI()
547: {
548: return (ViewportUI) ui;
549: }
550:
551:
556: public void setUI(ViewportUI ui)
557: {
558: super.setUI(ui);
559: }
560:
561: public final void setBorder(Border border)
562: {
563: if (border != null)
564: throw new IllegalArgumentException();
565: }
566:
567:
572: public void scrollRectToVisible(Rectangle contentRect)
573: {
574: Component view = getView();
575: if (view == null)
576: return;
577:
578: Point pos = getViewPosition();
579:
580:
581: int contentX = contentRect.x + pos.x;
582: int contentY = contentRect.y + pos.y;
583: Rectangle viewBounds = getView().getBounds();
584: Rectangle portBounds = getBounds();
585:
586: if (isShowing())
587: getView().validate();
588:
589:
590:
591: if (contentY + contentRect.height + viewBounds.y > portBounds.height)
592: pos.y = contentY + contentRect.height - portBounds.height;
593:
594:
595: if (contentY + viewBounds.y < 0)
596: pos.y = contentY;
597:
598:
599: if (contentX + contentRect.width + viewBounds.x > portBounds.width)
600: pos.x = contentX + contentRect.width - portBounds.width;
601:
602:
603: if (contentX + viewBounds.x < 0)
604: pos.x = contentX;
605: setViewPosition(pos);
606: }
607:
608:
614: public AccessibleContext getAccessibleContext()
615: {
616: if (accessibleContext == null)
617: accessibleContext = new AccessibleJViewport();
618: return accessibleContext;
619: }
620:
621:
631: public void repaint(long tm, int x, int y, int w, int h)
632: {
633: Component parent = getParent();
634: if (parent != null)
635: parent.repaint(tm, x + getX(), y + getY(), w, h);
636: else
637: super.repaint(tm, x, y, w, h);
638: }
639:
640: protected void addImpl(Component comp, Object constraints, int index)
641: {
642: if (getComponentCount() > 0)
643: remove(getComponents()[0]);
644:
645: super.addImpl(comp, constraints, index);
646: }
647:
648: protected void fireStateChanged()
649: {
650: ChangeListener[] listeners = getChangeListeners();
651: for (int i = 0; i < listeners.length; ++i)
652: listeners[i].stateChanged(changeEvent);
653: }
654:
655:
661: protected ViewListener createViewListener()
662: {
663: return new ViewListener();
664: }
665:
666:
672: protected LayoutManager createLayoutManager()
673: {
674: return new ViewportLayout();
675: }
676:
677:
705: protected boolean computeBlit(int dx, int dy, Point blitFrom, Point blitTo,
706: Dimension blitSize, Rectangle blitPaint)
707: {
708: if ((dx != 0 && dy != 0) || (dy == 0 && dy == 0) || damaged)
709:
710:
711:
712:
713: return false;
714:
715: Rectangle portBounds = SwingUtilities.calculateInnerArea(this, getBounds());
716:
717:
718: blitFrom.x = portBounds.x;
719: blitFrom.y = portBounds.y;
720: blitTo.x = portBounds.x;
721: blitTo.y = portBounds.y;
722:
723: if (dy > 0)
724: {
725: blitFrom.y = portBounds.y + dy;
726: }
727: else if (dy < 0)
728: {
729: blitTo.y = portBounds.y - dy;
730: }
731: else if (dx > 0)
732: {
733: blitFrom.x = portBounds.x + dx;
734: }
735: else if (dx < 0)
736: {
737: blitTo.x = portBounds.x - dx;
738: }
739:
740:
741: if (dx != 0)
742: {
743: blitSize.width = portBounds.width - Math.abs(dx);
744: blitSize.height = portBounds.height;
745: }
746: else if (dy != 0)
747: {
748: blitSize.width = portBounds.width;
749: blitSize.height = portBounds.height - Math.abs(dy);
750: }
751:
752:
753: blitPaint.setBounds(portBounds);
754: if (dy > 0)
755: {
756: blitPaint.y = portBounds.y + portBounds.height - dy;
757: blitPaint.height = dy;
758: }
759: else if (dy < 0)
760: {
761: blitPaint.height = -dy;
762: }
763: if (dx > 0)
764: {
765: blitPaint.x = portBounds.x + portBounds.width - dx;
766: blitPaint.width = dx;
767: }
768: else if (dx < 0)
769: {
770: blitPaint.width = -dx;
771: }
772:
773: return true;
774: }
775:
776:
784: void paintSimple(Graphics g)
785: {
786:
787: paintComponent(g);
788:
789: Point pos = getViewPosition();
790: Component view = getView();
791: Shape oldClip = g.getClip();
792: g.clipRect(0, 0, getWidth(), getHeight());
793: boolean translated = false;
794: try
795: {
796: g.translate(-pos.x, -pos.y);
797: translated = true;
798: view.paint(g);
799: }
800: finally
801: {
802: if (translated)
803: g.translate (pos.x, pos.y);
804: g.setClip(oldClip);
805: }
806: }
807:
808:
818: void paintBackingStore(Graphics g)
819: {
820:
821:
822: if (backingStoreImage == null || sizeChanged)
823: {
824: backingStoreImage = createImage(getWidth(), getHeight());
825: sizeChanged = false;
826: Graphics g2 = backingStoreImage.getGraphics();
827: paintSimple(g2);
828: g2.dispose();
829: }
830:
831:
832:
833: else
834: {
835: Graphics g2 = backingStoreImage.getGraphics();
836: Point viewPosition = getViewPosition();
837: int dx = viewPosition.x - lastPaintPosition.x;
838: int dy = viewPosition.y - lastPaintPosition.y;
839: boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo,
840: cachedBlitSize, cachedBlitPaint);
841: if (canBlit && isPaintRoot)
842: {
843:
844: if (cachedBlitSize.width > 0 && cachedBlitSize.height > 0)
845: {
846: g2.copyArea(cachedBlitFrom.x, cachedBlitFrom.y,
847: cachedBlitSize.width, cachedBlitSize.height,
848: cachedBlitTo.x - cachedBlitFrom.x,
849: cachedBlitTo.y - cachedBlitFrom.y);
850: }
851:
852: g2.setClip(cachedBlitPaint.x, cachedBlitPaint.y,
853: cachedBlitPaint.width, cachedBlitPaint.height);
854: paintSimple(g2);
855: }
856:
857:
858: else
859: {
860:
861:
862: if (dx == 0 && dy == 0)
863: g2.setClip(g.getClip());
864:
865: paintSimple(g2);
866: }
867: g2.dispose();
868: }
869:
870: g.drawImage(backingStoreImage, 0, 0, this);
871:
872:
873: lastPaintPosition.setLocation(getViewPosition());
874: }
875:
876:
886: void paintBlit(Graphics g)
887: {
888:
889:
890: Point viewPosition = getViewPosition();
891: int dx = viewPosition.x - lastPaintPosition.x;
892: int dy = viewPosition.y - lastPaintPosition.y;
893: boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo,
894: cachedBlitSize, cachedBlitPaint);
895: if (canBlit && isPaintRoot)
896: {
897:
898: if (cachedBlitSize.width > 0 && cachedBlitSize.width > 0)
899: {
900: g.copyArea(cachedBlitFrom.x, cachedBlitFrom.y,
901: cachedBlitSize.width, cachedBlitSize.height,
902: cachedBlitTo.x - cachedBlitFrom.x,
903: cachedBlitTo.y - cachedBlitFrom.y);
904: }
905:
906: Shape oldClip = g.getClip();
907: g.clipRect(cachedBlitPaint.x, cachedBlitPaint.y,
908: cachedBlitPaint.width, cachedBlitPaint.height);
909: try
910: {
911: paintSimple(g);
912: }
913: finally
914: {
915: g.setClip(oldClip);
916: }
917: }
918:
919:
920: else
921: paintSimple(g);
922: lastPaintPosition.setLocation(getViewPosition());
923: }
924:
925:
933: void paintImmediately2(int x, int y, int w, int h)
934: {
935: isPaintRoot = true;
936: super.paintImmediately2(x, y, w, h);
937: isPaintRoot = false;
938: }
939:
940:
944: boolean isPaintRoot()
945: {
946: return scrollMode == BACKINGSTORE_SCROLL_MODE;
947: }
948: }