001    /*
002     * PainterUtil.java
003     *
004     * Created on July 20, 2006, 1:18 PM
005     *
006     * To change this template, choose Tools | Template Manager
007     * and open the template in the editor.
008     */
009    
010    package org.jdesktop.swingx.editors;
011    
012    
013    import java.awt.GradientPaint;
014    import java.awt.Graphics2D;
015    import java.awt.Insets;
016    import java.awt.LinearGradientPaint;
017    import java.awt.RadialGradientPaint;
018    import java.awt.RenderingHints;
019    import java.awt.geom.AffineTransform;
020    import java.awt.geom.Arc2D;
021    import java.awt.geom.Area;
022    import java.awt.geom.CubicCurve2D;
023    import java.awt.geom.Ellipse2D;
024    import java.awt.geom.GeneralPath;
025    import java.awt.geom.Line2D;
026    import java.awt.geom.Point2D;
027    import java.awt.geom.QuadCurve2D;
028    import java.awt.geom.Rectangle2D;
029    import java.awt.geom.RoundRectangle2D;
030    import java.awt.image.BufferedImage;
031    import java.beans.BeanInfo;
032    import java.beans.DefaultPersistenceDelegate;
033    import java.beans.Encoder;
034    import java.beans.ExceptionListener;
035    import java.beans.Expression;
036    import java.beans.Introspector;
037    import java.beans.PersistenceDelegate;
038    import java.beans.PropertyDescriptor;
039    import java.beans.Statement;
040    import java.beans.XMLDecoder;
041    import java.beans.XMLEncoder;
042    import java.io.File;
043    import java.io.FileNotFoundException;
044    import java.io.FileOutputStream;
045    import java.io.IOException;
046    import java.lang.reflect.Field;
047    import java.lang.reflect.Modifier;
048    import java.net.MalformedURLException;
049    import java.net.URL;
050    
051    import javax.imageio.ImageIO;
052    import javax.swing.JComponent;
053    
054    import org.jdesktop.swingx.JXButton;
055    import org.jdesktop.swingx.JXLabel;
056    import org.jdesktop.swingx.JXPanel;
057    import org.jdesktop.swingx.editors.PainterPropertyEditor.AffineTransformDelegate;
058    import org.jdesktop.swingx.editors.PainterPropertyEditor.Arc2DDelegate;
059    import org.jdesktop.swingx.editors.PainterPropertyEditor.AreaDelegate;
060    import org.jdesktop.swingx.editors.PainterPropertyEditor.CubicCurve2DDelegate;
061    import org.jdesktop.swingx.editors.PainterPropertyEditor.Ellipse2DDelegate;
062    import org.jdesktop.swingx.editors.PainterPropertyEditor.GeneralPathDelegate;
063    import org.jdesktop.swingx.editors.PainterPropertyEditor.GradientPaintDelegate;
064    import org.jdesktop.swingx.editors.PainterPropertyEditor.InsetsDelegate;
065    import org.jdesktop.swingx.editors.PainterPropertyEditor.Line2DDelegate;
066    import org.jdesktop.swingx.editors.PainterPropertyEditor.LinearGradientPaintDelegate;
067    import org.jdesktop.swingx.editors.PainterPropertyEditor.Point2DDelegate;
068    import org.jdesktop.swingx.editors.PainterPropertyEditor.QuadCurve2DDelegate;
069    import org.jdesktop.swingx.editors.PainterPropertyEditor.RadialGradientPaintDelegate;
070    import org.jdesktop.swingx.editors.PainterPropertyEditor.Rectangle2DDelegate;
071    import org.jdesktop.swingx.editors.PainterPropertyEditor.RoundRectangle2DDelegate;
072    import org.jdesktop.swingx.painter.AbstractLayoutPainter;
073    import org.jdesktop.swingx.painter.AbstractPainter;
074    import org.jdesktop.swingx.painter.CompoundPainter;
075    import org.jdesktop.swingx.painter.ImagePainter;
076    import org.jdesktop.swingx.painter.Painter;
077    import org.jdesktop.swingx.painter.RectanglePainter;
078    
079    /**
080     *
081     * @author joshy
082     */
083    public class PainterUtil {
084        
085        /** Creates a new instance of PainterUtil */
086        private PainterUtil() {
087        }
088        /*
089        public static void main(String[] args) throws Exception {
090            ImagePainter ip = new ImagePainter();
091            ip.setImageString("file:/Users/joshy/Pictures/cooltikis.jpg");
092            File outfile = new File("/Users/joshy/Desktop/test.xml");
093            outfile.createNewFile();
094            p("outfile = " + outfile.getAbsolutePath());
095            p("exists = " + outfile.exists());
096            savePainterToFile(ip, outfile, outfile.getParentFile().toURL());
097            p("---------");
098            ip = (ImagePainter)loadPainter(outfile);
099            p("image = " + ip.getImage());
100            ip = (ImagePainter)loadPainter(outfile.toURL());
101            p("image = " + ip.getImage());
102            p("==================");
103            
104            
105        }*/
106        
107        public static Painter loadPainter(File file) throws FileNotFoundException, MalformedURLException, IOException {
108            return loadPainter(file.toURI().toURL(), file.toURI().toURL());
109        }
110        
111        private static Painter loadPainter(final URL in, URL baseURL) throws FileNotFoundException, IOException {
112            Thread.currentThread().setContextClassLoader(PainterUtil.class.getClassLoader());
113            XMLDecoder dec = new XMLDecoder(in.openStream());
114    //        p("creating a persistence owner with the base url: " + baseURL);
115            dec.setOwner(new PersistenceOwner(baseURL));
116            dec.setExceptionListener(new ExceptionListener() {
117                public void exceptionThrown(Exception ex) {
118                    System.out.println(ex.getMessage());
119                    ex.printStackTrace();
120                }
121            });
122            Object obj = dec.readObject();
123            return (Painter)obj;
124        }
125        
126        public static Painter loadPainter(URL url) throws IOException {
127            return loadPainter(url,url);
128        }
129        
130        static public void savePainterToFile(Painter compoundPainter, File file) throws IOException {
131            savePainterToFile(compoundPainter,file,file.getParentFile().toURI().toURL());
132        }
133        
134        static public void savePainterToFile(Painter compoundPainter, File file, URL baseURL) throws IOException {
135            //System.setErr(null);
136            //        u.p("writing out to: " + file.getCanonicalPath());
137            setTransient(ImagePainter.class, "image");
138            setTransient(ImagePainter.class, "imageString");
139            //setTransient(CompoundPainter.class,"antialiasing");
140            //setTransient(AbstractPainter.class,"antialiasing");
141            //setTransient(AbstractPainter.class,"renderingHints");
142            //setPropertyDelegate();
143            
144            XMLEncoder e = new XMLEncoder(new FileOutputStream(file));
145            e.setOwner(new PersistenceOwner(baseURL));
146            //p("owner = " + e.getOwner());
147            //e.setOwner(compoundPainter);
148            
149            // serialize the enums
150            //e.setPersistenceDelegate(AbstractPainter.Antialiasing.class, new TypeSafeEnumPersistenceDelegate());
151            e.setPersistenceDelegate(AbstractPainter.Interpolation.class, new TypeSafeEnumPersistenceDelegate());
152           // e.setPersistenceDelegate(AbstractPainter.FractionalMetrics.class, new TypeSafeEnumPersistenceDelegate());
153            e.setPersistenceDelegate(RectanglePainter.Style.class, new TypeSafeEnumPersistenceDelegate());
154            e.setPersistenceDelegate(AbstractLayoutPainter.HorizontalAlignment.class, new TypeSafeEnumPersistenceDelegate());
155            e.setPersistenceDelegate(AbstractLayoutPainter.VerticalAlignment.class, new TypeSafeEnumPersistenceDelegate());
156            
157            
158            e.setPersistenceDelegate(AbstractPainter.class, new AbstractPainterDelegate());
159            e.setPersistenceDelegate(ImagePainter.class, new ImagePainterDelegate());
160            e.setPersistenceDelegate(RenderingHints.class, new RenderingHintsDelegate());
161            e.setPersistenceDelegate(GradientPaint.class, new GradientPaintDelegate());
162            e.setPersistenceDelegate(Arc2D.Float.class, new Arc2DDelegate());
163            e.setPersistenceDelegate(Arc2D.Double.class, new Arc2DDelegate());
164            e.setPersistenceDelegate(CubicCurve2D.Float.class, new CubicCurve2DDelegate());
165            e.setPersistenceDelegate(CubicCurve2D.Double.class, new CubicCurve2DDelegate());
166            e.setPersistenceDelegate(Ellipse2D.Float.class, new Ellipse2DDelegate());
167            e.setPersistenceDelegate(Ellipse2D.Double.class, new Ellipse2DDelegate());
168            e.setPersistenceDelegate(Line2D.Float.class, new Line2DDelegate());
169            e.setPersistenceDelegate(Line2D.Double.class, new Line2DDelegate());
170            e.setPersistenceDelegate(Point2D.Float.class, new Point2DDelegate());
171            e.setPersistenceDelegate(Point2D.Double.class, new Point2DDelegate());
172            e.setPersistenceDelegate(QuadCurve2D.Float.class, new QuadCurve2DDelegate());
173            e.setPersistenceDelegate(QuadCurve2D.Double.class, new QuadCurve2DDelegate());
174            e.setPersistenceDelegate(Rectangle2D.Float.class, new Rectangle2DDelegate());
175            e.setPersistenceDelegate(Rectangle2D.Double.class, new Rectangle2DDelegate());
176            e.setPersistenceDelegate(RoundRectangle2D.Float.class, new RoundRectangle2DDelegate());
177            e.setPersistenceDelegate(RoundRectangle2D.Double.class, new RoundRectangle2DDelegate());
178            e.setPersistenceDelegate(Area.class, new AreaDelegate());
179            e.setPersistenceDelegate(GeneralPath.class, new GeneralPathDelegate());
180            e.setPersistenceDelegate(AffineTransform.class, new AffineTransformDelegate());
181            e.setPersistenceDelegate(RadialGradientPaint.class, new RadialGradientPaintDelegate());
182            e.setPersistenceDelegate(LinearGradientPaint.class, new LinearGradientPaintDelegate());
183            e.setPersistenceDelegate(Insets.class, new InsetsDelegate());
184            
185            e.writeObject(compoundPainter);
186            e.close();
187        }
188        
189        //private static void setPropertyDelegate(Class clazz, String property, )
190        private static void setTransient(Class clazz, String property) {
191            try {
192                BeanInfo info = Introspector.getBeanInfo(clazz);
193                PropertyDescriptor[] propertyDescriptors =
194                        info.getPropertyDescriptors();
195                for (int i = 0; i < propertyDescriptors.length; ++i) {
196                    PropertyDescriptor pd = propertyDescriptors[i];
197                    if (pd.getName().equals(property)) {
198                        pd.setValue("transient", Boolean.TRUE);
199                        //u.p(pd.attributeNames());
200                    }
201                }
202            } catch (Exception ex) {
203                //u.p(ex);
204            }
205        }
206        
207        static class TypeSafeEnumPersistenceDelegate extends PersistenceDelegate {
208            protected boolean mutatesTo( Object oldInstance, Object newInstance ) {
209                return oldInstance == newInstance;
210            }
211            
212            protected Expression instantiate( Object oldInstance, Encoder out ) {
213                Class type = oldInstance.getClass();
214                if ( !Modifier.isPublic( type.getModifiers() ) )
215                    throw new IllegalArgumentException( "Could not instantiate instance of non-public class: " + oldInstance );
216                
217                for ( Field field : type.getFields() ) {
218                    int mod = field.getModifiers();
219                    if ( Modifier.isPublic( mod ) && Modifier.isStatic( mod ) && Modifier.isFinal( mod ) && ( type == field.getDeclaringClass() ) ) {
220                        try {
221                            if ( oldInstance == field.get( null ) )
222                                return new Expression( oldInstance, field, "get", new Object[]{null} );
223                        } catch ( IllegalAccessException exception ) {
224                            throw new IllegalArgumentException( "Could not get value of the field: " + field, exception );
225                        }
226                    }
227                }
228                throw new IllegalArgumentException( "Could not instantiate value: " + oldInstance );
229            }
230        }
231        
232        public static final class RenderingHintsDelegate extends PersistenceDelegate {
233            protected Expression instantiate(Object oldInstance, Encoder out) {
234                //u.p("rh inst");
235                // give it a constructor w/ null as the argument
236                return new Expression(oldInstance, oldInstance.getClass(),
237                        "new", new Object[] { null });
238            }
239            protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
240                //u.p("rh init ");
241                RenderingHints rh = (RenderingHints)oldInstance;
242                out.writeStatement(new Statement(oldInstance, "put",
243                        new Object[] {RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON}));
244                //u.p("done");
245            }
246        }
247        
248        public static final class AbstractPainterDelegate extends DefaultPersistenceDelegate {
249            protected void initialize(Class type, Object oldInstance,
250                    Object newInstance, Encoder out) {
251    //            p("ap delegate called");
252                super.initialize(type, oldInstance,  newInstance, out);
253            }
254        }
255        
256        public static final class ImagePainterDelegate extends DefaultPersistenceDelegate {
257            protected void initialize(Class type, Object oldInstance,
258                    Object newInstance, Encoder out) {
259    //            p("image painter delegate called");
260                super.initialize(type, oldInstance,  newInstance, out);
261                //p("old instance = " + oldInstance);
262                //p("owner = " + ((XMLEncoder)out).getOwner());
263                PersistenceOwner owner = (PersistenceOwner)((XMLEncoder)out).getOwner();
264                ImagePainter ip = (ImagePainter)oldInstance;
265    //            p("need to convert string: " + ip.getImageString());
266                String s = owner.toXMLURL(ip.getImageString());
267    //            p("converted to: " + s);
268                    //out.writeExpression(new Expression(oldInstance,owner,"fromXMLURL",new Object[]{ip.getImageString()}));
269                    //out.writeStatement(new Statement(owner,"fromXMLURL",new Object[]{ip.getImageString()}));
270                    //out.writeStatement(new Statement(oldInstance,"setImageString",new Object[]{
271                    //new Expression(oldInstance,owner,"fromXMLURL",new Object[]{ip.getImageString()})
272                    //}));
273                    
274                out.writeStatement(new Statement(oldInstance,"setResolver",new Object[]{owner}));
275                out.writeStatement(new Statement(oldInstance,"setImageString",new Object[]{s}));
276            }
277        }
278        
279        public static void savePainterToImage(JComponent testPanel, CompoundPainter compoundPainter, File file) throws IOException {
280            BufferedImage img = new BufferedImage(testPanel.getWidth(),testPanel.getHeight(),
281                    BufferedImage.TYPE_INT_ARGB);
282            Graphics2D g = img.createGraphics();
283            setBGP(testPanel,compoundPainter);
284            testPanel.paint(g);
285            ImageIO.write(img,"png",file);
286        }
287        
288        public static void setBGP(JComponent comp, Painter painter) {
289            if(comp instanceof JXPanel) {
290                ((JXPanel)comp).setBackgroundPainter(painter);
291            }
292            if(comp instanceof JXButton) {
293                ((JXButton)comp).setBackgroundPainter(painter);
294            }
295        }
296        public static void setFGP(JComponent comp, Painter painter) {
297            if(comp instanceof JXLabel) {
298                ((JXLabel)comp).setForegroundPainter(painter);
299            }
300            if(comp instanceof JXButton) {
301                ((JXButton)comp).setForegroundPainter(painter);
302            }
303        }
304        
305        public static Painter getFGP(JComponent comp) {
306            if(comp instanceof JXLabel) {
307                return ((JXLabel)comp).getForegroundPainter();
308            }
309            if(comp instanceof JXButton) {
310                return ((JXButton)comp).getForegroundPainter();
311            }
312            return null;
313        }
314        
315        public static Painter getBGP(JComponent comp) {
316            if(comp instanceof JXPanel) {
317                return ((JXPanel)comp).getBackgroundPainter();
318            }
319            if(comp instanceof JXButton) {
320                return ((JXButton)comp).getBackgroundPainter();
321            }
322            return null;
323        }
324        
325        public static class PersistenceOwner {
326            private URL baseURL;
327            public PersistenceOwner(URL baseURL) {
328                this.baseURL = baseURL;
329            }
330            
331            public URL getBaseURL() {
332                return baseURL;
333            }
334            public String toXMLURL(String url) {
335    //            p("========");
336    //            p("in toXMLURL()");
337    //            p("base url = " + baseURL);
338    //            p("url to convert = " + url);
339                //trim off the beginning if the url is relative to the base
340                if(url.startsWith(baseURL.toString())) {
341    //                p("it's a valid substring!!!!!!!!!!!!");
342                    url = url.substring(baseURL.toString().length());
343    //                p("subsstring = " + url);
344                }
345    //            p("final url = " + url);
346    //            p("========");
347                return url;
348            }
349            
350            public String fromXMLURL(String url) throws MalformedURLException {
351                /*p("========");
352                p("in fromXMLURL()");
353                p("base url = " + baseURL);
354                p("url to convert: " + url);*/
355                String s = new URL(baseURL,url).toString();
356    //            p("returning: " + s);
357    //            p("========");
358                return s;
359            }
360        }
361    }