001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.lib.profiler.ui.components;
042:
043: import java.awt.Dimension;
044: import java.awt.Insets;
045: import java.awt.event.ComponentEvent;
046: import java.awt.event.ComponentListener;
047: import javax.accessibility.Accessible;
048: import javax.accessibility.AccessibleContext;
049: import javax.swing.JComponent;
050: import javax.swing.JPanel;
051: import javax.swing.border.Border;
052:
053: /**
054: *
055: * @author Jiri Sedlacek
056: */
057: public class ComponentMorpher extends JComponent implements
058: ComponentListener, Accessible {
059: //~ Inner Classes ------------------------------------------------------------------------------------------------------------
060:
061: private class MorpherThread extends Thread {
062: //~ Methods --------------------------------------------------------------------------------------------------------------
063:
064: public void run() {
065: setupMorphing();
066:
067: while (isMorphing()) {
068: morphingStep();
069:
070: try {
071: Thread.sleep(morphingDelay);
072: } catch (InterruptedException ie) {
073: }
074: }
075: }
076: }
077:
078: //~ Instance fields ----------------------------------------------------------------------------------------------------------
079:
080: private ImageBlenderPanel blenderPanel;
081: private JComponent component1;
082: private JComponent component2;
083: private JComponent currentComponent;
084: private JComponent endComponent;
085:
086: // --- Morphing stuff --------------------------------------------------------
087: private JComponent startComponent;
088: private JPanel accessibleDelegate;
089: private boolean isMorphing = false;
090: private float heightDelta;
091: private int morphingDelay;
092: private int morphingStep;
093: private int morphingSteps;
094:
095: //~ Constructors -------------------------------------------------------------------------------------------------------------
096:
097: public ComponentMorpher(JComponent component1, JComponent component2) {
098: this (component1, component2, 10, 15);
099: }
100:
101: public ComponentMorpher(JComponent component1,
102: JComponent component2, int morphingSteps, int morphingDelay) {
103: this .component1 = component1;
104: this .component2 = component2;
105:
106: setMorphingSteps(morphingSteps);
107: setMorphingDelay(morphingDelay);
108:
109: setLayout(null);
110: setCurrentComponent(component1);
111:
112: addComponentListener(this );
113: }
114:
115: //~ Methods ------------------------------------------------------------------------------------------------------------------
116:
117: public AccessibleContext getAccessibleContext() {
118: if (accessibleDelegate == null) {
119: accessibleDelegate = new JPanel();
120: }
121:
122: return accessibleDelegate.getAccessibleContext();
123: }
124:
125: public void setBorder(Border border) {
126: super .setBorder(border);
127: setClientPreferredSize(currentComponent.getPreferredSize());
128: }
129:
130: public boolean isExpanded() {
131: return currentComponent == component2;
132: }
133:
134: public boolean isMorphing() {
135: return isMorphing;
136: }
137:
138: public void setMorphingDelay(int morphingDelay) {
139: this .morphingDelay = morphingDelay;
140: }
141:
142: public int getMorphingDelay() {
143: return morphingDelay;
144: }
145:
146: public void setMorphingSteps(int morphingSteps) {
147: this .morphingSteps = morphingSteps;
148: }
149:
150: public int getMorphingSteps() {
151: return morphingSteps;
152: }
153:
154: public void componentHidden(ComponentEvent e) {
155: }
156:
157: public void componentMoved(ComponentEvent e) {
158: }
159:
160: public void componentResized(ComponentEvent e) {
161: if (!isMorphing && (currentComponent != null)) {
162: setCurrentComponent(currentComponent);
163: revalidate();
164: }
165: }
166:
167: public void componentShown(ComponentEvent e) {
168: }
169:
170: public void expand() {
171: if (currentComponent != component2) {
172: setCurrentComponent(component2);
173: }
174: }
175:
176: public void morph() {
177: if (!isMorphing()) {
178: new MorpherThread().start();
179: }
180: }
181:
182: public void morphingStep() {
183: if (morphingStep > morphingSteps) {
184: return;
185: }
186:
187: // --- Workaround to update data for incorrectly sized endComponent due to nested multiline textcomponent (HTMLTextArea, JEditorPane, JTextArea...)
188: if (endComponent.getSize().height != endComponent
189: .getPreferredSize().height) {
190: endComponent.setSize(new Dimension(getClientSize().width,
191: endComponent.getPreferredSize().height));
192: heightDelta = (float) (endComponent.getSize().height - startComponent
193: .getSize().height)
194: / (float) ((morphingStep == 0) ? morphingSteps
195: : (morphingSteps - morphingStep + 1));
196: }
197:
198: // ---
199: if (morphingStep == 0) { // First step
200:
201: if (endComponent == component2) {
202: setCurrentComponent(endComponent);
203: }
204:
205: setClientPreferredSize(startComponent.getSize());
206: } else if (morphingStep == morphingSteps) { // Last step
207:
208: if (endComponent == component1) {
209: setCurrentComponent(endComponent);
210: }
211:
212: setClientPreferredSize(endComponent.getSize());
213: isMorphing = false;
214: } else { // Intermediate step
215: setClientPreferredSize(new Dimension(
216: endComponent.getSize().width, startComponent
217: .getSize().height
218: + (int) (morphingStep * heightDelta)));
219: }
220:
221: revalidate();
222: morphingStep++;
223: }
224:
225: public void refreshLayout() {
226: if (currentComponent != null) {
227: setCurrentComponent(currentComponent);
228: }
229:
230: revalidate();
231: }
232:
233: public void reset() {
234: if (currentComponent != component1) {
235: setCurrentComponent(component1);
236: }
237: }
238:
239: public void setupMorphing() {
240: startComponent = layoutComponent((currentComponent == component1) ? component1
241: : component2);
242: endComponent = layoutComponent((currentComponent == component1) ? component2
243: : component1);
244:
245: heightDelta = (float) (endComponent.getSize().height - startComponent
246: .getSize().height)
247: / (float) morphingSteps;
248:
249: morphingStep = 0;
250: isMorphing = true;
251:
252: setCurrentComponent(startComponent);
253: }
254:
255: private void setClientPreferredSize(Dimension size) {
256: Insets insets = getInsets();
257: setPreferredSize(new Dimension(size.width + insets.left
258: + insets.right, size.height + insets.top
259: + insets.bottom));
260: }
261:
262: private Dimension getClientSize() {
263: Dimension size = getSize();
264: Insets insets = getInsets();
265:
266: return new Dimension(size.width - insets.left - insets.right,
267: size.height - insets.top - insets.bottom);
268: }
269:
270: private void setCurrentComponent(JComponent component) {
271: boolean sameComponents = component == currentComponent;
272:
273: if (!sameComponents && (currentComponent != null)) {
274: remove(currentComponent);
275: }
276:
277: component = layoutComponent(component);
278: currentComponent = component;
279:
280: if (!sameComponents) {
281: add(currentComponent);
282: }
283:
284: Insets insets = getInsets();
285: currentComponent.setLocation(insets.left, insets.top);
286: setClientPreferredSize(component.getSize());
287: }
288:
289: private JComponent layoutComponent(JComponent component) {
290: // Initial component sizing & layout
291: if (getClientSize().width > 0) {
292: component.setSize(getClientSize()); // try to fit the component to ComponentMorpher
293: component.validate(); // layout component
294:
295: // Correct component sizing & layout
296: component.setSize(new Dimension(getClientSize().width,
297: component.getPreferredSize().height)); // Width of component is fixed, update height
298: component.validate(); // layout component
299: }
300:
301: return component;
302: }
303: }
|