001: /*
002: * Copyright (c) 2005, romain guy (romain.guy@jext.org) and craig wickesser (craig@codecraig.com) and henry story
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
006: *
007: * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
008: * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
009: * * Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
010: *
011: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
012: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
013: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
014: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
015: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
016: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
017: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
018: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
019: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
020: * POSSIBILITY OF SUCH DAMAGE.
021: */
022: package com.jidesoft.swing;
023:
024: import javax.swing.*;
025: import java.awt.*;
026: import java.awt.event.ActionEvent;
027: import java.awt.event.ActionListener;
028: import java.awt.geom.AffineTransform;
029: import java.awt.geom.Area;
030: import java.awt.geom.Point2D;
031: import java.awt.geom.Rectangle2D;
032:
033: public class InfiniteProgressPanel extends JComponent implements
034: ActionListener {
035: private static final int DEFAULT_NUMBER_OF_BARS = 12;
036:
037: private int numBars;
038: private double dScale = 1.2d;
039:
040: private Area[] bars;
041: private Rectangle barsBounds = null;
042: private Rectangle barsScreenBounds = null;
043: private AffineTransform centerAndScaleTransform = null;
044: private Timer timer = new Timer(1000 / 16, this );
045: private Color[] colors = null;
046: private int colorOffset = 0;
047: private boolean tempHide = false;
048: private String text;
049:
050: public InfiniteProgressPanel() {
051: this .numBars = DEFAULT_NUMBER_OF_BARS;
052:
053: colors = new Color[numBars * 2];
054:
055: // build bars
056: bars = buildTicker(numBars);
057:
058: // calculate bars bounding rectangle
059: barsBounds = new Rectangle();
060: for (int i = 0; i < bars.length; i++) {
061: barsBounds = barsBounds.union(bars[i].getBounds());
062: }
063:
064: // create colors
065: for (int i = 0; i < bars.length; i++) {
066: int channel = 224 - 128 / (i + 1);
067: colors[i] = new Color(channel, channel, channel);
068: colors[numBars + i] = colors[i];
069: }
070:
071: // set cursor
072: //setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
073:
074: // set opaque
075: setOpaque(true);
076: }
077:
078: /**
079: * Called to animate the rotation of the bar's colors
080: */
081: public void actionPerformed(ActionEvent e) {
082: // rotate colors
083: if (colorOffset == (numBars - 1)) {
084: colorOffset = 0;
085: } else {
086: colorOffset++;
087: }
088: // repaint
089: if (barsScreenBounds != null) {
090: repaint(barsScreenBounds);
091: } else {
092: repaint();
093: }
094: }
095:
096: /**
097: * Show/Hide the pane, starting and stopping the animation as you go
098: */
099: public void setVisible(boolean i_bIsVisible) {
100: setOpaque(false);
101: // capture
102: if (i_bIsVisible) {
103: // start anim
104: timer.start();
105: } else {
106: // stop anim
107: timer.stop();
108: }
109: super .setVisible(i_bIsVisible);
110: }
111:
112: /**
113: * Recalc bars based on changes in size
114: */
115: public void setBounds(int x, int y, int width, int height) {
116: super .setBounds(x, y, width, height);
117: // update centering transform
118: centerAndScaleTransform = new AffineTransform();
119: centerAndScaleTransform.translate((double) getWidth() / 2d,
120: (double) getHeight() / 2d);
121: centerAndScaleTransform.scale(dScale, dScale);
122: // calc new bars bounds
123: if (barsBounds != null) {
124: Area oBounds = new Area(barsBounds);
125: oBounds.transform(centerAndScaleTransform);
126: barsScreenBounds = oBounds.getBounds();
127: }
128: }
129:
130: /**
131: * paint background dimed and bars over top
132: */
133: protected void paintComponent(Graphics g) {
134: if (!tempHide) {
135: Rectangle oClip = g.getClipBounds();
136:
137: if (isOpaque()) {
138: g.setColor(getBackground());
139: g.fillRect(oClip.x, oClip.y, oClip.width, oClip.height);
140: }
141:
142: // move to center
143: Graphics2D g2 = (Graphics2D) g.create();
144: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
145: RenderingHints.VALUE_ANTIALIAS_ON);
146: g2.transform(centerAndScaleTransform);
147: // draw ticker
148: for (int i = 0; i < bars.length; i++) {
149: g2.setColor(colors[i + colorOffset]);
150: g2.fill(bars[i]);
151: }
152: }
153: }
154:
155: /**
156: * Builds the circular shape and returns the result as an array of <code>Area</code>. Each <code>Area</code> is one
157: * of the bars composing the shape.
158: */
159: private static Area[] buildTicker(int i_iBarCount) {
160: Area[] ticker = new Area[i_iBarCount];
161: Point2D.Double center = new Point2D.Double(0, 0);
162: double fixedAngle = 2.0 * Math.PI / ((double) i_iBarCount);
163:
164: for (double i = 0.0; i < (double) i_iBarCount; i++) {
165: Area primitive = buildPrimitive();
166:
167: AffineTransform toCenter = AffineTransform
168: .getTranslateInstance(center.getX(), center.getY());
169: AffineTransform toBorder = AffineTransform
170: .getTranslateInstance(2.0, -0.4);
171: AffineTransform toCircle = AffineTransform
172: .getRotateInstance(-i * fixedAngle, center.getX(),
173: center.getY());
174:
175: AffineTransform toWheel = new AffineTransform();
176: toWheel.concatenate(toCenter);
177: toWheel.concatenate(toBorder);
178:
179: primitive.transform(toWheel);
180: primitive.transform(toCircle);
181:
182: ticker[(int) i] = primitive;
183: }
184:
185: return ticker;
186: }
187:
188: /**
189: * Builds a bar.
190: */
191: private static Area buildPrimitive() {
192: // Rectangle2D.Double body = new Rectangle2D.Double(6, 0, 30, 12);
193: // Ellipse2D.Double head = new Ellipse2D.Double(0, 0, 12, 12);
194: // Ellipse2D.Double tail = new Ellipse2D.Double(30, 0, 12, 12);
195: // Rectangle2D.Double body = new Rectangle2D.Double(3, 0, 15, 6);
196: // Ellipse2D.Double head = new Ellipse2D.Double(0, 0, 6, 6);
197: // Ellipse2D.Double tail = new Ellipse2D.Double(15, 0, 6, 6);
198: // Rectangle2D.Double body = new Rectangle2D.Double(2, 0, 10, 4);
199: // Ellipse2D.Double head = new Ellipse2D.Double(0, 0, 4, 4);
200: // Ellipse2D.Double tail = new Ellipse2D.Double(10, 0, 4, 4);
201: Rectangle2D.Double body = new Rectangle2D.Double(0, 0, 6, 1);
202: // Ellipse2D.Double head = new Ellipse2D.Double(0, 0, 2, 2);
203: // Ellipse2D.Double tail = new Ellipse2D.Double(5, 0, 2, 2);
204:
205: Area tick = new Area(body);
206: // tick.add(new Area(head));
207: // tick.add(new Area(tail));
208: //
209: return tick;
210: }
211:
212: public void start() {
213: setVisible(true);
214: }
215:
216: public void stop() {
217: setVisible(false);
218: }
219: }
|