JViewport.java 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  1. /* JViewport.java --
  2. Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. 02110-1301 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package javax.swing;
  32. import gnu.classpath.SystemProperties;
  33. import java.awt.Component;
  34. import java.awt.Dimension;
  35. import java.awt.Graphics;
  36. import java.awt.Image;
  37. import java.awt.Insets;
  38. import java.awt.LayoutManager;
  39. import java.awt.Point;
  40. import java.awt.Rectangle;
  41. import java.awt.Shape;
  42. import java.awt.event.ComponentAdapter;
  43. import java.awt.event.ComponentEvent;
  44. import java.io.Serializable;
  45. import javax.accessibility.Accessible;
  46. import javax.accessibility.AccessibleContext;
  47. import javax.accessibility.AccessibleRole;
  48. import javax.swing.border.Border;
  49. import javax.swing.event.ChangeEvent;
  50. import javax.swing.event.ChangeListener;
  51. import javax.swing.plaf.ViewportUI;
  52. /**
  53. *
  54. * <pre>
  55. * _
  56. * +-------------------------------+ ...........Y1 \
  57. * | view | . \
  58. * | (this component's child) | . > VY
  59. * | | . / = Y2-Y1
  60. * | +------------------------------+ ....Y2_/
  61. * | | viewport | | .
  62. * | | (this component) | | .
  63. * | | | | .
  64. * | | | | .
  65. * | | | | .
  66. * | | | | .
  67. * | +------------------------------+ ....Y3
  68. * | | .
  69. * | . | . .
  70. * | . | . .
  71. * +---------.---------------------+ ...........Y4
  72. * . . . .
  73. * . . . .
  74. * . . . .
  75. * X1.......X2.....................X3.......X4
  76. * \____ ___/
  77. * \/
  78. * VX = X2-X1
  79. *</pre>
  80. *
  81. * <p>A viewport is, like all swing components, located at some position in
  82. * the swing component tree; that location is exactly the same as any other
  83. * components: the viewport's "bounds".</p>
  84. *
  85. * <p>But in terms of drawing its child, the viewport thinks of itself as
  86. * covering a particular position <em>of the view's coordinate space</em>.
  87. * For example, the {@link #getViewPosition} method returns
  88. * the position <code>(VX,VY)</code> shown above, which is an position in
  89. * "view space", even though this is <em>implemented</em> by positioning
  90. * the underlying child at position <code>(-VX,-VY)</code></p>
  91. *
  92. */
  93. public class JViewport extends JComponent implements Accessible
  94. {
  95. /**
  96. * Provides accessibility support for <code>JViewport</code>.
  97. *
  98. * @author Roman Kennke (roman@kennke.org)
  99. */
  100. protected class AccessibleJViewport extends AccessibleJComponent
  101. {
  102. /**
  103. * Creates a new instance of <code>AccessibleJViewport</code>.
  104. */
  105. protected AccessibleJViewport()
  106. {
  107. // Nothing to do here.
  108. }
  109. /**
  110. * Returns the accessible role of <code>JViewport</code>, which is
  111. * {@link AccessibleRole#VIEWPORT}.
  112. *
  113. * @return the accessible role of <code>JViewport</code>
  114. */
  115. public AccessibleRole getAccessibleRole()
  116. {
  117. return AccessibleRole.VIEWPORT;
  118. }
  119. }
  120. /**
  121. * A {@link java.awt.event.ComponentListener} that listens for
  122. * changes of the view's size. This triggers a revalidate() call on the
  123. * viewport.
  124. */
  125. protected class ViewListener extends ComponentAdapter implements Serializable
  126. {
  127. private static final long serialVersionUID = -2812489404285958070L;
  128. /**
  129. * Creates a new instance of ViewListener.
  130. */
  131. protected ViewListener()
  132. {
  133. // Nothing to do here.
  134. }
  135. /**
  136. * Receives notification when a component (in this case: the view
  137. * component) changes it's size. This simply triggers a revalidate() on the
  138. * viewport.
  139. *
  140. * @param ev the ComponentEvent describing the change
  141. */
  142. public void componentResized(ComponentEvent ev)
  143. {
  144. // Fire state change, because resizing the view means changing the
  145. // extentSize.
  146. fireStateChanged();
  147. revalidate();
  148. }
  149. }
  150. public static final int SIMPLE_SCROLL_MODE = 0;
  151. public static final int BLIT_SCROLL_MODE = 1;
  152. public static final int BACKINGSTORE_SCROLL_MODE = 2;
  153. private static final long serialVersionUID = -6925142919680527970L;
  154. /**
  155. * The default scrollmode to be used by all JViewports as determined by
  156. * the system property gnu.javax.swing.JViewport.scrollMode.
  157. */
  158. private static final int defaultScrollMode;
  159. protected boolean scrollUnderway;
  160. protected boolean isViewSizeSet;
  161. /**
  162. * This flag indicates whether we use a backing store for drawing.
  163. *
  164. * @deprecated since JDK 1.3
  165. */
  166. protected boolean backingStore;
  167. /**
  168. * The backingstore image used for the backingstore and blit scroll methods.
  169. */
  170. protected Image backingStoreImage;
  171. /**
  172. * The position at which the view has been drawn the last time. This is used
  173. * to determine the bittable area.
  174. */
  175. protected Point lastPaintPosition;
  176. ChangeEvent changeEvent = new ChangeEvent(this);
  177. int scrollMode;
  178. /**
  179. * The ViewListener instance.
  180. */
  181. ViewListener viewListener;
  182. /**
  183. * Stores the location from where to blit. This is a cached Point object used
  184. * in blitting calculations.
  185. */
  186. Point cachedBlitFrom;
  187. /**
  188. * Stores the location where to blit to. This is a cached Point object used
  189. * in blitting calculations.
  190. */
  191. Point cachedBlitTo;
  192. /**
  193. * Stores the width of the blitted area. This is a cached Dimension object
  194. * used in blitting calculations.
  195. */
  196. Dimension cachedBlitSize;
  197. /**
  198. * Stores the bounds of the area that needs to be repainted. This is a cached
  199. * Rectangle object used in blitting calculations.
  200. */
  201. Rectangle cachedBlitPaint;
  202. boolean damaged = true;
  203. /**
  204. * A flag indicating if the size of the viewport has changed since the
  205. * last repaint. This is used in double buffered painting to check if we
  206. * need a new double buffer, or can reuse the old one.
  207. */
  208. boolean sizeChanged = true;
  209. /**
  210. * Indicates if this JViewport is the paint root or not. If it is not, then
  211. * we may not assume that the offscreen buffer still has the right content
  212. * because parent components may have cleared the background already.
  213. */
  214. private boolean isPaintRoot = false;
  215. /**
  216. * Initializes the default setting for the scrollMode property.
  217. */
  218. static
  219. {
  220. String scrollModeProp =
  221. SystemProperties.getProperty("gnu.swing.scrollmode", "BACKINGSTORE");
  222. if (scrollModeProp.equalsIgnoreCase("simple"))
  223. defaultScrollMode = SIMPLE_SCROLL_MODE;
  224. else if (scrollModeProp.equalsIgnoreCase("backingstore"))
  225. defaultScrollMode = BACKINGSTORE_SCROLL_MODE;
  226. else
  227. defaultScrollMode = BLIT_SCROLL_MODE;
  228. }
  229. public JViewport()
  230. {
  231. setOpaque(true);
  232. setScrollMode(defaultScrollMode);
  233. updateUI();
  234. setLayout(createLayoutManager());
  235. lastPaintPosition = new Point();
  236. cachedBlitFrom = new Point();
  237. cachedBlitTo = new Point();
  238. cachedBlitSize = new Dimension();
  239. cachedBlitPaint = new Rectangle();
  240. }
  241. public Dimension getExtentSize()
  242. {
  243. return getSize();
  244. }
  245. public Dimension toViewCoordinates(Dimension size)
  246. {
  247. return size;
  248. }
  249. public Point toViewCoordinates(Point p)
  250. {
  251. Point pos = getViewPosition();
  252. return new Point(p.x + pos.x,
  253. p.y + pos.y);
  254. }
  255. public void setExtentSize(Dimension newSize)
  256. {
  257. Dimension oldExtent = getExtentSize();
  258. if (! newSize.equals(oldExtent))
  259. {
  260. setSize(newSize);
  261. fireStateChanged();
  262. }
  263. }
  264. /**
  265. * Returns the viewSize when set, or the preferred size of the set
  266. * Component view. If no viewSize and no Component view is set an
  267. * empty Dimension is returned.
  268. */
  269. public Dimension getViewSize()
  270. {
  271. Dimension size;
  272. Component view = getView();
  273. if (view != null)
  274. {
  275. if (isViewSizeSet)
  276. size = view.getSize();
  277. else
  278. size = view.getPreferredSize();
  279. }
  280. else
  281. size = new Dimension(0, 0);
  282. return size;
  283. }
  284. public void setViewSize(Dimension newSize)
  285. {
  286. Component view = getView();
  287. if (view != null)
  288. {
  289. if (! newSize.equals(view.getSize()))
  290. {
  291. scrollUnderway = false;
  292. view.setSize(newSize);
  293. isViewSizeSet = true;
  294. fireStateChanged();
  295. }
  296. }
  297. }
  298. /**
  299. * Get the viewport's position in view space. Despite confusing name,
  300. * this really does return the viewport's (0,0) position in view space,
  301. * not the view's position.
  302. */
  303. public Point getViewPosition()
  304. {
  305. Component view = getView();
  306. if (view == null)
  307. return new Point(0,0);
  308. else
  309. {
  310. Point p = view.getLocation();
  311. p.x = -p.x;
  312. p.y = -p.y;
  313. return p;
  314. }
  315. }
  316. public void setViewPosition(Point p)
  317. {
  318. Component view = getView();
  319. if (view != null && ! p.equals(getViewPosition()))
  320. {
  321. scrollUnderway = true;
  322. view.setLocation(-p.x, -p.y);
  323. fireStateChanged();
  324. }
  325. }
  326. public Rectangle getViewRect()
  327. {
  328. return new Rectangle(getViewPosition(), getExtentSize());
  329. }
  330. /**
  331. * @deprecated 1.4
  332. */
  333. public boolean isBackingStoreEnabled()
  334. {
  335. return scrollMode == BACKINGSTORE_SCROLL_MODE;
  336. }
  337. /**
  338. * @deprecated 1.4
  339. */
  340. public void setBackingStoreEnabled(boolean b)
  341. {
  342. if (b && scrollMode != BACKINGSTORE_SCROLL_MODE)
  343. {
  344. scrollMode = BACKINGSTORE_SCROLL_MODE;
  345. fireStateChanged();
  346. }
  347. }
  348. public void setScrollMode(int mode)
  349. {
  350. scrollMode = mode;
  351. fireStateChanged();
  352. }
  353. public int getScrollMode()
  354. {
  355. return scrollMode;
  356. }
  357. public Component getView()
  358. {
  359. if (getComponentCount() == 0)
  360. return null;
  361. return getComponents()[0];
  362. }
  363. public void setView(Component v)
  364. {
  365. Component currView = getView();
  366. if (viewListener != null && currView != null)
  367. currView.removeComponentListener(viewListener);
  368. if (v != null)
  369. {
  370. if (viewListener == null)
  371. viewListener = createViewListener();
  372. v.addComponentListener(viewListener);
  373. add(v);
  374. fireStateChanged();
  375. }
  376. revalidate();
  377. repaint();
  378. }
  379. public void reshape(int x, int y, int w, int h)
  380. {
  381. if (w != getWidth() || h != getHeight())
  382. sizeChanged = true;
  383. super.reshape(x, y, w, h);
  384. if (sizeChanged)
  385. {
  386. damaged = true;
  387. fireStateChanged();
  388. }
  389. }
  390. public final Insets getInsets()
  391. {
  392. return new Insets(0, 0, 0, 0);
  393. }
  394. public final Insets getInsets(Insets insets)
  395. {
  396. if (insets == null)
  397. return getInsets();
  398. insets.top = 0;
  399. insets.bottom = 0;
  400. insets.left = 0;
  401. insets.right = 0;
  402. return insets;
  403. }
  404. /**
  405. * Overridden to return <code>false</code>, so the JViewport's paint method
  406. * gets called instead of directly calling the children. This is necessary
  407. * in order to get a useful clipping and translation on the children.
  408. *
  409. * @return <code>false</code>
  410. */
  411. public boolean isOptimizedDrawingEnabled()
  412. {
  413. return false;
  414. }
  415. public void paint(Graphics g)
  416. {
  417. Component view = getView();
  418. if (view == null)
  419. return;
  420. Rectangle viewBounds = view.getBounds();
  421. Rectangle portBounds = getBounds();
  422. if (viewBounds.width == 0
  423. || viewBounds.height == 0
  424. || portBounds.width == 0
  425. || portBounds.height == 0)
  426. return;
  427. switch (getScrollMode())
  428. {
  429. case JViewport.BACKINGSTORE_SCROLL_MODE:
  430. paintBackingStore(g);
  431. break;
  432. case JViewport.BLIT_SCROLL_MODE:
  433. paintBlit(g);
  434. break;
  435. case JViewport.SIMPLE_SCROLL_MODE:
  436. default:
  437. paintSimple(g);
  438. break;
  439. }
  440. damaged = false;
  441. }
  442. public void addChangeListener(ChangeListener listener)
  443. {
  444. listenerList.add(ChangeListener.class, listener);
  445. }
  446. public void removeChangeListener(ChangeListener listener)
  447. {
  448. listenerList.remove(ChangeListener.class, listener);
  449. }
  450. public ChangeListener[] getChangeListeners()
  451. {
  452. return (ChangeListener[]) getListeners(ChangeListener.class);
  453. }
  454. /**
  455. * This method returns the String ID of the UI class of Separator.
  456. *
  457. * @return The UI class' String ID.
  458. */
  459. public String getUIClassID()
  460. {
  461. return "ViewportUI";
  462. }
  463. /**
  464. * This method resets the UI used to the Look and Feel defaults..
  465. */
  466. public void updateUI()
  467. {
  468. setUI((ViewportUI) UIManager.getUI(this));
  469. }
  470. /**
  471. * This method returns the viewport's UI delegate.
  472. *
  473. * @return The viewport's UI delegate.
  474. */
  475. public ViewportUI getUI()
  476. {
  477. return (ViewportUI) ui;
  478. }
  479. /**
  480. * This method sets the viewport's UI delegate.
  481. *
  482. * @param ui The viewport's UI delegate.
  483. */
  484. public void setUI(ViewportUI ui)
  485. {
  486. super.setUI(ui);
  487. }
  488. public final void setBorder(Border border)
  489. {
  490. if (border != null)
  491. throw new IllegalArgumentException();
  492. }
  493. /**
  494. * Scrolls the view so that contentRect becomes visible.
  495. *
  496. * @param contentRect the rectangle to make visible within the view
  497. */
  498. public void scrollRectToVisible(Rectangle contentRect)
  499. {
  500. Component view = getView();
  501. if (view == null)
  502. return;
  503. Point pos = getViewPosition();
  504. // We get the contentRect in the viewport coordinates. But we want to
  505. // calculate with view coordinates.
  506. int contentX = contentRect.x + pos.x;
  507. int contentY = contentRect.y + pos.y;
  508. Rectangle viewBounds = getView().getBounds();
  509. Rectangle portBounds = getBounds();
  510. if (isShowing())
  511. getView().validate();
  512. // If the bottom boundary of contentRect is below the port
  513. // boundaries, scroll up as necessary.
  514. if (contentY + contentRect.height + viewBounds.y > portBounds.height)
  515. pos.y = contentY + contentRect.height - portBounds.height;
  516. // If contentY is above the port boundaries, scroll down to
  517. // contentY.
  518. if (contentY + viewBounds.y < 0)
  519. pos.y = contentY;
  520. // If the right boundary of contentRect is right from the port
  521. // boundaries, scroll left as necessary.
  522. if (contentX + contentRect.width + viewBounds.x > portBounds.width)
  523. pos.x = contentX + contentRect.width - portBounds.width;
  524. // If contentX is left from the port boundaries, scroll right to
  525. // contentRect.x.
  526. if (contentX + viewBounds.x < 0)
  527. pos.x = contentX;
  528. setViewPosition(pos);
  529. }
  530. /**
  531. * Returns the accessible context for this <code>JViewport</code>. This
  532. * will be an instance of {@link AccessibleJViewport}.
  533. *
  534. * @return the accessible context for this <code>JViewport</code>
  535. */
  536. public AccessibleContext getAccessibleContext()
  537. {
  538. if (accessibleContext == null)
  539. accessibleContext = new AccessibleJViewport();
  540. return accessibleContext;
  541. }
  542. /**
  543. * Forward repaint to parent to make sure only one paint is performed by the
  544. * RepaintManager.
  545. *
  546. * @param tm number of milliseconds to defer the repaint request
  547. * @param x the X coordinate of the upper left corner of the dirty area
  548. * @param y the Y coordinate of the upper left corner of the dirty area
  549. * @param w the width of the dirty area
  550. * @param h the height of the dirty area
  551. */
  552. public void repaint(long tm, int x, int y, int w, int h)
  553. {
  554. Component parent = getParent();
  555. if (parent != null)
  556. parent.repaint(tm, x + getX(), y + getY(), w, h);
  557. else
  558. super.repaint(tm, x, y, w, h);
  559. }
  560. protected void addImpl(Component comp, Object constraints, int index)
  561. {
  562. if (getComponentCount() > 0)
  563. remove(getComponents()[0]);
  564. super.addImpl(comp, constraints, index);
  565. }
  566. protected void fireStateChanged()
  567. {
  568. ChangeListener[] listeners = getChangeListeners();
  569. for (int i = 0; i < listeners.length; ++i)
  570. listeners[i].stateChanged(changeEvent);
  571. }
  572. /**
  573. * Creates a {@link ViewListener} that is supposed to listen for
  574. * size changes on the view component.
  575. *
  576. * @return a ViewListener instance
  577. */
  578. protected ViewListener createViewListener()
  579. {
  580. return new ViewListener();
  581. }
  582. /**
  583. * Creates the LayoutManager that is used for this viewport. Override
  584. * this method if you want to use a custom LayoutManager.
  585. *
  586. * @return a LayoutManager to use for this viewport
  587. */
  588. protected LayoutManager createLayoutManager()
  589. {
  590. return new ViewportLayout();
  591. }
  592. /**
  593. * Computes the parameters for the blitting scroll method. <code>dx</code>
  594. * and <code>dy</code> specifiy the X and Y offset by which the viewport
  595. * is scrolled. All other arguments are output parameters and are filled by
  596. * this method.
  597. *
  598. * <code>blitFrom</code> holds the position of the blit rectangle in the
  599. * viewport rectangle before scrolling, <code>blitTo</code> where the blitArea
  600. * is copied to.
  601. *
  602. * <code>blitSize</code> holds the size of the blit area and
  603. * <code>blitPaint</code> is the area of the view that needs to be painted.
  604. *
  605. * This method returns <code>true</code> if blitting is possible and
  606. * <code>false</code> if the viewport has to be repainted completetly without
  607. * blitting.
  608. *
  609. * @param dx the horizontal delta
  610. * @param dy the vertical delta
  611. * @param blitFrom the position from where to blit; set by this method
  612. * @param blitTo the position where to blit area is copied to; set by this
  613. * method
  614. * @param blitSize the size of the blitted area; set by this method
  615. * @param blitPaint the area that needs repainting; set by this method
  616. *
  617. * @return <code>true</code> if blitting is possible,
  618. * <code>false</code> otherwise
  619. */
  620. protected boolean computeBlit(int dx, int dy, Point blitFrom, Point blitTo,
  621. Dimension blitSize, Rectangle blitPaint)
  622. {
  623. if ((dx != 0 && dy != 0) || (dy == 0 && dy == 0) || damaged)
  624. // We cannot blit if the viewport is scrolled in both directions at
  625. // once. Also, we do not want to blit if the viewport is not scrolled at
  626. // all, because that probably means the view component repaints itself
  627. // and the buffer needs updating.
  628. return false;
  629. Rectangle portBounds = SwingUtilities.calculateInnerArea(this, getBounds());
  630. // Compute the blitFrom and blitTo parameters.
  631. blitFrom.x = portBounds.x;
  632. blitFrom.y = portBounds.y;
  633. blitTo.x = portBounds.x;
  634. blitTo.y = portBounds.y;
  635. if (dy > 0)
  636. {
  637. blitFrom.y = portBounds.y + dy;
  638. }
  639. else if (dy < 0)
  640. {
  641. blitTo.y = portBounds.y - dy;
  642. }
  643. else if (dx > 0)
  644. {
  645. blitFrom.x = portBounds.x + dx;
  646. }
  647. else if (dx < 0)
  648. {
  649. blitTo.x = portBounds.x - dx;
  650. }
  651. // Compute size of the blit area.
  652. if (dx != 0)
  653. {
  654. blitSize.width = portBounds.width - Math.abs(dx);
  655. blitSize.height = portBounds.height;
  656. }
  657. else if (dy != 0)
  658. {
  659. blitSize.width = portBounds.width;
  660. blitSize.height = portBounds.height - Math.abs(dy);
  661. }
  662. // Compute the blitPaint parameter.
  663. blitPaint.setBounds(portBounds);
  664. if (dy > 0)
  665. {
  666. blitPaint.y = portBounds.y + portBounds.height - dy;
  667. blitPaint.height = dy;
  668. }
  669. else if (dy < 0)
  670. {
  671. blitPaint.height = -dy;
  672. }
  673. if (dx > 0)
  674. {
  675. blitPaint.x = portBounds.x + portBounds.width - dx;
  676. blitPaint.width = dx;
  677. }
  678. else if (dx < 0)
  679. {
  680. blitPaint.width = -dx;
  681. }
  682. return true;
  683. }
  684. /**
  685. * Paints the viewport in case we have a scrollmode of
  686. * {@link #SIMPLE_SCROLL_MODE}.
  687. *
  688. * This simply paints the view directly on the surface of the viewport.
  689. *
  690. * @param g the graphics context to use
  691. */
  692. void paintSimple(Graphics g)
  693. {
  694. // We need to call this to properly clear the background.
  695. paintComponent(g);
  696. Point pos = getViewPosition();
  697. Component view = getView();
  698. Shape oldClip = g.getClip();
  699. g.clipRect(0, 0, getWidth(), getHeight());
  700. boolean translated = false;
  701. try
  702. {
  703. g.translate(-pos.x, -pos.y);
  704. translated = true;
  705. view.paint(g);
  706. }
  707. finally
  708. {
  709. if (translated)
  710. g.translate (pos.x, pos.y);
  711. g.setClip(oldClip);
  712. }
  713. }
  714. /**
  715. * Paints the viewport in case we have a scroll mode of
  716. * {@link #BACKINGSTORE_SCROLL_MODE}.
  717. *
  718. * This method uses a backing store image to paint the view to, which is then
  719. * subsequently painted on the screen. This should make scrolling more
  720. * smooth.
  721. *
  722. * @param g the graphics context to use
  723. */
  724. void paintBackingStore(Graphics g)
  725. {
  726. // If we have no backing store image yet or the size of the component has
  727. // changed, we need to rebuild the backing store.
  728. if (backingStoreImage == null || sizeChanged)
  729. {
  730. backingStoreImage = createImage(getWidth(), getHeight());
  731. sizeChanged = false;
  732. Graphics g2 = backingStoreImage.getGraphics();
  733. paintSimple(g2);
  734. g2.dispose();
  735. }
  736. // Otherwise we can perform the blitting on the backing store image:
  737. // First we move the part that remains visible after scrolling, then
  738. // we only need to paint the bit that becomes newly visible.
  739. else
  740. {
  741. Graphics g2 = backingStoreImage.getGraphics();
  742. Point viewPosition = getViewPosition();
  743. int dx = viewPosition.x - lastPaintPosition.x;
  744. int dy = viewPosition.y - lastPaintPosition.y;
  745. boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo,
  746. cachedBlitSize, cachedBlitPaint);
  747. if (canBlit && isPaintRoot)
  748. {
  749. // Copy the part that remains visible during scrolling.
  750. if (cachedBlitSize.width > 0 && cachedBlitSize.height > 0)
  751. {
  752. g2.copyArea(cachedBlitFrom.x, cachedBlitFrom.y,
  753. cachedBlitSize.width, cachedBlitSize.height,
  754. cachedBlitTo.x - cachedBlitFrom.x,
  755. cachedBlitTo.y - cachedBlitFrom.y);
  756. }
  757. // Now paint the part that becomes newly visible.
  758. g2.setClip(cachedBlitPaint.x, cachedBlitPaint.y,
  759. cachedBlitPaint.width, cachedBlitPaint.height);
  760. paintSimple(g2);
  761. }
  762. // If blitting is not possible for some reason, fall back to repainting
  763. // everything.
  764. else
  765. {
  766. // If the image has not been scrolled at all, only the changed
  767. // clip must be updated in the buffer.
  768. if (dx == 0 && dy == 0)
  769. g2.setClip(g.getClip());
  770. paintSimple(g2);
  771. }
  772. g2.dispose();
  773. }
  774. // Actually draw the backingstore image to the graphics context.
  775. g.drawImage(backingStoreImage, 0, 0, this);
  776. // Update the lastPaintPosition so that we know what is already drawn when
  777. // we paint the next time.
  778. lastPaintPosition.setLocation(getViewPosition());
  779. }
  780. /**
  781. * Paints the viewport in case we have a scrollmode of
  782. * {@link #BLIT_SCROLL_MODE}.
  783. *
  784. * This paints the viewport using a backingstore and a blitting algorithm.
  785. * Only the newly exposed area of the view is painted from the view painting
  786. * methods, the remainder is copied from the backing store.
  787. *
  788. * @param g the graphics context to use
  789. */
  790. void paintBlit(Graphics g)
  791. {
  792. // First we move the part that remains visible after scrolling, then
  793. // we only need to paint the bit that becomes newly visible.
  794. Point viewPosition = getViewPosition();
  795. int dx = viewPosition.x - lastPaintPosition.x;
  796. int dy = viewPosition.y - lastPaintPosition.y;
  797. boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo,
  798. cachedBlitSize, cachedBlitPaint);
  799. if (canBlit && isPaintRoot)
  800. {
  801. // Copy the part that remains visible during scrolling.
  802. if (cachedBlitSize.width > 0 && cachedBlitSize.width > 0)
  803. {
  804. g.copyArea(cachedBlitFrom.x, cachedBlitFrom.y,
  805. cachedBlitSize.width, cachedBlitSize.height,
  806. cachedBlitTo.x - cachedBlitFrom.x,
  807. cachedBlitTo.y - cachedBlitFrom.y);
  808. }
  809. // Now paint the part that becomes newly visible.
  810. Shape oldClip = g.getClip();
  811. g.clipRect(cachedBlitPaint.x, cachedBlitPaint.y,
  812. cachedBlitPaint.width, cachedBlitPaint.height);
  813. try
  814. {
  815. paintSimple(g);
  816. }
  817. finally
  818. {
  819. g.setClip(oldClip);
  820. }
  821. }
  822. // If blitting is not possible for some reason, fall back to repainting
  823. // everything.
  824. else
  825. paintSimple(g);
  826. lastPaintPosition.setLocation(getViewPosition());
  827. }
  828. /**
  829. * Overridden from JComponent to set the {@link #isPaintRoot} flag.
  830. *
  831. * @param x the rectangle to paint, X coordinate
  832. * @param y the rectangle to paint, Y coordinate
  833. * @param w the rectangle to paint, width
  834. * @param h the rectangle to paint, height
  835. */
  836. void paintImmediately2(int x, int y, int w, int h)
  837. {
  838. isPaintRoot = true;
  839. super.paintImmediately2(x, y, w, h);
  840. isPaintRoot = false;
  841. }
  842. /**
  843. * Returns true when the JViewport is using a backbuffer, so that we
  844. * can update our backbuffer correctly.
  845. */
  846. boolean isPaintRoot()
  847. {
  848. return scrollMode == BACKINGSTORE_SCROLL_MODE;
  849. }
  850. }