001 /**
002 * Copyright (c) 2009, Piet Blok
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without
006 * modification, are permitted provided that the following conditions
007 * are met:
008 *
009 * * Redistributions of source code must retain the above copyright
010 * notice, this list of conditions and the following disclaimer.
011 * * Redistributions in binary form must reproduce the above
012 * copyright notice, this list of conditions and the following
013 * disclaimer in the documentation and/or other materials provided
014 * with the distribution.
015 * * Neither the name of the copyright holder nor the names of the
016 * contributors may be used to endorse or promote products derived
017 * from this software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
020 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
021 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
022 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
023 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
024 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
025 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
026 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
027 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
029 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031
032 package org.pbjar.jxlayer.plaf.ext.transform;
033
034 import java.awt.Point;
035 import java.awt.Rectangle;
036 import java.lang.reflect.Field;
037 import java.lang.reflect.Method;
038
039 import javax.swing.JComponent;
040 import javax.swing.RepaintManager;
041 import javax.swing.SwingUtilities;
042
043 import org.jdesktop.jxlayer.JXLayer;
044 import org.jdesktop.jxlayer.plaf.LayerUI;
045 import org.pbjar.jxlayer.plaf.ext.TransformUI;
046
047 /**
048 * To avoid duplicate code, this class implements the actual logic for
049 * {@link TransformRPMSwingX} and {@link TransformRPMFallBack}.
050 *
051 * @author Piet Blok
052 */
053 public class TransformRPMImpl {
054
055 /**
056 * A flag, indicating whether or not a very dirty initialization on created
057 * {@link RepaintManager}s must be performed.
058 *
059 * @see #hackInitialization(RepaintManager, RepaintManager)
060 */
061 public static boolean hack = false;
062
063 /**
064 * Searches upwards in the component hierarchy for a {@link JXLayer}
065 * ancestor with an enabled {@link TransformUI}.
066 * <p>
067 * If found, the dirty rectangle is transformed to a rectangle targeted at
068 * that {@link JXLayer} and the argument manager's
069 * {@link RepaintManager#addDirtyRegion(JComponent, int, int, int, int)} is
070 * invoked. {@code true} is returned.
071 * </p>
072 * <p>
073 * Else, (@code false} is returned.
074 * </p>
075 *
076 * @param aComponent
077 * a component
078 * @param x
079 * the X of the dirty region
080 * @param y
081 * the Y of the dirty region
082 * @param w
083 * the width of the dirty region
084 * @param h
085 * the height of the dirty region
086 * @param manager
087 * the current {@link RepaintManager}
088 * @return {@code true} if the call is delegated to the manager with a
089 * transformed rectangle, {@code false} otherwise
090 */
091 @SuppressWarnings("unchecked")
092 public static boolean addDirtyRegion(JComponent aComponent, int x, int y,
093 int w, int h, RepaintManager manager) {
094 if (aComponent.isShowing()) {
095 JXLayer<?> layer = findJXLayer(aComponent);
096 if (layer != null) {
097 TransformUI ui = (TransformUI) layer.getUI();
098 Point point = aComponent.getLocationOnScreen();
099 SwingUtilities.convertPointFromScreen(point, layer);
100 Rectangle transformPortRegion = ui.transform(new Rectangle(x
101 + point.x, y + point.y, w, h),
102 (JXLayer<JComponent>) layer);
103 manager.addDirtyRegion((JXLayer<?>) layer,
104 transformPortRegion.x, transformPortRegion.y,
105 transformPortRegion.width, transformPortRegion.height);
106 return true;
107 }
108 }
109 return false;
110 }
111
112 /**
113 * If {@link #hack} is {@code true}, the private fields {@code paintManager}
114 * and {@code bufferStrategyType} are copied via reflection from the source
115 * manager into the destination manager.
116 *
117 * @param sourceManager
118 * @param destinationManager
119 */
120 public static void hackInitialization(RepaintManager sourceManager,
121 RepaintManager destinationManager) {
122 if (hack) {
123 Class<RepaintManager> rpmClass = RepaintManager.class;
124 try {
125
126 Field fieldBufferStrategyType = rpmClass
127 .getDeclaredField("bufferStrategyType");
128 Field fieldPaintManager = rpmClass
129 .getDeclaredField("paintManager");
130 Method methodGetPaintManager = rpmClass
131 .getDeclaredMethod("getPaintManager");
132
133 fieldBufferStrategyType.setAccessible(true);
134 fieldPaintManager.setAccessible(true);
135 methodGetPaintManager.setAccessible(true);
136
137 Object paintManager = methodGetPaintManager
138 .invoke(sourceManager);
139 short bufferStrategyType = (Short) fieldBufferStrategyType
140 .get(sourceManager);
141
142 fieldBufferStrategyType.set(destinationManager,
143 bufferStrategyType);
144 fieldPaintManager.set(destinationManager, paintManager);
145
146 fieldBufferStrategyType.setAccessible(false);
147 fieldPaintManager.setAccessible(false);
148 methodGetPaintManager.setAccessible(false);
149
150 System.out.println("Copied paintManager of type: "
151 + paintManager.getClass().getName());
152 switch (bufferStrategyType) {
153 case (0):
154 System.out.println("Copied bufferStrategyType "
155 + bufferStrategyType
156 + ": BUFFER_STRATEGY_NOT_SPECIFIED");
157 break;
158 case (1):
159 System.out.println("Copied bufferStrategyType "
160 + bufferStrategyType
161 + ": BUFFER_STRATEGY_SPECIFIED_ON");
162 break;
163 case (2):
164 System.out.println("Copied bufferStrategyType "
165 + bufferStrategyType
166 + ": BUFFER_STRATEGY_SPECIFIED_OFF");
167 break;
168 default:
169 System.out.println("Copied bufferStrategyType "
170 + bufferStrategyType + ": ???");
171 }
172 } catch (Throwable t) {
173 t.printStackTrace(System.out);
174 }
175 }
176 }
177
178 /**
179 * Find the first ancestor {@link JXLayer} with an enabled
180 * {@link TransformUI}.
181 *
182 * @param aComponent
183 * some component
184 * @return a {@link JXLayer} instance or {@code null}
185 */
186 private static JXLayer<?> findJXLayer(JComponent aComponent) {
187
188 JXLayer<?> layer = (JXLayer<?>) SwingUtilities.getAncestorOfClass(
189 JXLayer.class, aComponent);
190 if (layer != null) {
191 LayerUI<?> ui = ((JXLayer<?>) layer).getUI();
192 if (ui instanceof TransformUI) {
193 if (ui.isEnabled()) {
194 return layer;
195 }
196 }
197 return findJXLayer(layer);
198 }
199 return null;
200 }
201
202 private TransformRPMImpl() {
203 }
204 }