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 }