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.Container;
035    import java.awt.Dimension;
036    import java.awt.Rectangle;
037    import java.awt.geom.AffineTransform;
038    import java.awt.geom.Area;
039    import java.awt.geom.Rectangle2D;
040    
041    import javax.swing.JComponent;
042    import javax.swing.SwingUtilities;
043    
044    import org.jdesktop.jxlayer.JXLayer;
045    import org.jdesktop.jxlayer.plaf.DefaultLayerLayout;
046    import org.jdesktop.jxlayer.plaf.LayerUI;
047    import org.pbjar.jxlayer.plaf.ext.TransformUI;
048    
049    /**
050     * A specialized layout manager for {@link JXLayer} in combination with the
051     * {@link TransformUI}.
052     * <p>
053     * It extends {@link DefaultLayerLayout} and, as long as no enabled
054     * {@link TransformUI} is set to {@link JXLayer}, will act exactly the same as
055     * its super class.
056     * </p>
057     * <p>
058     * However, when the above conditions are all true, its behavior becomes
059     * different:
060     * <ol>
061     * <li>
062     * Instead of setting the view's size to the layer's calculated inner area, it
063     * will set the view's size to its preferred size.</li>
064     * <li>
065     * Instead of setting the view's bounds to the calculated inner area, it will
066     * center the view in that inner area. This may result in some parts of the view
067     * formally obscured, or, some parts of the inner area not covered by the view.</li>
068     * <li>
069     * The preferred size will first be computed by the super implementation. Then,
070     * before returning, the calculated size will be transformed with the
071     * {@link AffineTransform} returned by
072     * {@link TransformUI#getPreferredTransform(Dimension, JXLayer)};</li>
073     * <li>
074     * The minimum size will first be computed by the super implementation. Then,
075     * before returning, the calculated size will be transformed with the
076     * {@link AffineTransform} returned by
077     * {@link TransformUI#getPreferredTransform(Dimension, JXLayer)};</li>
078     * </ol>
079     * </p>
080     * 
081     * @see JXLayer#getView()
082     * @see JXLayer#getGlassPane()
083     * @see TransformUI
084     */
085    public class TransformLayout extends DefaultLayerLayout {
086    
087        public TransformLayout() {
088    
089        }
090    
091        /**
092         * Overridden to apply a different layout when the {@link LayerUI} is an
093         * instance of {@link TransformUI}. If this is not the case, the super
094         * implementation will be invoked.
095         */
096        @Override
097        public void layoutContainer(Container parent) {
098            JXLayer<?> layer = (JXLayer<?>) parent;
099            LayerUI<?> layerUI = layer.getUI();
100            if (layerUI instanceof TransformUI) {
101                // if (layerUI.isEnabled()) {
102                JComponent view = layer.getView();
103                JComponent glassPane = layer.getGlassPane();
104                if (view != null) {
105                    Rectangle innerArea = new Rectangle();
106                    SwingUtilities.calculateInnerArea(layer, innerArea);
107                    view.setSize(view.getPreferredSize());
108                    Rectangle viewRect = new Rectangle(0, 0, view.getWidth(), view
109                            .getHeight());
110                    int x = (int) Math.round(innerArea.getCenterX()
111                            - viewRect.getCenterX());
112                    int y = (int) Math.round(innerArea.getCenterY()
113                            - viewRect.getCenterY());
114                    viewRect.translate(x, y);
115                    view.setBounds(viewRect);
116    
117                }
118                if (glassPane != null) {
119                    glassPane.setLocation(0, 0);
120                    glassPane.setSize(layer.getWidth(), layer.getHeight());
121                }
122                return;
123                // }
124            }
125            super.layoutContainer(parent);
126        }
127    
128        /**
129         * Overridden to apply a preferred transform on the {@link Dimension} object
130         * returned from the super implementation.
131         */
132        @Override
133        public Dimension minimumLayoutSize(Container parent) {
134            return transform(parent, super.minimumLayoutSize(parent));
135        }
136    
137        /**
138         * Overridden to apply a preferred transform on the {@link Dimension} object
139         * returned from the super implementation.
140         */
141        @Override
142        public Dimension preferredLayoutSize(Container parent) {
143            return transform(parent, super.preferredLayoutSize(parent));
144        }
145    
146        @SuppressWarnings("unchecked")
147        private Dimension transform(Container parent, Dimension size) {
148            JXLayer<JComponent> layer = (JXLayer<JComponent>) parent;
149            LayerUI<?> ui = layer.getUI();
150            if (ui instanceof TransformUI) {
151                TransformUI transformUI = (TransformUI) ui;
152                AffineTransform transform = transformUI.getPreferredTransform(size,
153                        layer);
154                if (transform != null) {
155                    Area area = new Area(new Rectangle2D.Double(0, 0, size
156                            .getWidth(), size.getHeight()));
157                    area.transform(transform);
158                    Rectangle2D bounds = area.getBounds2D();
159                    size.setSize(bounds.getWidth(), bounds.getHeight());
160                }
161            }
162            return size;
163        }
164    }