001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Anton Avtamonov
019: * @version $Revision$
020: */package org.apache.harmony.x.swing;
021:
022: import java.awt.Component;
023: import java.awt.Container;
024: import java.awt.EventQueue;
025: import java.awt.Graphics;
026: import java.awt.Point;
027: import java.awt.Rectangle;
028: import java.awt.Shape;
029:
030: import javax.swing.JComponent;
031: import javax.swing.RepaintManager;
032:
033: import org.apache.harmony.awt.ComponentInternals;
034: import org.apache.harmony.awt.gl.MultiRectArea;
035:
036: import org.apache.harmony.x.swing.internal.nls.Messages;
037:
038: /**
039: * Blit engine which allows to 'repaint' moving components using Graphics.copyArea() (blitting mode).
040: * To use this class a component and its parent should be JComponent.
041: * Parent can be dynamically changed which causes blitting reset.
042: */
043: public class BlitSupport {
044: private JComponent blitingComponent;
045: private JComponent parent;
046: private boolean wasPainted;
047: private Point lastPaintPosition;
048: private Rectangle lastPaintedRect;
049:
050: /**
051: * Constructs BlitSupport with no component set.
052: * In this case component must be set before first call to {@link #paint()} method.
053: */
054: public BlitSupport() {
055: }
056:
057: /**
058: * Constructs BlitSupport for the specified component.
059: * @param c JComponent which drag-related repaints should be optimized
060: */
061: public BlitSupport(final JComponent c) {
062: setBlitComponent(c);
063: }
064:
065: /**
066: * Sets blitting component.
067: * @param c JComponent which drag-related repaints shoudl be optimized
068: */
069: public void setBlitComponent(final JComponent c) {
070: blitingComponent = c;
071: parent = null;
072: resetBlitting();
073: }
074:
075: /**
076: * Should be called from the place where component position was changed and optimized repainting is required.
077: * Note that if optimized repainting was not called or failed (returned false) the 'normal' repainting will occur automatically.
078: * Method must be called from the event-dispatching thread.
079: *
080: * @return <code>true</code> if optimized repainting was successful, <code>false</code> otherwise
081: */
082: public boolean paint() {
083: if (!EventQueue.isDispatchThread()) {
084: return false;
085: }
086:
087: if (!initialize()) {
088: return false;
089: }
090:
091: if (lastPaintedRect == null || lastPaintedRect.isEmpty()) {
092: return false;
093: }
094:
095: Rectangle parentBounds = parent.getVisibleRect();
096:
097: Graphics g = parent.getGraphics();
098: if (g == null) {
099: resetBlitting();
100: return false;
101: }
102:
103: Point currentLocation = blitingComponent.getLocation();
104: Rectangle visibleBounds = getVisibleBounds();
105:
106: int dx = currentLocation.x - lastPaintPosition.x;
107: int dy = currentLocation.y - lastPaintPosition.y;
108:
109: Rectangle copyRect = new Rectangle(lastPaintedRect);
110: copyRect.translate(dx, dy);
111: if (!parentBounds.intersects(copyRect)) {
112: resetBlitting();
113: return false;
114: }
115:
116: Rectangle adjustedCopyRect = copyRect
117: .intersection(parentBounds);
118: if (isObscured(adjustedCopyRect.x - dx,
119: adjustedCopyRect.y - dy, adjustedCopyRect.width,
120: adjustedCopyRect.height)) {
121: return false;
122: }
123:
124: RepaintManager.currentManager(blitingComponent)
125: .markCompletelyClean(blitingComponent);
126: RepaintManager.currentManager(blitingComponent)
127: .markCompletelyClean(parent);
128:
129: g
130: .copyArea(adjustedCopyRect.x - dx, adjustedCopyRect.y
131: - dy, adjustedCopyRect.width,
132: adjustedCopyRect.height, dx, dy);
133:
134: wasPainted = false;
135: MultiRectArea affectedArea = new MultiRectArea(visibleBounds);
136: affectedArea.add(lastPaintedRect);
137: affectedArea.substract(adjustedCopyRect);
138: if (!affectedArea.isEmpty()) {
139: Shape oldClip = g.getClip();
140:
141: g.setClip(affectedArea);
142: parent.paint(g);
143:
144: g.setClip(oldClip);
145: }
146: if (!wasPainted) {
147: onPaint();
148: }
149: g.dispose();
150:
151: return true;
152: }
153:
154: /**
155: * Must be called from Component.paint() or related method to synchromize
156: * 'normal' and optimized paints. Method must be called from
157: * the event-dispatching thread.
158: *
159: */
160: public void onPaint() {
161: initialize();
162:
163: if (!EventQueue.isDispatchThread()) {
164: return;
165: }
166:
167: lastPaintPosition = blitingComponent.getLocation();
168: lastPaintedRect = getVisibleBounds();
169: wasPainted = true;
170: }
171:
172: private Rectangle getVisibleBounds() {
173: Rectangle result = blitingComponent.getVisibleRect();
174: result.translate(blitingComponent.getX(), blitingComponent
175: .getY());
176:
177: return result;
178: }
179:
180: private boolean initialize() {
181: if (blitingComponent == null) {
182: throw new IllegalStateException(Messages
183: .getString("swing.71")); //$NON-NLS-1$
184: }
185:
186: if (parent == null) {
187: Container blitParent = blitingComponent.getParent();
188: if (!(blitParent instanceof JComponent)) {
189: return false;
190: }
191:
192: parent = (JComponent) blitParent;
193: }
194:
195: return true;
196: }
197:
198: private boolean isObscured(final int x, final int y,
199: final int width, final int height) {
200: ComponentInternals ci = ComponentInternals
201: .getComponentInternals();
202: MultiRectArea obscuredArea = ci.getObscuredRegion(parent);
203: ci.addObscuredRegions(obscuredArea, blitingComponent, parent);
204: if (obscuredArea == null || obscuredArea.isEmpty()) {
205: return false;
206: }
207: return obscuredArea.intersects(x, y, width, height);
208: }
209:
210: private void resetBlitting() {
211: wasPainted = false;
212: lastPaintPosition = null;
213: lastPaintedRect = null;
214: }
215: }
|