Author: amarkhel
Date: 2010-09-21 13:41:11 -0400 (Tue, 21 Sep 2010)
New Revision: 19293
Added:
trunk/core/impl/src/main/java/org/ajax4jsf/resource/AnimationResource.java
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/AnimatedGifEncoder.java
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/GifDecoder.java
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/LZWEncoder.java
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/NeuQuant.java
trunk/ui/output/ui/src/main/java/org/richfaces/component/AbstractProgressBar.java
trunk/ui/output/ui/src/main/java/org/richfaces/component/NumberUtils.java
trunk/ui/output/ui/src/main/java/org/richfaces/renderkit/html/ProgressBarBaseRenderer.java
trunk/ui/output/ui/src/main/resources/META-INF/resources/org.richfaces/progressBar.ecss
trunk/ui/output/ui/src/main/resources/META-INF/resources/org.richfaces/progressBar.js
trunk/ui/output/ui/src/main/templates/progressBar.template.xml
Modified:
trunk/core/impl/src/main/java/org/ajax4jsf/resource/Java2Dresource.java
trunk/ui/output/ui/pom.xml
trunk/ui/output/ui/src/main/resources/META-INF/pn.faces-config.xml
trunk/ui/output/ui/src/main/resources/META-INF/pn.taglib.xml
Log:
Progressbar initial commit
Added: trunk/core/impl/src/main/java/org/ajax4jsf/resource/AnimationResource.java
===================================================================
--- trunk/core/impl/src/main/java/org/ajax4jsf/resource/AnimationResource.java
(rev 0)
+++ trunk/core/impl/src/main/java/org/ajax4jsf/resource/AnimationResource.java 2010-09-21
17:41:11 UTC (rev 19293)
@@ -0,0 +1,105 @@
+/**
+ * License Agreement.
+ *
+ * Rich Faces - Natural Ajax for Java Server Faces (JSF)
+ *
+ * Copyright (C) 2007 Exadel, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package org.ajax4jsf.resource;
+
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+import org.ajax4jsf.resource.image.animatedgif.AnimatedGifEncoder;
+import org.richfaces.resource.ImageType;
+
+public abstract class AnimationResource extends Java2Dresource {
+
+ private int[] delays;
+ private int currFrameIndex = 0;
+
+ public AnimationResource() {
+ super(ImageType.GIF);
+ }
+
+ protected abstract Dimension getFrameSize();
+
+ protected abstract int getNumberOfFrames();
+
+ protected int getRepeat() {
+ return -1;
+ }
+
+ protected int[] getFrameDelays() {
+ if (delays == null) {
+ delays = new int[getNumberOfFrames()];
+ Arrays.fill(delays, 0);
+ }
+
+ return delays;
+ }
+
+
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream output = new DataOutputStream(baos);
+ Dimension frameSize = getFrameSize();
+ int numberOfFrames = getNumberOfFrames();
+ BufferedImage frame = null;
+ currFrameIndex = 0;
+ if (frameSize.getHeight() > 0.0 && frameSize.getWidth() > 0.0
+ && numberOfFrames > 0) {
+ AnimatedGifEncoder encoder = new AnimatedGifEncoder();
+ encoder.start(output);
+ encoder.setRepeat(getRepeat());
+ int[] delays = getFrameDelays();
+ while (currFrameIndex < numberOfFrames) {
+ frame = getImageType().createImage(frameSize.width,
+ frameSize.height);
+ Graphics2D graphics = frame.createGraphics();
+ paint(graphics, currFrameIndex++);
+ graphics.dispose();
+ encoder.addFrame(frame);
+ if (delays != null && delays.length > currFrameIndex) {
+ encoder.setDelay(delays[currFrameIndex]);
+ }
+ }
+ encoder.finish();
+ }
+ output.flush();
+ output.close();
+ return new ByteArrayInputStream(baos.toByteArray());
+
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ protected abstract void paint(Graphics2D graphics2D, int frameIndex);
+
+}
Modified: trunk/core/impl/src/main/java/org/ajax4jsf/resource/Java2Dresource.java
===================================================================
--- trunk/core/impl/src/main/java/org/ajax4jsf/resource/Java2Dresource.java 2010-09-21
17:34:26 UTC (rev 19292)
+++ trunk/core/impl/src/main/java/org/ajax4jsf/resource/Java2Dresource.java 2010-09-21
17:41:11 UTC (rev 19293)
@@ -55,7 +55,9 @@
super();
this.imageType = imageType;
}
-
+ public ImageType getImageType() {
+ return this.imageType;
+ }
/**
* Primary calculation of image dimensions - used when HTML code is
* generated to render IMG's width and height Subclasses should override
Added:
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/AnimatedGifEncoder.java
===================================================================
---
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/AnimatedGifEncoder.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/AnimatedGifEncoder.java 2010-09-21
17:41:11 UTC (rev 19293)
@@ -0,0 +1,486 @@
+package org.ajax4jsf.resource.image.animatedgif;
+
+import java.io.*;
+import java.awt.*;
+import java.awt.image.*;
+
+/**
+ * Class AnimatedGifEncoder - Encodes a GIF file consisting of one or
+ * more frames.
+ * <pre>
+ * Example:
+ * AnimatedGifEncoder e = new AnimatedGifEncoder();
+ * e.start(outputFileName);
+ * e.setDelay(1000); // 1 frame per sec
+ * e.addFrame(image1);
+ * e.addFrame(image2);
+ * e.finish();
+ * </pre>
+ * No copyright asserted on the source code of this class. May be used
+ * for any purpose, however, refer to the Unisys LZW patent for restrictions
+ * on use of the associated LZWEncoder class. Please forward any corrections
+ * to kweiner(a)fmsware.com.
+ *
+ * @author Kevin Weiner, FM Software
+ * @version 1.03 November 2003
+ *
+ */
+
+public class AnimatedGifEncoder {
+
+ protected int width; // image size
+ protected int height;
+ protected Color transparent = null; // transparent color if given
+ protected int transIndex; // transparent index in color table
+ protected int repeat = -1; // no repeat
+ protected int delay = 0; // frame delay (hundredths)
+ protected boolean started = false; // ready to output frames
+ protected OutputStream out;
+ protected BufferedImage image; // current frame
+ protected byte[] pixels; // BGR byte array from frame
+ protected byte[] indexedPixels; // converted frame indexed to palette
+ protected int colorDepth; // number of bit planes
+ protected byte[] colorTab; // RGB palette
+ protected boolean[] usedEntry = new boolean[256]; // active palette entries
+ protected int palSize = 7; // color table size (bits-1)
+ protected int dispose = -1; // disposal code (-1 = use default)
+ protected boolean closeStream = false; // close stream when finished
+ protected boolean firstFrame = true;
+ protected boolean sizeSet = false; // if false, get size from first frame
+ protected int sample = 10; // default sample interval for quantizer
+
+ /**
+ * Sets the delay time between each frame, or changes it
+ * for subsequent frames (applies to last frame added).
+ *
+ * @param ms int delay time in milliseconds
+ */
+ public void setDelay(int ms) {
+ delay = Math.round(ms / 10.0f);
+ }
+
+ /**
+ * Sets the GIF frame disposal code for the last added frame
+ * and any subsequent frames. Default is 0 if no transparent
+ * color has been set, otherwise 2.
+ * @param code int disposal code.
+ */
+ public void setDispose(int code) {
+ if (code >= 0) {
+ dispose = code;
+ }
+ }
+
+ /**
+ * Sets the number of times the set of GIF frames
+ * should be played. Default is 1; 0 means play
+ * indefinitely. Must be invoked before the first
+ * image is added.
+ *
+ * @param iter int number of iterations.
+ * @return
+ */
+ public void setRepeat(int iter) {
+ if (iter >= 0) {
+ repeat = iter;
+ }
+ }
+
+ /**
+ * Sets the transparent color for the last added frame
+ * and any subsequent frames.
+ * Since all colors are subject to modification
+ * in the quantization process, the color in the final
+ * palette for each frame closest to the given color
+ * becomes the transparent color for that frame.
+ * May be set to null to indicate no transparent color.
+ *
+ * @param c Color to be treated as transparent on display.
+ */
+ public void setTransparent(Color c) {
+ transparent = c;
+ }
+
+ /**
+ * Adds next GIF frame. The frame is not written immediately, but is
+ * actually deferred until the next frame is received so that timing
+ * data can be inserted. Invoking <code>finish()</code> flushes all
+ * frames. If <code>setSize</code> was not invoked, the size of the
+ * first image is used for all subsequent frames.
+ *
+ * @param im BufferedImage containing frame to write.
+ * @return true if successful.
+ */
+ public boolean addFrame(BufferedImage im) {
+ if ((im == null) || !started) {
+ return false;
+ }
+ boolean ok = true;
+ try {
+ if (!sizeSet) {
+ // use first frame's size
+ setSize(im.getWidth(), im.getHeight());
+ }
+ image = im;
+ getImagePixels(); // convert to correct format if necessary
+ analyzePixels(); // build color table & map pixels
+ if (firstFrame) {
+ writeLSD(); // logical screen descriptior
+ writePalette(); // global color table
+ if (repeat >= 0) {
+ // use NS app extension to indicate reps
+ writeNetscapeExt();
+ }
+ }
+ writeGraphicCtrlExt(); // write graphic control extension
+ writeImageDesc(); // image descriptor
+ if (!firstFrame) {
+ writePalette(); // local color table
+ }
+ writePixels(); // encode and write pixel data
+ firstFrame = false;
+ } catch (IOException e) {
+ ok = false;
+ }
+
+ return ok;
+ }
+
+ /**
+ * Flushes any pending data and closes output file.
+ * If writing to an OutputStream, the stream is not
+ * closed.
+ */
+ public boolean finish() {
+ if (!started) {
+ return false;
+ }
+ boolean ok = true;
+ started = false;
+ try {
+ out.write(0x3b); // gif trailer
+ out.flush();
+ if (closeStream) {
+ out.close();
+ }
+ } catch (IOException e) {
+ ok = false;
+ }
+
+ // reset for subsequent use
+ transIndex = 0;
+ out = null;
+ image = null;
+ pixels = null;
+ indexedPixels = null;
+ colorTab = null;
+ closeStream = false;
+ firstFrame = true;
+
+ return ok;
+ }
+
+ /**
+ * Sets frame rate in frames per second. Equivalent to
+ * <code>setDelay(1000/fps)</code>.
+ *
+ * @param fps float frame rate (frames per second)
+ */
+ public void setFrameRate(float fps) {
+ if (fps != 0f) {
+ delay = Math.round(100f / fps);
+ }
+ }
+
+ /**
+ * Sets quality of color quantization (conversion of images
+ * to the maximum 256 colors allowed by the GIF specification).
+ * Lower values (minimum = 1) produce better colors, but slow
+ * processing significantly. 10 is the default, and produces
+ * good color mapping at reasonable speeds. Values greater
+ * than 20 do not yield significant improvements in speed.
+ *
+ * @param quality int greater than 0.
+ * @return
+ */
+ public void setQuality(int quality) {
+ if (quality < 1) {
+ quality = 1;
+ }
+ sample = quality;
+ }
+
+ /**
+ * Sets the GIF frame size. The default size is the
+ * size of the first frame added if this method is
+ * not invoked.
+ *
+ * @param w int frame width.
+ * @param h int frame width.
+ */
+ public void setSize(int w, int h) {
+ if (started && !firstFrame) {
+ return;
+ }
+ width = w;
+ height = h;
+ if (width < 1) {
+ width = 320;
+ }
+ if (height < 1) {
+ height = 240;
+ }
+ sizeSet = true;
+ }
+
+ /**
+ * Initiates GIF file creation on the given stream. The stream
+ * is not closed automatically.
+ *
+ * @param os OutputStream on which GIF images are written.
+ * @return false if initial write failed.
+ */
+ public boolean start(OutputStream os) {
+ if (os == null) {
+ return false;
+ }
+ boolean ok = true;
+ closeStream = false;
+ out = os;
+ try {
+ writeString("GIF89a"); // header
+ } catch (IOException e) {
+ ok = false;
+ }
+ started = ok;
+ return started;
+ }
+
+ /**
+ * Initiates writing of a GIF file with the specified name.
+ *
+ * @param file String containing output file name.
+ * @return false if open or initial write failed.
+ */
+ public boolean start(String file) {
+ boolean ok = true;
+ try {
+ out = new BufferedOutputStream(new FileOutputStream(file));
+ ok = start(out);
+ closeStream = true;
+ } catch (IOException e) {
+ ok = false;
+ }
+ started = ok;
+ return started;
+ }
+
+ /**
+ * Analyzes image colors and creates color map.
+ */
+ protected void analyzePixels() {
+ int len = pixels.length;
+ int nPix = len / 3;
+ indexedPixels = new byte[nPix];
+ NeuQuant nq = new NeuQuant(pixels, len, sample);
+ // initialize quantizer
+ colorTab = nq.process(); // create reduced palette
+ // convert map from BGR to RGB
+ for (int i = 0; i < colorTab.length; i += 3) {
+ byte temp = colorTab[i];
+ colorTab[i] = colorTab[i + 2];
+ colorTab[i + 2] = temp;
+ usedEntry[i / 3] = false;
+ }
+ // map image pixels to new palette
+ int k = 0;
+ for (int i = 0; i < nPix; i++) {
+ int index =
+ nq.map(pixels[k++] & 0xff,
+ pixels[k++] & 0xff,
+ pixels[k++] & 0xff);
+ usedEntry[index] = true;
+ indexedPixels[i] = (byte) index;
+ }
+ pixels = null;
+ colorDepth = 8;
+ palSize = 7;
+ // get closest match to transparent color if specified
+ if (transparent != null) {
+ transIndex = findClosest(transparent);
+ }
+ }
+
+ /**
+ * Returns index of palette color closest to c
+ *
+ */
+ protected int findClosest(Color c) {
+ if (colorTab == null) {
+ return -1;
+ }
+ int r = c.getRed();
+ int g = c.getGreen();
+ int b = c.getBlue();
+ int minpos = 0;
+ int dmin = 256 * 256 * 256;
+ int len = colorTab.length;
+ for (int i = 0; i < len; i += 3) {
+ int dr = r - (colorTab[i] & 0xff);
+ int dg = g - (colorTab[i + 1] & 0xff);
+ int db = b - (colorTab[i + 2] & 0xff);
+ int d = dr * dr + dg * dg + db * db;
+ int index = i + 2 / 3;
+ if (usedEntry[index] && (d < dmin)) {
+ dmin = d;
+ minpos = index;
+ }
+
+ }
+ return minpos;
+ }
+
+ /**
+ * Extracts image pixels into byte array "pixels"
+ */
+ protected void getImagePixels() {
+ int w = image.getWidth();
+ int h = image.getHeight();
+ int type = image.getType();
+ if ((w != width)
+ || (h != height)
+ || (type != BufferedImage.TYPE_3BYTE_BGR)) {
+ // create new image with right size/format
+ BufferedImage temp =
+ new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
+ Graphics2D g = temp.createGraphics();
+ g.drawImage(image, 0, 0, null);
+ image = temp;
+ }
+ pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
+ }
+
+ /**
+ * Writes Graphic Control Extension
+ */
+ protected void writeGraphicCtrlExt() throws IOException {
+ out.write(0x21); // extension introducer
+ out.write(0xf9); // GCE label
+ out.write(4); // data block size
+ int transp;
+ int disp;
+ if (transparent == null) {
+ transp = 0;
+ disp = 0; // dispose = no action
+ } else {
+ transp = 1;
+ disp = 2; // force clear if using transparent color
+ }
+ if (dispose >= 0) {
+ disp = dispose & 7; // user override
+ }
+ disp <<= 2;
+
+ // packed fields
+ out.write(0 | // 1:3 reserved
+ disp | // 4:6 disposal
+ 0 | // 7 user input - 0 = none
+ transp); // 8 transparency flag
+
+ writeShort(delay); // delay x 1/100 sec
+ out.write(transIndex); // transparent color index
+ out.write(0); // block terminator
+ }
+
+ /**
+ * Writes Image Descriptor
+ */
+ protected void writeImageDesc() throws IOException {
+ out.write(0x2c); // image separator
+ writeShort(0); // image position x,y = 0,0
+ writeShort(0);
+ writeShort(width); // image size
+ writeShort(height);
+ // packed fields
+ if (firstFrame) {
+ // no LCT - GCT is used for first (or only) frame
+ out.write(0);
+ } else {
+ // specify normal LCT
+ out.write(0x80 | // 1 local color table 1=yes
+ 0 | // 2 interlace - 0=no
+ 0 | // 3 sorted - 0=no
+ 0 | // 4-5 reserved
+ palSize); // 6-8 size of color table
+ }
+ }
+
+ /**
+ * Writes Logical Screen Descriptor
+ */
+ protected void writeLSD() throws IOException {
+ // logical screen size
+ writeShort(width);
+ writeShort(height);
+ // packed fields
+ out.write((0x80 | // 1 : global color table flag = 1 (gct used)
+ 0x70 | // 2-4 : color resolution = 7
+ 0x00 | // 5 : gct sort flag = 0
+ palSize)); // 6-8 : gct size
+
+ out.write(0); // background color index
+ out.write(0); // pixel aspect ratio - assume 1:1
+ }
+
+ /**
+ * Writes Netscape application extension to define
+ * repeat count.
+ */
+ protected void writeNetscapeExt() throws IOException {
+ out.write(0x21); // extension introducer
+ out.write(0xff); // app extension label
+ out.write(11); // block size
+ writeString("NETSCAPE" + "2.0"); // app id + auth code
+ out.write(3); // sub-block size
+ out.write(1); // loop sub-block id
+ writeShort(repeat); // loop count (extra iterations, 0=repeat forever)
+ out.write(0); // block terminator
+ }
+
+ /**
+ * Writes color table
+ */
+ protected void writePalette() throws IOException {
+ out.write(colorTab, 0, colorTab.length);
+ int n = (3 * 256) - colorTab.length;
+ for (int i = 0; i < n; i++) {
+ out.write(0);
+ }
+ }
+
+ /**
+ * Encodes and writes pixel data
+ */
+ protected void writePixels() throws IOException {
+ LZWEncoder encoder =
+ new LZWEncoder(width, height, indexedPixels, colorDepth);
+ encoder.encode(out);
+ }
+
+ /**
+ * Write 16-bit value to output stream, LSB first
+ */
+ protected void writeShort(int value) throws IOException {
+ out.write(value & 0xff);
+ out.write((value >> 8) & 0xff);
+ }
+
+ /**
+ * Writes string to output stream
+ */
+ protected void writeString(String s) throws IOException {
+ for (int i = 0; i < s.length(); i++) {
+ out.write((byte) s.charAt(i));
+ }
+ }
+}
Added:
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/GifDecoder.java
===================================================================
--- trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/GifDecoder.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/GifDecoder.java 2010-09-21
17:41:11 UTC (rev 19293)
@@ -0,0 +1,817 @@
+package org.ajax4jsf.resource.image.animatedgif;
+
+import java.net.*;
+import java.io.*;
+import java.util.*;
+import java.awt.*;
+import java.awt.image.*;
+
+/**
+ * Class GifDecoder - Decodes a GIF file into one or more frames.
+ * <br><pre>
+ * Example:
+ * GifDecoder d = new GifDecoder();
+ * d.read("sample.gif");
+ * int n = d.getFrameCount();
+ * for (int i = 0; i < n; i++) {
+ * BufferedImage frame = d.getFrame(i); // frame i
+ * int t = d.getDelay(i); // display duration of frame in milliseconds
+ * // do something with frame
+ * }
+ * </pre>
+ * No copyright asserted on the source code of this class. May be used for
+ * any purpose, however, refer to the Unisys LZW patent for any additional
+ * restrictions. Please forward any corrections to kweiner(a)fmsware.com.
+ *
+ * @author Kevin Weiner, FM Software; LZW decoder adapted from John Cristy's
ImageMagick.
+ * @version 1.03 November 2003
+ *
+ */
+
+public class GifDecoder {
+
+ /**
+ * File read status: No errors.
+ */
+ public static final int STATUS_OK = 0;
+
+ /**
+ * File read status: Error decoding file (may be partially decoded)
+ */
+ public static final int STATUS_FORMAT_ERROR = 1;
+
+ /**
+ * File read status: Unable to open source.
+ */
+ public static final int STATUS_OPEN_ERROR = 2;
+ protected static final int MAXSTACKSIZE = 4096;
+ protected BufferedInputStream in;
+ protected int status;
+
+ protected int width; // full image width
+ protected int height; // full image height
+ protected boolean gctFlag; // global color table used
+ protected int gctSize; // size of global color table
+ protected int loopCount = 1; // iterations; 0 = repeat forever
+
+ protected int[] gct; // global color table
+ protected int[] lct; // local color table
+ protected int[] act; // active color table
+
+ protected int bgIndex; // background color index
+ protected int bgColor; // background color
+ protected int lastBgColor; // previous bg color
+ protected int pixelAspect; // pixel aspect ratio
+
+ protected boolean lctFlag; // local color table flag
+ protected boolean interlace; // interlace flag
+ protected int lctSize; // local color table size
+
+ protected int ix;
+ protected int iy;
+ protected int iw;
+ protected int ih; // current image rectangle
+ protected Rectangle lastRect; // last image rect
+ protected BufferedImage image; // current frame
+ protected BufferedImage lastImage; // previous frame
+
+ protected byte[] block = new byte[256]; // current data block
+ protected int blockSize = 0; // block size
+
+ // last graphic control extension info
+ protected int dispose = 0;
+ // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev
+ protected int lastDispose = 0;
+ protected boolean transparency = false; // use transparent color
+ protected int delay = 0; // delay in milliseconds
+ protected int transIndex; // transparent color index
+
+
+ // max decoder pixel stack size
+
+ // LZW decoder working arrays
+ protected short[] prefix;
+ protected byte[] suffix;
+ protected byte[] pixelStack;
+ protected byte[] pixels;
+
+ protected ArrayList frames; // frames read from current file
+ protected int frameCount;
+
+ static class GifFrame {
+ private BufferedImage image;
+ private int delay;
+ public GifFrame(BufferedImage im, int del) {
+ image = im;
+ delay = del;
+ }
+
+ public BufferedImage getImage() {
+ return image;
+ }
+
+ public int getDelay() {
+ return delay;
+ }
+ }
+
+ /**
+ * Gets display duration for specified frame.
+ *
+ * @param n int index of frame
+ * @return delay in milliseconds
+ */
+ public int getDelay(int n) {
+ //
+ delay = -1;
+ if ((n >= 0) && (n < frameCount)) {
+ delay = ((GifFrame) frames.get(n)).delay;
+ }
+ return delay;
+ }
+
+ /**
+ * Gets the number of frames read from file.
+ * @return frame count
+ */
+ public int getFrameCount() {
+ return frameCount;
+ }
+
+ /**
+ * Gets the first (or only) image read.
+ *
+ * @return BufferedImage containing first frame, or null if none.
+ */
+ public BufferedImage getImage() {
+ return getFrame(0);
+ }
+
+ /**
+ * Gets the "Netscape" iteration count, if any.
+ * A count of 0 means repeat indefinitiely.
+ *
+ * @return iteration count if one was specified, else 1.
+ */
+ public int getLoopCount() {
+ return loopCount;
+ }
+
+ /**
+ * Creates new frame image from current data (and previous
+ * frames as specified by their disposition codes).
+ */
+ protected void setPixels() {
+ // expose destination image's pixels as int array
+ int[] dest =
+ ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
+
+ // fill in starting image contents based on last image's dispose code
+ if (lastDispose > 0) {
+ if (lastDispose == 3) {
+ // use image before last
+ int n = frameCount - 2;
+ if (n > 0) {
+ lastImage = getFrame(n - 1);
+ } else {
+ lastImage = null;
+ }
+ }
+
+ if (lastImage != null) {
+ int[] prev =
+ ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData();
+ System.arraycopy(prev, 0, dest, 0, width * height);
+ // copy pixels
+
+ if (lastDispose == 2) {
+ // fill last image rect area with background color
+ Graphics2D g = image.createGraphics();
+ Color c = null;
+ if (transparency) {
+ c = new Color(0, 0, 0, 0); // assume background is transparent
+ } else {
+ c = new Color(lastBgColor); // use given background color
+ }
+ g.setColor(c);
+ g.setComposite(AlphaComposite.Src); // replace area
+ g.fill(lastRect);
+ g.dispose();
+ }
+ }
+ }
+
+ // copy each source line to the appropriate place in the destination
+ int pass = 1;
+ int inc = 8;
+ int iline = 0;
+ for (int i = 0; i < ih; i++) {
+ int line = i;
+ if (interlace) {
+ if (iline >= ih) {
+ pass++;
+ switch (pass) {
+ case 2 :
+ iline = 4;
+ break;
+ case 3 :
+ iline = 2;
+ inc = 4;
+ break;
+ case 4 :
+ iline = 1;
+ inc = 2;
+ break;
+ default:
+ break;
+ }
+ }
+ line = iline;
+ iline += inc;
+ }
+ line += iy;
+ if (line < height) {
+ int k = line * width;
+ int dx = k + ix; // start of line in dest
+ int dlim = dx + iw; // end of dest line
+ if ((k + width) < dlim) {
+ dlim = k + width; // past dest edge
+ }
+ int sx = i * iw; // start of line in source
+ while (dx < dlim) {
+ // map color and insert in destination
+ int index = ((int) pixels[sx++]) & 0xff;
+ int c = act[index];
+ if (c != 0) {
+ dest[dx] = c;
+ }
+ dx++;
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the image contents of frame n.
+ *
+ * @return BufferedImage representation of frame, or null if n is invalid.
+ */
+ public BufferedImage getFrame(int n) {
+ BufferedImage im = null;
+ if ((n >= 0) && (n < frameCount)) {
+ im = ((GifFrame) frames.get(n)).image;
+ }
+ return im;
+ }
+
+ /**
+ * Gets image size.
+ *
+ * @return GIF image dimensions
+ */
+ public Dimension getFrameSize() {
+ return new Dimension(width, height);
+ }
+
+ /**
+ * Reads GIF image from stream
+ *
+ * @param BufferedInputStream containing GIF file.
+ * @return read status code (0 = no errors)
+ */
+ public int read(BufferedInputStream is) {
+ init();
+ if (is != null) {
+ in = is;
+ readHeader();
+ if (!err()) {
+ readContents();
+ if (frameCount < 0) {
+ status = STATUS_FORMAT_ERROR;
+ }
+ }
+ } else {
+ status = STATUS_OPEN_ERROR;
+ }
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return status;
+ }
+
+ /**
+ * Reads GIF image from stream
+ *
+ * @param InputStream containing GIF file.
+ * @return read status code (0 = no errors)
+ */
+ public int read(InputStream is) {
+ init();
+ if (is != null) {
+ if (!(is instanceof BufferedInputStream)) {
+ is = new BufferedInputStream(is);
+ }
+ in = (BufferedInputStream) is;
+ readHeader();
+ if (!err()) {
+ readContents();
+ if (frameCount < 0) {
+ status = STATUS_FORMAT_ERROR;
+ }
+ }
+ } else {
+ status = STATUS_OPEN_ERROR;
+ }
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return status;
+ }
+
+ /**
+ * Reads GIF file from specified file/URL source
+ * (URL assumed if name contains ":/" or "file:")
+ *
+ * @param name String containing source
+ * @return read status code (0 = no errors)
+ */
+ public int read(String name) {
+ status = STATUS_OK;
+ try {
+ name = name.trim().toLowerCase();
+ if ((name.indexOf("file:") >= 0) ||
+ (name.indexOf(":/") > 0)) {
+ URL url = new URL(name);
+ in = new BufferedInputStream(url.openStream());
+ } else {
+ in = new BufferedInputStream(new FileInputStream(name));
+ }
+ status = read(in);
+ } catch (IOException e) {
+ status = STATUS_OPEN_ERROR;
+ }
+
+ return status;
+ }
+
+ /**
+ * Decodes LZW image data into pixel array.
+ * Adapted from John Cristy's ImageMagick.
+ */
+ protected void decodeImageData() {
+ int nullCode = -1;
+ int npix = iw * ih;
+ int available;
+ int clear;
+ int codeMask;
+ int codeSize;
+ int endOfInformation;
+ int inCode;
+ int oldCode;
+ int bits;
+ int code;
+ int count;
+ int i;
+ int datum;
+ int dataSize;
+ int first;
+ int top;
+ int bi;
+ int pi;
+
+ if ((pixels == null) || (pixels.length < npix)) {
+ pixels = new byte[npix]; // allocate new pixel array
+ }
+ if (prefix == null) {
+ prefix = new short[MAXSTACKSIZE];
+ }
+ if (suffix == null) {
+ suffix = new byte[MAXSTACKSIZE];
+ }
+ if (pixelStack == null) {
+ pixelStack = new byte[MAXSTACKSIZE + 1];
+ }
+
+ // Initialize GIF data stream decoder.
+
+ dataSize = read();
+ clear = 1 << dataSize;
+ endOfInformation = clear + 1;
+ available = clear + 2;
+ oldCode = nullCode;
+ codeSize = dataSize + 1;
+ codeMask = (1 << codeSize) - 1;
+ for (code = 0; code < clear; code++) {
+ prefix[code] = 0;
+ suffix[code] = (byte) code;
+ }
+
+ // Decode GIF pixel stream.
+ bi = 0;
+ datum = 0;
+ bits = 0;
+ count = 0;
+ first = 0;
+ top = 0;
+ pi = 0;
+ bi = 0;
+
+ for (i = 0; i < npix;) {
+ if (top == 0) {
+ if (bits < codeSize) {
+ // Load bytes until there are enough bits for a code.
+ if (count == 0) {
+ // Read a new data block.
+ count = readBlock();
+ if (count <= 0) {
+ break;
+ }
+ bi = 0;
+ }
+ datum += (((int) block[bi]) & 0xff) << bits;
+ bits += 8;
+ bi++;
+ count--;
+ continue;
+ }
+
+ // Get the next code.
+
+ code = datum & codeMask;
+ datum >>= codeSize;
+ bits -= codeSize;
+
+ // Interpret the code
+
+ if ((code > available) || (code == endOfInformation)) {
+ break;
+ }
+ if (code == clear) {
+ // Reset decoder.
+ codeSize = dataSize + 1;
+ codeMask = (1 << codeSize) - 1;
+ available = clear + 2;
+ oldCode = nullCode;
+ continue;
+ }
+ if (oldCode == nullCode) {
+ pixelStack[top++] = suffix[code];
+ oldCode = code;
+ first = code;
+ continue;
+ }
+ inCode = code;
+ if (code == available) {
+ pixelStack[top++] = (byte) first;
+ code = oldCode;
+ }
+ while (code > clear) {
+ pixelStack[top++] = suffix[code];
+ code = prefix[code];
+ }
+ first = ((int) suffix[code]) & 0xff;
+
+ // Add a new string to the string table,
+
+ if (available >= MAXSTACKSIZE) {
+ break;
+ }
+ pixelStack[top++] = (byte) first;
+ prefix[available] = (short) oldCode;
+ suffix[available] = (byte) first;
+ available++;
+ if (((available & codeMask) == 0)
+ && (available < MAXSTACKSIZE)) {
+ codeSize++;
+ codeMask += available;
+ }
+ oldCode = inCode;
+ }
+
+ // Pop a pixel off the pixel stack.
+
+ top--;
+ pixels[pi++] = pixelStack[top];
+ i++;
+ }
+
+ for (i = pi; i < npix; i++) {
+ pixels[i] = 0; // clear missing pixels
+ }
+
+ }
+
+ /**
+ * Returns true if an error was encountered during reading/decoding
+ */
+ protected boolean err() {
+ return status != STATUS_OK;
+ }
+
+ /**
+ * Initializes or re-initializes reader
+ */
+ protected void init() {
+ status = STATUS_OK;
+ frameCount = 0;
+ frames = new ArrayList();
+ gct = null;
+ lct = null;
+ }
+
+ /**
+ * Reads a single byte from the input stream.
+ */
+ protected int read() {
+ int curByte = 0;
+ try {
+ curByte = in.read();
+ } catch (IOException e) {
+ status = STATUS_FORMAT_ERROR;
+ }
+ return curByte;
+ }
+
+ /**
+ * Reads next variable length block from input.
+ *
+ * @return number of bytes stored in "buffer"
+ */
+ protected int readBlock() {
+ blockSize = read();
+ int n = 0;
+ if (blockSize > 0) {
+ try {
+ int count = 0;
+ while (n < blockSize) {
+ count = in.read(block, n, blockSize - n);
+ if (count == -1) {
+ break;
+ }
+ n += count;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ if (n < blockSize) {
+ status = STATUS_FORMAT_ERROR;
+ }
+ }
+ return n;
+ }
+
+ /**
+ * Reads color table as 256 RGB integer values
+ *
+ * @param ncolors int number of colors to read
+ * @return int array containing 256 colors (packed ARGB with full alpha)
+ */
+ protected int[] readColorTable(int ncolors) {
+ int nbytes = 3 * ncolors;
+ int[] tab = null;
+ byte[] c = new byte[nbytes];
+ int n = 0;
+ try {
+ n = in.read(c);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ if (n < nbytes) {
+ status = STATUS_FORMAT_ERROR;
+ } else {
+ tab = new int[256]; // max size to avoid bounds checks
+ int i = 0;
+ int j = 0;
+ while (i < ncolors) {
+ int r = ((int) c[j++]) & 0xff;
+ int g = ((int) c[j++]) & 0xff;
+ int b = ((int) c[j++]) & 0xff;
+ tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
+ }
+ }
+ return tab;
+ }
+
+ /**
+ * Main file parser. Reads GIF content blocks.
+ */
+ protected void readContents() {
+ // read GIF file content blocks
+ boolean done = false;
+ while (!(done || err())) {
+ int code = read();
+ switch (code) {
+
+ case 0x2C : // image separator
+ readImage();
+ break;
+
+ case 0x21 : // extension
+ code = read();
+ switch (code) {
+ case 0xf9 : // graphics control extension
+ readGraphicControlExt();
+ break;
+
+ case 0xff : // application extension
+ readBlock();
+ String app = "";
+ for (int i = 0; i < 11; i++) {
+ app += (char) block[i];
+ }
+ if (app.equals("NETSCAPE2.0")) {
+ readNetscapeExt();
+ } else {
+ skip();
+ }// don't care
+ break;
+
+ default : // uninteresting extension
+ skip();
+ }
+ break;
+
+ case 0x3b : // terminator
+ done = true;
+ break;
+
+ case 0x00 : // bad byte, but keep going and see what happens
+ break;
+
+ default :
+ status = STATUS_FORMAT_ERROR;
+ }
+ }
+ }
+
+ /**
+ * Reads Graphics Control Extension values
+ */
+ protected void readGraphicControlExt() {
+ read(); // block size
+ int packed = read(); // packed fields
+ dispose = (packed & 0x1c) >> 2; // disposal method
+ if (dispose == 0) {
+ dispose = 1; // elect to keep old image if discretionary
+ }
+ transparency = (packed & 1) != 0;
+ delay = readShort() * 10; // delay in milliseconds
+ transIndex = read(); // transparent color index
+ read(); // block terminator
+ }
+
+ /**
+ * Reads GIF file header information.
+ */
+ protected void readHeader() {
+ String id = "";
+ for (int i = 0; i < 6; i++) {
+ id += (char) read();
+ }
+ if (!id.startsWith("GIF")) {
+ status = STATUS_FORMAT_ERROR;
+ return;
+ }
+
+ readLSD();
+ if (gctFlag && !err()) {
+ gct = readColorTable(gctSize);
+ bgColor = gct[bgIndex];
+ }
+ }
+
+ /**
+ * Reads next frame image
+ */
+ protected void readImage() {
+ ix = readShort(); // (sub)image position & size
+ iy = readShort();
+ iw = readShort();
+ ih = readShort();
+
+ int packed = read();
+ lctFlag = (packed & 0x80) != 0; // 1 - local color table flag
+ interlace = (packed & 0x40) != 0; // 2 - interlace flag
+ // 3 - sort flag
+ // 4-5 - reserved
+ lctSize = 2 << (packed & 7); // 6-8 - local color table size
+
+ if (lctFlag) {
+ lct = readColorTable(lctSize); // read table
+ act = lct; // make local table active
+ } else {
+ act = gct; // make global table active
+ if (bgIndex == transIndex) {
+ bgColor = 0;
+ }
+ }
+ int save = 0;
+ if (transparency) {
+ save = act[transIndex];
+ act[transIndex] = 0; // set transparent color if specified
+ }
+
+ if (act == null) {
+ status = STATUS_FORMAT_ERROR; // no color table defined
+ }
+
+ if (err()) {
+ return;
+ }
+
+ decodeImageData(); // decode pixel data
+ skip();
+
+ if (err()) {
+ return;
+ }
+
+ frameCount++;
+
+ // create new image to receive frame data
+ image =
+ new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
+
+ setPixels(); // transfer pixel data to image
+
+ frames.add(new GifFrame(image, delay)); // add image to frame list
+
+ if (transparency) {
+ act[transIndex] = save;
+ }
+ resetFrame();
+
+ }
+
+ /**
+ * Reads Logical Screen Descriptor
+ */
+ protected void readLSD() {
+
+ // logical screen size
+ width = readShort();
+ height = readShort();
+
+ // packed fields
+ int packed = read();
+ gctFlag = (packed & 0x80) != 0; // 1 : global color table flag
+ // 2-4 : color resolution
+ // 5 : gct sort flag
+ gctSize = 2 << (packed & 7); // 6-8 : gct size
+
+ bgIndex = read(); // background color index
+ pixelAspect = read(); // pixel aspect ratio
+ }
+
+ /**
+ * Reads Netscape extenstion to obtain iteration count
+ */
+ protected void readNetscapeExt() {
+ do {
+ readBlock();
+ if (block[0] == 1) {
+ // loop count sub-block
+ int b1 = ((int) block[1]) & 0xff;
+ int b2 = ((int) block[2]) & 0xff;
+ loopCount = (b2 << 8) | b1;
+ }
+ } while ((blockSize > 0) && !err());
+ }
+
+ /**
+ * Reads next 16-bit value, LSB first
+ */
+ protected int readShort() {
+ // read 16-bit value, LSB first
+ return read() | (read() << 8);
+ }
+
+ /**
+ * Resets frame state for reading next image.
+ */
+ protected void resetFrame() {
+ lastDispose = dispose;
+ lastRect = new Rectangle(ix, iy, iw, ih);
+ lastImage = image;
+ lastBgColor = bgColor;
+ int dispose = 0;
+ boolean transparency = false;
+ int delay = 0;
+ lct = null;
+ }
+
+ /**
+ * Skips variable length blocks up to and including
+ * next zero length block.
+ */
+ protected void skip() {
+ do {
+ readBlock();
+ } while ((blockSize > 0) && !err());
+ }
+}
Added:
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/LZWEncoder.java
===================================================================
--- trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/LZWEncoder.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/LZWEncoder.java 2010-09-21
17:41:11 UTC (rev 19293)
@@ -0,0 +1,291 @@
+package org.ajax4jsf.resource.image.animatedgif;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+//==============================================================================
+// Adapted from Jef Poskanzer's Java port by way of J. M. G. Elliott.
+// K Weiner 12/00
+
+class LZWEncoder {
+ static final int BITS = 12;
+ static final int HSIZE = 5003;
+ private static final int EOF = -1;
+ private int imgW;
+ private int imgH;
+ private byte[] pixAry;
+ private int initCodeSize;
+ private int remaining;
+ private int curPixel;
+
+ private int nBits; // number of bits/code
+ private int maxbits = BITS; // user settable max # bits/code
+ private int maxcode; // maximum code, given n_bits
+ private int maxmaxcode = 1 << BITS; // should NEVER generate this code
+
+ private int[] htab = new int[HSIZE];
+ private int[] codetab = new int[HSIZE];
+
+ private int hsize = HSIZE; // for dynamic table sizing
+
+ private int freeEnt = 0; // first unused entry
+
+ // block compression parameters -- after all codes are used up,
+ // and compression rate changes, start over.
+ private boolean clearFlg = false;
+
+ // Algorithm: use open addressing double hashing (no chaining) on the
+ // prefix code / next character combination. We do a variant of Knuth's
+ // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
+ // secondary probe. Here, the modular division first probe is gives way
+ // to a faster exclusive-or manipulation. Also do block compression with
+ // an adaptive reset, whereby the code table is cleared when the compression
+ // ratio decreases, but after the table fills. The variable-length output
+ // codes are re-sized at this point, and a special CLEAR code is generated
+ // for the decompressor. Late addition: construct the table according to
+ // file size for noticeable speed improvement on small files. Please direct
+ // questions about this implementation to ames!jaw.
+
+ private int gInitBits;
+
+ private int clearCode;
+ private int eOFCode;
+
+ // output
+ //
+ // Output the given code.
+ // Inputs:
+ // code: A n_bits-bit integer. If == -1, then EOF. This assumes
+ // that n_bits =< wordsize - 1.
+ // Outputs:
+ // Outputs code to the file.
+ // Assumptions:
+ // Chars are 8 bits long.
+ // Algorithm:
+ // Maintain a BITS character long buffer (so that 8 codes will
+ // fit in it exactly). Use the VAX insv instruction to insert each
+ // code in turn. When the buffer fills up empty it and start over.
+
+ private int curAccum = 0;
+ private int curBits = 0;
+ private int aCount;
+
+ // Define the storage for the packet accumulator
+ private byte[] accum = new byte[256];
+
+ private int[] masks =
+ {
+ 0x0000,
+ 0x0001,
+ 0x0003,
+ 0x0007,
+ 0x000F,
+ 0x001F,
+ 0x003F,
+ 0x007F,
+ 0x00FF,
+ 0x01FF,
+ 0x03FF,
+ 0x07FF,
+ 0x0FFF,
+ 0x1FFF,
+ 0x3FFF,
+ 0x7FFF,
+ 0xFFFF
+ };
+
+ LZWEncoder(int width, int height, byte[] pixels, int colorDepth) {
+ imgW = width;
+ imgH = height;
+ pixAry = pixels;
+ initCodeSize = Math.max(2, colorDepth);
+ }
+
+ // Add a character to the end of the current packet, and if it is 254
+ // characters, flush the packet to disk.
+ void charOut(byte c, OutputStream outs) throws IOException {
+ accum[aCount++] = c;
+ if (aCount >= 254) {
+ flushChar(outs);
+ }
+ }
+
+ // Clear out the hash table
+
+ // table clear for block compress
+ void clBlock(OutputStream outs) throws IOException {
+ clHash(hsize);
+ freeEnt = clearCode + 2;
+ clearFlg = true;
+
+ output(clearCode, outs);
+ }
+
+ // reset code table
+ void clHash(int hsize) {
+ for (int i = 0; i < hsize; ++i) {
+ htab[i] = -1;
+ }
+ }
+
+ void compress(int initBits, OutputStream outs) throws IOException {
+ int fcode;
+ int i /* = 0 */;
+ int c;
+ int ent;
+ int disp;
+ int hsizeReg;
+ int hshift;
+
+ // Set up the globals: g_init_bits - initial number of bits
+ gInitBits = initBits;
+
+ // Set up the necessary values
+ clearFlg = false;
+ nBits = gInitBits;
+ maxcode = maxcode(nBits);
+
+ clearCode = 1 << (initBits - 1);
+ eOFCode = clearCode + 1;
+ freeEnt = clearCode + 2;
+
+ aCount = 0; // clear packet
+
+ ent = nextPixel();
+
+ hshift = 0;
+ for (fcode = hsize; fcode < 65536; fcode *= 2) {
+ ++hshift;
+ }
+ hshift = 8 - hshift; // set hash code range bound
+
+ hsizeReg = hsize;
+ clHash(hsizeReg); // clear hash table
+
+ output(clearCode, outs);
+
+ outer_loop :
+ while ((c = nextPixel()) != EOF) {
+ fcode = (c << maxbits) + ent;
+ i = (c << hshift) ^ ent; // xor hashing
+
+ if (htab[i] == fcode) {
+ ent = codetab[i];
+ continue;
+ } else if (htab[i] >= 0) {
+ disp = hsizeReg - i; // secondary hash (after G. Knott)
+ if (i == 0) {
+ disp = 1;
+ }
+ do {
+ i -= disp;
+ if (i < 0) {
+ i += hsizeReg;
+ }
+
+ if (htab[i] == fcode) {
+ ent = codetab[i];
+ continue outer_loop;
+ }
+ } while (htab[i] >= 0);
+ }
+ output(ent, outs);
+ ent = c;
+ if (freeEnt < maxmaxcode) {
+ codetab[i] = freeEnt++; // code -> hashtable
+ htab[i] = fcode;
+ } else {
+ clBlock(outs);
+ }
+ }
+ // Put out the final code.
+ output(ent, outs);
+ output(eOFCode, outs);
+ }
+
+ //----------------------------------------------------------------------------
+ void encode(OutputStream os) throws IOException {
+ os.write(initCodeSize); // write "initial code size" byte
+
+ remaining = imgW * imgH; // reset navigation variables
+ curPixel = 0;
+
+ compress(initCodeSize + 1, os); // compress and write the pixel data
+
+ os.write(0); // write block terminator
+ }
+
+ // Flush the packet to disk, and reset the accumulator
+ void flushChar(OutputStream outs) throws IOException {
+ if (aCount > 0) {
+ outs.write(aCount);
+ outs.write(accum, 0, aCount);
+ aCount = 0;
+ }
+ }
+
+ final int maxcode(int nBits) {
+ return (1 << nBits) - 1;
+ }
+
+ //----------------------------------------------------------------------------
+ // Return the next pixel from the image
+ //----------------------------------------------------------------------------
+ private int nextPixel() {
+ if (remaining == 0) {
+ return EOF;
+ }
+
+ --remaining;
+
+ byte pix = pixAry[curPixel++];
+
+ return pix & 0xff;
+ }
+
+ void output(int code, OutputStream outs) throws IOException {
+ curAccum &= masks[curBits];
+
+ if (curBits > 0) {
+ curAccum |= (code << curBits);
+ } else {
+ curAccum = code;
+ }
+
+ curBits += nBits;
+
+ while (curBits >= 8) {
+ charOut((byte) (curAccum & 0xff), outs);
+ curAccum >>= 8;
+ curBits -= 8;
+ }
+
+ // If the next entry is going to be too big for the code size,
+ // then increase it, if possible.
+ if (freeEnt > maxcode || clearFlg) {
+ if (clearFlg) {
+ nBits = gInitBits;
+ maxcode = maxcode(nBits);
+ clearFlg = false;
+ } else {
+ ++nBits;
+ if (nBits == maxbits) {
+ maxcode = maxmaxcode;
+ } else {
+ maxcode = maxcode(nBits);
+ }
+ }
+ }
+
+ if (code == eOFCode) {
+ // At EOF, write the rest of the buffer.
+ while (curBits > 0) {
+ charOut((byte) (curAccum & 0xff), outs);
+ curAccum >>= 8;
+ curBits -= 8;
+ }
+
+ flushChar(outs);
+ }
+ }
+}
Added:
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/NeuQuant.java
===================================================================
--- trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/NeuQuant.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/ajax4jsf/resource/image/animatedgif/NeuQuant.java 2010-09-21
17:41:11 UTC (rev 19293)
@@ -0,0 +1,519 @@
+/* NeuQuant Neural-Net Quantization Algorithm
+ * ------------------------------------------
+ *
+ * Copyright (c) 1994 Anthony Dekker
+ *
+ * NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.
+ * See "Kohonen neural networks for optimal colour quantization"
+ * in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367.
+ * for a discussion of the algorithm.
+ *
+ * Any party obtaining a copy of these files from the author, directly or
+ * indirectly, is granted, free of charge, a full and unrestricted irrevocable,
+ * world-wide, paid up, royalty-free, nonexclusive right and license to deal
+ * in this software and documentation files (the "Software"), including
without
+ * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons who receive
+ * copies from any such party to do so, with the only requirement being
+ * that this copyright notice remain intact.
+ */
+package org.ajax4jsf.resource.image.animatedgif;
+
+// Ported to Java 12/00 K Weiner
+
+public class NeuQuant {
+
+ protected static final int NETSIZE = 256; /* number of colours used */
+
+ /* four primes near 500 - assume no image has a length so large */
+ /* that it is divisible by all four primes */
+ protected static final int PRIME1 = 499;
+ protected static final int PRIME2 = 491;
+ protected static final int PRIME3 = 487;
+ protected static final int PRIME4 = 503;
+
+ protected static final int MINPICTUREBYTES = (3 * PRIME4);
+ /* minimum size for input image */
+
+ /* Program Skeleton
+ ----------------
+ [select samplefac in range 1..30]
+ [read image from input file]
+ pic = (unsigned char*) malloc(3*width*height);
+ initnet(pic,3*width*height,samplefac);
+ learn();
+ unbiasnet();
+ [write output image header, using writecolourmap(f)]
+ inxbuild();
+ write output image using inxsearch(b,g,r) */
+
+ /* Network Definitions
+ ------------------- */
+
+ protected static final int MAXNETPOS = (NETSIZE - 1);
+ protected static final int NETBIASSHIFT = 4; /* bias for colour values */
+ protected static final int NCYCLES = 100; /* no. of learning cycles */
+
+ /* defs for freq and bias */
+ protected static final int INTBIASSHIFT = 16; /* bias for fractions */
+ protected static final int INTBIAS = (((int) 1) << INTBIASSHIFT);
+ protected static final int GAMMASHIFT = 10; /* gamma = 1024 */
+ protected static final int GAMMA = (((int) 1) << GAMMASHIFT);
+ protected static final int BETASHIFT = 10;
+ protected static final int BETA = (INTBIAS >> BETASHIFT); /* beta = 1/1024 */
+ protected static final int BETAGAMMA =
+ (INTBIAS << (GAMMASHIFT - BETASHIFT));
+
+ /* defs for decreasing radius factor */
+ protected static final int INITRAD = (NETSIZE >> 3); /* for 256 cols, radius
starts */
+ protected static final int RADIUSBIASSHIFT = 6; /* at 32.0 biased by 6 bits */
+ protected static final int RADIUSBIAS = (((int) 1) << RADIUSBIASSHIFT);
+ protected static final int INITRADIUS = (INITRAD * RADIUSBIAS); /* and decreases by a
*/
+ protected static final int RADIUSDEC = 30; /* factor of 1/30 each cycle */
+
+ /* defs for decreasing alpha factor */
+ protected static final int ALPHABIASSHIFT = 10; /* alpha starts at 1.0 */
+ protected static final int INITALPHA = (((int) 1) << ALPHABIASSHIFT);
+
+ protected static final int RADBIASSHIFT = 8;
+ protected static final int RADBIAS = (((int) 1) << RADBIASSHIFT);
+ protected static final int ALPHARADBSHIFT = (ALPHABIASSHIFT + RADBIASSHIFT);
+ protected static final int ALPHARADBIAS = (((int) 1) << ALPHARADBSHIFT);
+
+ protected int alphadec; /* biased by 10 bits */
+
+ /* radbias and alpharadbias used for radpower calculation */
+
+
+ /* Types and Global Variables
+ -------------------------- */
+
+ protected byte[] thepicture; /* the input image itself */
+ protected int lengthcount; /* lengthcount = H*W*3 */
+
+ protected int samplefac; /* sampling factor 1..30 */
+
+ // typedef int pixel[4]; /* BGRc */
+ protected int[][] network; /* the network itself - [netsize][4] */
+
+ protected int[] netindex = new int[256];
+ /* for network lookup - really 256 */
+
+ protected int[] bias = new int[NETSIZE];
+ /* bias and freq arrays for learning */
+ protected int[] freq = new int[NETSIZE];
+ protected int[] radpower = new int[INITRAD];
+ /* radpower for precomputation */
+
+ /* Initialise network in range (0,0,0) to (255,255,255) and set parameters
+ ----------------------------------------------------------------------- */
+ public NeuQuant(byte[] thepic, int len, int sample) {
+
+ int i;
+ int[] p;
+
+ thepicture = thepic;
+ lengthcount = len;
+ samplefac = sample;
+
+ network = new int[NETSIZE][];
+ for (i = 0; i < NETSIZE; i++) {
+ network[i] = new int[4];
+ p = network[i];
+ p[0] = (i << (NETBIASSHIFT + 8)) / NETSIZE;
+ p[1] = (i << (NETBIASSHIFT + 8)) / NETSIZE;
+ p[2] = (i << (NETBIASSHIFT + 8)) / NETSIZE;
+ freq[i] = INTBIAS / NETSIZE; /* 1/netsize */
+ bias[i] = 0;
+ }
+ }
+
+ public byte[] colorMap() {
+ byte[] map = new byte[3 * NETSIZE];
+ int[] index = new int[NETSIZE];
+ for (int i = 0; i < NETSIZE; i++) {
+ index[network[i][3]] = i;
+ }
+ int k = 0;
+ for (int i = 0; i < NETSIZE; i++) {
+ int j = index[i];
+ map[k++] = (byte) (network[j][0]);
+ map[k++] = (byte) (network[j][1]);
+ map[k++] = (byte) (network[j][2]);
+ }
+ return map;
+ }
+
+ /* Insertion sort of network and building of netindex[0..255] (to do after unbias)
+ -------------------------------------------------------------------------------
*/
+ public void inxbuild() {
+
+ int i;
+ int j;
+ int smallpos;
+ int smallval;
+ int[] p;
+ int[] q;
+ int previouscol;
+ int startpos;
+
+ previouscol = 0;
+ startpos = 0;
+ for (i = 0; i < NETSIZE; i++) {
+ p = network[i];
+ smallpos = i;
+ smallval = p[1]; /* index on g */
+ /* find smallest in i..netsize-1 */
+ for (j = i + 1; j < NETSIZE; j++) {
+ q = network[j];
+ if (q[1] < smallval) { /* index on g */
+ smallpos = j;
+ smallval = q[1]; /* index on g */
+ }
+ }
+ q = network[smallpos];
+ /* swap p (i) and q (smallpos) entries */
+ if (i != smallpos) {
+ j = q[0];
+ q[0] = p[0];
+ p[0] = j;
+ j = q[1];
+ q[1] = p[1];
+ p[1] = j;
+ j = q[2];
+ q[2] = p[2];
+ p[2] = j;
+ j = q[3];
+ q[3] = p[3];
+ p[3] = j;
+ }
+ /* smallval entry is now in position i */
+ if (smallval != previouscol) {
+ netindex[previouscol] = (startpos + i) >> 1;
+ for (j = previouscol + 1; j < smallval; j++) {
+ netindex[j] = i;
+ }
+ previouscol = smallval;
+ startpos = i;
+ }
+ }
+ netindex[previouscol] = (startpos + MAXNETPOS) >> 1;
+ for (j = previouscol + 1; j < 256; j++) {
+ netindex[j] = MAXNETPOS; /* really 256 */
+ }
+ }
+
+ /* Main Learning Loop
+ ------------------ */
+ public void learn() {
+
+ int i;
+ int j;
+ int b;
+ int g;
+ int r;
+ int radius;
+ int rad;
+ int alpha;
+ int step;
+ int delta;
+ int samplepixels;
+ byte[] p;
+ int pix;
+ int lim;
+
+ if (lengthcount < MINPICTUREBYTES){
+ samplefac = 1;
+ }
+
+ alphadec = 30 + ((samplefac - 1) / 3);
+ p = thepicture;
+ pix = 0;
+ lim = lengthcount;
+ samplepixels = lengthcount / (3 * samplefac);
+ delta = samplepixels / NCYCLES;
+ alpha = INITALPHA;
+ radius = INITRADIUS;
+
+ rad = radius >> RADIUSBIASSHIFT;
+ if (rad <= 1) {
+ rad = 0;
+ }
+ for (i = 0; i < rad; i++) {
+ radpower[i] =
+ alpha * (((rad * rad - i * i) * RADBIAS) / (rad * rad));
+ }
+
+ //fprintf(stderr,"beginning 1D learning: initial radius=%d\n", rad);
+
+ if (lengthcount < MINPICTUREBYTES) {
+ step = 3;
+ } else if ((lengthcount % PRIME1) != 0) {
+ step = 3 * PRIME1;
+ } else {
+ if ((lengthcount % PRIME2) != 0) {
+ step = 3 * PRIME2;
+ } else {
+ if ((lengthcount % PRIME3) != 0) {
+ step = 3 * PRIME3;
+ } else {
+ step = 3 * PRIME4;
+ }
+ }
+ }
+
+ i = 0;
+ while (i < samplepixels) {
+ b = (p[pix + 0] & 0xff) << NETBIASSHIFT;
+ g = (p[pix + 1] & 0xff) << NETBIASSHIFT;
+ r = (p[pix + 2] & 0xff) << NETBIASSHIFT;
+ j = contest(b, g, r);
+
+ altersingle(alpha, j, b, g, r);
+ if (rad != 0) {
+ alterneigh(rad, j, b, g, r); /* alter neighbours */
+ }
+
+ pix += step;
+ if (pix >= lim) {
+ pix -= lengthcount;
+ }
+
+ i++;
+ if (delta == 0) {
+ delta = 1;
+ }
+ if (i % delta == 0) {
+ alpha -= alpha / alphadec;
+ radius -= radius / RADIUSDEC;
+ rad = radius >> RADIUSBIASSHIFT;
+ if (rad <= 1) {
+ rad = 0;
+ }
+ for (j = 0; j < rad; j++) {
+ radpower[j] =
+ alpha * (((rad * rad - j * j) * RADBIAS) / (rad * rad));
+ }
+ }
+ }
+ //fprintf(stderr,"finished 1D learning: final alpha=%f
!\n",((float)alpha)/initalpha);
+ }
+
+ /* Search for BGR values 0..255 (after net is unbiased) and return colour index
+ ---------------------------------------------------------------------------- */
+ public int map(int b, int g, int r) {
+
+ int i;
+ int j;
+ int dist;
+ int a;
+ int bestd;
+ int[] p;
+ int best;
+
+ bestd = 1000; /* biggest possible dist is 256*3 */
+ best = -1;
+ i = netindex[g]; /* index on g */
+ j = i - 1; /* start at netindex[g] and work outwards */
+
+ while ((i < NETSIZE) || (j >= 0)) {
+ if (i < NETSIZE) {
+ p = network[i];
+ dist = p[1] - g; /* inx key */
+ if (dist >= bestd) {
+ i = NETSIZE; /* stop iter */
+ } else {
+ i++;
+ if (dist < 0) {
+ dist = -dist;
+ }
+ a = p[0] - b;
+ if (a < 0) {
+ a = -a;
+ }
+ dist += a;
+ if (dist < bestd) {
+ a = p[2] - r;
+ if (a < 0) {
+ a = -a;
+ }
+ dist += a;
+ if (dist < bestd) {
+ bestd = dist;
+ best = p[3];
+ }
+ }
+ }
+ }
+ if (j >= 0) {
+ p = network[j];
+ dist = g - p[1]; /* inx key - reverse dif */
+ if (dist >= bestd) {
+ j = -1; /* stop iter */
+ } else {
+ j--;
+ if (dist < 0) {
+ dist = -dist;
+ }
+ a = p[0] - b;
+ if (a < 0) {
+ a = -a;
+ }
+ dist += a;
+ if (dist < bestd) {
+ a = p[2] - r;
+ if (a < 0) {
+ a = -a;
+ }
+ dist += a;
+ if (dist < bestd) {
+ bestd = dist;
+ best = p[3];
+ }
+ }
+ }
+ }
+ }
+ return (best);
+ }
+ public byte[] process() {
+ learn();
+ unbiasnet();
+ inxbuild();
+ return colorMap();
+ }
+
+ /* Unbias network to give byte values 0..255 and record position i to prepare for
sort
+
----------------------------------------------------------------------------------- */
+ public void unbiasnet() {
+
+ int i;
+ int j;
+
+ for (i = 0; i < NETSIZE; i++) {
+ network[i][0] >>= NETBIASSHIFT;
+ network[i][1] >>= NETBIASSHIFT;
+ network[i][2] >>= NETBIASSHIFT;
+ network[i][3] = i; /* record colour no */
+ }
+ }
+
+ /* Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|]
+ ---------------------------------------------------------------------------------
*/
+ protected void alterneigh(int rad, int i, int b, int g, int r) {
+
+ int j;
+ int k;
+ int lo;
+ int hi;
+ int a;
+ int m;
+ int[] p;
+
+ lo = i - rad;
+ if (lo < -1) {
+ lo = -1;
+ }
+ hi = i + rad;
+ if (hi > NETSIZE) {
+ hi = NETSIZE;
+ }
+
+ j = i + 1;
+ k = i - 1;
+ m = 1;
+ while ((j < hi) || (k > lo)) {
+ a = radpower[m++];
+ if (j < hi) {
+ p = network[j++];
+ try {
+ p[0] -= (a * (p[0] - b)) / ALPHARADBIAS;
+ p[1] -= (a * (p[1] - g)) / ALPHARADBIAS;
+ p[2] -= (a * (p[2] - r)) / ALPHARADBIAS;
+ } catch (Exception e) {
+ e.printStackTrace();
+ } // prevents 1.3 miscompilation
+ }
+ if (k > lo) {
+ p = network[k--];
+ try {
+ p[0] -= (a * (p[0] - b)) / ALPHARADBIAS;
+ p[1] -= (a * (p[1] - g)) / ALPHARADBIAS;
+ p[2] -= (a * (p[2] - r)) / ALPHARADBIAS;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /* Move neuron i towards biased (b,g,r) by factor alpha
+ ---------------------------------------------------- */
+ protected void altersingle(int alpha, int i, int b, int g, int r) {
+
+ /* alter hit neuron */
+ int[] n = network[i];
+ n[0] -= (alpha * (n[0] - b)) / INITALPHA;
+ n[1] -= (alpha * (n[1] - g)) / INITALPHA;
+ n[2] -= (alpha * (n[2] - r)) / INITALPHA;
+ }
+
+ /* Search for biased BGR values
+ ---------------------------- */
+ protected int contest(int b, int g, int r) {
+
+ /* finds closest neuron (min dist) and updates freq */
+ /* finds best neuron (min dist-bias) and returns position */
+ /* for frequently chosen neurons, freq[i] is high and bias[i] is negative */
+ /* bias[i] = gamma*((1/netsize)-freq[i]) */
+
+ int i;
+ int dist;
+ int a;
+ int biasdist;
+ int betafreq;
+ int bestpos;
+ int bestbiaspos;
+ int bestd;
+ int bestbiasd;
+ int[] n;
+
+ bestd = ~(((int) 1) << 31);
+ bestbiasd = bestd;
+ bestpos = -1;
+ bestbiaspos = bestpos;
+
+ for (i = 0; i < NETSIZE; i++) {
+ n = network[i];
+ dist = n[0] - b;
+ if (dist < 0) {
+ dist = -dist;
+ }
+ a = n[1] - g;
+ if (a < 0) {
+ a = -a;
+ }
+ dist += a;
+ a = n[2] - r;
+ if (a < 0) {
+ a = -a;
+ }
+ dist += a;
+ if (dist < bestd) {
+ bestd = dist;
+ bestpos = i;
+ }
+ biasdist = dist - ((bias[i]) >> (INTBIASSHIFT - NETBIASSHIFT));
+ if (biasdist < bestbiasd) {
+ bestbiasd = biasdist;
+ bestbiaspos = i;
+ }
+ betafreq = (freq[i] >> BETASHIFT);
+ freq[i] -= betafreq;
+ bias[i] += (betafreq << GAMMASHIFT);
+ }
+ freq[bestpos] += BETA;
+ bias[bestpos] -= BETAGAMMA;
+ return (bestbiaspos);
+ }
+}
Modified: trunk/ui/output/ui/pom.xml
===================================================================
--- trunk/ui/output/ui/pom.xml 2010-09-21 17:34:26 UTC (rev 19292)
+++ trunk/ui/output/ui/pom.xml 2010-09-21 17:41:11 UTC (rev 19293)
@@ -55,6 +55,10 @@
<groupId>org.richfaces.core</groupId>
<artifactId>richfaces-core-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.richfaces.core</groupId>
+ <artifactId>richfaces-core-impl</artifactId>
+ </dependency>
<dependency>
<groupId>org.richfaces.ui.common</groupId>
<artifactId>richfaces-ui-common-ui</artifactId>
Added: trunk/ui/output/ui/src/main/java/org/richfaces/component/AbstractProgressBar.java
===================================================================
--- trunk/ui/output/ui/src/main/java/org/richfaces/component/AbstractProgressBar.java
(rev 0)
+++
trunk/ui/output/ui/src/main/java/org/richfaces/component/AbstractProgressBar.java 2010-09-21
17:41:11 UTC (rev 19293)
@@ -0,0 +1,344 @@
+/**
+ * License Agreement.
+ *
+ * Rich Faces - Natural Ajax for Java Server Faces (JSF)
+ *
+ * Copyright (C) 2007 Exadel, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * UIProgressBar.java Date created: 19.12.2007
+ * Last modified by: $Author$
+ * $Revision$ $Date$
+ */
+
+package org.richfaces.component;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.faces.component.UIComponentBase;
+import javax.faces.context.FacesContext;
+import javax.faces.context.PartialViewContext;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.FacesEvent;
+
+import org.ajax4jsf.javascript.JSLiteral;
+import org.ajax4jsf.javascript.ScriptUtils;
+import org.richfaces.cdk.annotations.Attribute;
+import org.richfaces.cdk.annotations.EventName;
+import org.richfaces.cdk.annotations.JsfComponent;
+import org.richfaces.cdk.annotations.JsfRenderer;
+import org.richfaces.cdk.annotations.Tag;
+import org.richfaces.cdk.annotations.TagType;
+import org.richfaces.renderkit.HtmlConstants;
+import org.richfaces.renderkit.html.ProgressBarBaseRenderer;
+import org.richfaces.renderkit.util.CoreAjaxRendererUtils;
+
+/**
+ * Class provides base component class for progress bar
+ *
+ * @author "Andrey Markavtsov"
+ *
+ */
+@JsfComponent(tag = @Tag(type = TagType.Facelets), renderer = @JsfRenderer(type =
"org.richfaces.ProgressBarRenderer"))
+public abstract class AbstractProgressBar extends UIComponentBase{
+
+ /** Component type */
+ public static final String COMPONENT_TYPE = "org.richfaces.ProgressBar";
+
+ /** Component family */
+ public static final String COMPONENT_FAMILY = "org.richfaces.ProgressBar";
+
+ /** Request parameter name containing component state to render */
+ public static final String FORCE_PERCENT_PARAM = "forcePercent";
+
+ /** Percent param name */
+ private static final String PERCENT_PARAM = "percent";
+
+ /** Max value attribute name */
+ private static final String MAXVALUE = "maxValue";
+
+ /** Min value attribute name */
+ private static final String MINVALUE = "minValue";
+
+ /** Enabled attribute name */
+ private static final String ENABLED = "enabled";
+
+ /** Enabled attribute name */
+ private static final String INTERVAL = "interval";
+
+ /** Markup data key */
+ private static final String MARKUP = "markup";
+
+ /** Complete class attribute name */
+ private static final String COMPLETECLASS = "completeClass";
+
+ /** Remain class attribute name */
+ private static final String REMAINCLASS = "remainClass";
+
+ /** Style class attribute name */
+ private static final String STYLECLASS = "styleClass";
+
+ /** Context key */
+ private static final String CONTEXT = "context";
+ @Attribute(events = @EventName("click"))
+ public abstract String getOnclick();
+
+ @Attribute(events = @EventName("dblclick"))
+ public abstract String getOndblclick();
+
+ @Attribute(events = @EventName("mousedown"))
+ public abstract String getOnmousedown();
+
+ @Attribute(events = @EventName("mouseup"))
+ public abstract String getOnmouseup();
+
+ @Attribute(events = @EventName("mouseover"))
+ public abstract String getOnmouseover();
+
+ @Attribute(events = @EventName("mousemove"))
+ public abstract String getOnmousemove();
+
+ @Attribute(events = @EventName("mouseout"))
+ public abstract String getOnmouseout();
+
+ @Attribute(events = @EventName("submit"))
+ public abstract String getOnsubmit();
+
+
+ @Attribute
+ public abstract String getLabel();
+
+ @Attribute
+ public abstract Object getData();
+ public abstract void setData(Object data);
+ @Attribute(defaultValue = "1000")
+ public abstract int getInterval();
+
+ @Attribute(defaultValue = "false")
+ public abstract boolean isEnabled();
+
+ @Attribute(events = @EventName("beforedomupdate"))
+ public abstract String getOnbeforedomupdate();
+
+ @Attribute(events = @EventName("complete"))
+ public abstract String getOncomplete();
+
+ @Attribute
+ public abstract String getCompleteClass();
+
+ @Attribute
+ public abstract String getFinishClass();
+
+ @Attribute
+ public abstract String getInitialClass();
+
+ @Attribute
+ public abstract String getRemainClass();
+
+ @Attribute
+ public abstract String getFocus();
+
+ @Attribute
+ public abstract String getReRenderAfterComplete();
+
+ @Attribute
+ public abstract String getMode();
+
+ @Attribute
+ public abstract int getMaxValue();
+
+ @Attribute
+ public abstract int getMinValue();
+
+ @Attribute
+ public abstract Object getValue();
+
+ @Attribute
+ public abstract Object getParameters();
+
+
+ /**
+ * Method performs broadcasting of jsf events to progress bar component
+ *
+ * @param event -
+ * Faces Event instance
+ */
+ public void broadcast(FacesEvent event) throws AbortProcessingException {
+
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ Map<String, String> params =
facesContext.getExternalContext().getRequestParameterMap();
+ String clientId = this.getClientId(facesContext);
+
+ if (!params.containsKey(clientId)) {
+ return;
+ }
+ if (!params.containsKey(FORCE_PERCENT_PARAM)
+ && params.containsKey(PERCENT_PARAM)) {
+ Number value = NumberUtils.getNumber(this.getAttributes().get(
+ HtmlConstants.VALUE_ATTRIBUTE));
+ PartialViewContext pvc =
FacesContext.getCurrentInstance().getPartialViewContext();
+ pvc.getRenderIds().remove(
+ this.getClientId());
+ this.setData(getResponseData(value, facesContext));
+
+ } else if (params.containsKey(FORCE_PERCENT_PARAM)) {
+ PartialViewContext pvc =
FacesContext.getCurrentInstance().getPartialViewContext();
+ pvc.getRenderIds().add(this.getClientId());
+ String forcedState = params.get(FORCE_PERCENT_PARAM);
+ if ("completeState".equals(forcedState)) {
+ Object reRender =
this.getAttributes().get("reRenderAfterComplete");
+ Set<String> ajaxRegions =
CoreAjaxRendererUtils.asIdsSet(reRender);
+ if (ajaxRegions != null) {
+ for (Iterator<String> iter = ajaxRegions.iterator();
iter.hasNext();) {
+ String id = iter.next();
+ pvc.getExecuteIds().add(id);
+ pvc.getRenderIds().add(id);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns ajax response data
+ *
+ * @param uiComponent
+ * @param percent
+ * @return
+ */
+ private Map<Object, Object> getResponseData(Number value,
+ FacesContext facesContext) {
+
+ ProgressBarBaseRenderer renderer = (ProgressBarBaseRenderer) this
+ .getRenderer(facesContext);
+
+ Map<Object, Object> map = new HashMap<Object, Object>();
+ map.put(HtmlConstants.VALUE_ATTRIBUTE, value);
+ map.put(INTERVAL, this.getInterval());
+
+ if (this.getAttributes().get(HtmlConstants.STYLE_ATTRIBUTE) != null) {
+ map.put(HtmlConstants.STYLE_ATTRIBUTE, this.getAttributes()
+ .get(HtmlConstants.STYLE_ATTRIBUTE));
+ }
+
+ map.put(ENABLED, (Boolean) this.getAttributes().get(ENABLED));
+
+ if (!isSimple(renderer)) {
+ map.put(MARKUP, getMarkup(facesContext, renderer));
+ map.put(CONTEXT, getContext(renderer, value));
+ }
+
+ addStyles2Responce(map, COMPLETECLASS, this.getAttributes().get(
+ COMPLETECLASS));
+ addStyles2Responce(map, REMAINCLASS, this.getAttributes().get(
+ REMAINCLASS));
+ addStyles2Responce(map, STYLECLASS, this.getAttributes().get(
+ STYLECLASS));
+ return map;
+
+ }
+
+ /**
+ * Returns context for macrosubstitution
+ *
+ * @param renderer
+ * @param percent
+ * @return
+ */
+ private JSLiteral getContext(ProgressBarBaseRenderer renderer,
+ Number percent) {
+ StringBuffer buffer = new StringBuffer("{");
+ buffer.append("\"value\":");
+ buffer.append(ScriptUtils.toScript(percent.toString())).append(",");
+ buffer.append("\"minValue\":");
+ buffer.append(
+ ScriptUtils.toScript(this.getAttributes().get(MINVALUE)
+ .toString())).append(",");
+ buffer.append("\"maxValue\":");
+ buffer.append(ScriptUtils.toScript(this.getAttributes().get(MAXVALUE)
+ .toString()));
+
+ String parameters = handleParameters(renderer.getParameters(this));
+ if (parameters != null) {
+ buffer.append(",");
+ buffer.append(parameters);
+ }
+ buffer.append("}");
+ return new JSLiteral(buffer.toString());
+ }
+
+ private String handleParameters(String str){
+ if (str != null && str.length() > 0) {
+ StringBuilder s = new StringBuilder();
+ while(str.indexOf(":") != -1){
+ String a = str.substring(0, str.indexOf(":"));
+ str = str.substring(str.indexOf(":") );
+ s.append("\"");
+ s.append(a);
+ s.append("\"");
+ if (str.indexOf(",") != -1) {
+ String b = str.substring(0, str.indexOf(",") +1);
+ str = str.substring(str.indexOf(",") +1 );
+ s.append(b);
+ } else{
+ s.append(str);
+ return s.toString();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return true if markup is simple
+ *
+ * @return
+ */
+ private boolean isSimple(ProgressBarBaseRenderer renderer) {
+ return renderer.isSimpleMarkup(this);
+ }
+
+ /**
+ * Returns label markup
+ *
+ * @param context
+ * @param renderer
+ * @return
+ */
+ private String getMarkup(FacesContext context,
+ ProgressBarBaseRenderer renderer) {
+ return renderer.getMarkup(context, this).toString();
+ }
+
+ /**
+ * Add component classes to ajax response
+ *
+ * @param buffer
+ * @param attr
+ * @param newValue
+ */
+ private void addStyles2Responce(Map<Object, Object> map, String key,
+ Object className) {
+ if (className != null) {
+ map.put(key, className);
+ }
+ }
+
+}
Added: trunk/ui/output/ui/src/main/java/org/richfaces/component/NumberUtils.java
===================================================================
--- trunk/ui/output/ui/src/main/java/org/richfaces/component/NumberUtils.java
(rev 0)
+++ trunk/ui/output/ui/src/main/java/org/richfaces/component/NumberUtils.java 2010-09-21
17:41:11 UTC (rev 19293)
@@ -0,0 +1,40 @@
+package org.richfaces.component;
+
+import java.math.BigDecimal;
+
+public final class NumberUtils {
+ private NumberUtils() {
+
+ }
+ /**
+ * Converts value attr to number value
+ *
+ * @param v -
+ * value attr
+ * @return result
+ */
+ public static Number getNumber(Object v) {
+ Number result = null;
+ if (v != null) {
+ try {
+ if (v instanceof String) { // String
+ result = Double.parseDouble((String) v);
+ } else {
+ Number n = (Number) v;
+ if ((n instanceof BigDecimal) || (n instanceof Double) // Double
+ // or
+ //
BigDecimal
+ || (n instanceof Float)) {
+ result = n.floatValue();
+ } else if (n instanceof Integer || n instanceof Long) { // Integer
+ result = n.longValue();
+ }
+ }
+ } catch (Exception e) {
+ e.getMessage();
+ }
+ return result;
+ }
+ return new Integer(0);
+ }
+}
Added:
trunk/ui/output/ui/src/main/java/org/richfaces/renderkit/html/ProgressBarBaseRenderer.java
===================================================================
---
trunk/ui/output/ui/src/main/java/org/richfaces/renderkit/html/ProgressBarBaseRenderer.java
(rev 0)
+++
trunk/ui/output/ui/src/main/java/org/richfaces/renderkit/html/ProgressBarBaseRenderer.java 2010-09-21
17:41:11 UTC (rev 19293)
@@ -0,0 +1,392 @@
+/**
+ * License Agreement.
+ *
+ * Rich Faces - Natural Ajax for Java Server Faces (JSF)
+ *
+ * Copyright (C) 2007 Exadel, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * AbstractProgressBarRenderer.java Date created: 20.12.2007
+ * Last modified by: $Author$
+ * $Revision$ $Date$
+ */
+
+package org.richfaces.renderkit.html;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.faces.application.ResourceDependencies;
+import javax.faces.application.ResourceDependency;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.context.PartialViewContext;
+import javax.faces.context.ResponseWriter;
+import javax.faces.event.ActionEvent;
+
+import org.ajax4jsf.javascript.JSLiteral;
+import org.ajax4jsf.javascript.ScriptUtils;
+import org.richfaces.component.AbstractProgressBar;
+import org.richfaces.component.NumberUtils;
+import org.richfaces.log.Logger;
+import org.richfaces.log.RichfacesLogger;
+import org.richfaces.renderkit.RendererBase;
+import org.richfaces.renderkit.util.RendererUtils;
+
+/**
+ * Abstract progress bar renderer
+ *
+ * @author "Andrey Markavtsov"
+ *
+ */
+@ResourceDependencies( {
+ @ResourceDependency(library = "org.richfaces", name =
"ajax.reslib"),
+ @ResourceDependency(library = "org.richfaces", name =
"base-component.reslib"),
+ @ResourceDependency(library = "org.richfaces", name =
"progressBar.js"),
+ @ResourceDependency(library = "org.richfaces", name =
"progressBar.ecss")
+
+})
+public class ProgressBarBaseRenderer extends RendererBase {
+
+ private static final String INITIAL_FACET = "initial";
+ private static final String COMPLETE_FACET = "complete";
+ private static final Logger LOG = RichfacesLogger.APPLICATION.getLogger();
+
+
+ @Override
+ protected void doDecode(FacesContext context, UIComponent component) {
+ super.doDecode(context, component);
+ if (component.isRendered()) {
+ new ActionEvent(component).queue();
+ PartialViewContext pvc = context.getPartialViewContext();
+ pvc.getRenderIds().add(component.getClientId(context));
+ }
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
org.richfaces.renderkit.TemplateEncoderRendererBase#encodeChildren(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ @Override
+ public void encodeChildren(FacesContext context, UIComponent component) throws
IOException {
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
org.ajax4jsf.renderkit.RendererBase#doEncodeChildren(javax.faces.context.ResponseWriter,
+ * javax.faces.context.FacesContext, javax.faces.component.UIComponent)
+ */
+ @Override
+ public void doEncodeChildren(ResponseWriter writer, FacesContext context, UIComponent
component) throws IOException {
+
+ }
+
+ public final boolean getRendersChildren() {
+ return true;
+ }
+
+ /**
+ * Gets state forced from javascript
+ *
+ * @param component
+ * @return
+ */
+ public String getForcedState(FacesContext context, UIComponent component) {
+ String forcedState = null;
+ Map<String, String> params = context.getExternalContext()
+ .getRequestParameterMap();
+ if (params.containsKey(AbstractProgressBar.FORCE_PERCENT_PARAM)) {
+ forcedState = params.get(AbstractProgressBar.FORCE_PERCENT_PARAM);
+ }
+ return forcedState;
+ }
+
+ /**
+ * Renderes label markup
+ *
+ * @param context
+ * @param component
+ * @return
+ */
+ public StringBuffer getMarkup(FacesContext context, UIComponent component) {
+ StringBuffer result = new StringBuffer();
+ try {
+ result = new StringBuffer(getMarkupBody(context, component,
hasChildren(component)));
+
+ } catch (Exception e) {
+ LOG.error("Error occurred during rendering of progress bar label. It
switched to empty string", e);
+ }
+
+ return result;
+
+ }
+
+
+
+ protected String getMarkupBody(FacesContext context, UIComponent component, boolean
children) throws IOException {
+ ResponseWriter writer = context.getResponseWriter();
+ StringWriter dumpingWriter = new StringWriter();
+ ResponseWriter clonedWriter = writer.cloneWithWriter(dumpingWriter);
+ context.setResponseWriter(clonedWriter);
+ try {
+ if (children) {
+ this.renderChildren(context, component);
+ }
+ } finally {
+ clonedWriter.flush();
+ context.setResponseWriter(writer);
+ }
+
+ return dumpingWriter.toString();
+ }
+
+
+
+
+ /**
+ * Encodes script for state rendering in client mode
+ *
+ * @param context
+ * @param component
+ * @param state
+ * @throws IOException
+ */
+ public String getRenderStateScript(FacesContext context,
+ UIComponent component, String state) throws IOException {
+ StringBuffer script = new StringBuffer("\n");
+ script.append(
+ "RichFaces.$('" + component.getClientId(context)
+ + "').renderState('").append(state).append(
+ "');");
+ return script.toString();
+ }
+
+
+
+ /**
+ * Encode initial javascript
+ *
+ * @param context
+ * @param component
+ * @throws IOException
+ */
+ public String getInitialScript(FacesContext context,
+ UIComponent component, String state) throws IOException {
+ AbstractProgressBar progressBar = (AbstractProgressBar) component;
+ StringBuffer script = new StringBuffer();
+ Map<String, Object> options = new HashMap<String, Object>();
+ RendererUtils utils = getUtils();
+
+ String clientId = component.getClientId(context);
+
+ utils.addToScriptHash(options, "mode",
component.getAttributes().get("mode"), "ajax");
+ utils.addToScriptHash(options, "minValue",
component.getAttributes().get("minValue"), "0");
+ utils.addToScriptHash(options, "maxValue",
component.getAttributes().get("maxValue"), "100");
+ utils.addToScriptHash(options, "context", getContext(component));
+
+ Integer interval = new Integer(progressBar.getInterval());
+ utils.addToScriptHash(options, "pollinterval", interval);
+ utils.addToScriptHash(options, "enabled", progressBar.isEnabled());
+ utils.addToScriptHash(options, "pollId",
progressBar.getClientId(context));
+ utils.addToScriptHash(options, "state", state,
"initialState");
+ utils.addToScriptHash(options, "value",
NumberUtils.getNumber(component.getAttributes().get("value")));
+ utils.addToScriptHash(options, "onsubmit",
buildEventFunction(component.getAttributes().get("onsubmit")));
+ script.append("new
RichFaces.ui.ProgressBar('").append(clientId).append("'");
+ if (!options.isEmpty()) {
+ script.append(",").append(ScriptUtils.toScript(options));
+ }
+ script.append(")\n;");
+ return script.toString();
+ }
+
+ private Object buildEventFunction(Object eventFunction) {
+ if(eventFunction != null && eventFunction.toString().length() > 0) {
+ return "new Function(\"" + eventFunction.toString() +
"\");";
+ }
+ return null;
+ }
+
+ /**
+ * Creates options map for AJAX requests
+ *
+ * @param clientId
+ * @param progressBar
+ * @param context
+ * @return
+ */
+ public String getPollScript(FacesContext context, UIComponent component) {
+ return "RichFaces.$('" + component.getClientId() +
"').poll()";
+
+ }
+
+ public String getStopPollScript(FacesContext context, UIComponent component) {
+ return "RichFaces.$('" + component.getClientId() +
"').disable()";
+
+ }
+
+ /**
+ * Check if component mode is AJAX
+ *
+ * @param component
+ * @return
+ */
+ public boolean isAjaxMode(UIComponent component) {
+ String mode = (String) component.getAttributes().get("mode");
+ return "ajax".equalsIgnoreCase(mode);
+ }
+
+ public String getCurrentOrForcedState(FacesContext context, UIComponent component){
+ String forcedState = getForcedState(context,component);
+ if (forcedState != null) {
+ return forcedState;
+ }
+ return getCurrentState(context, component);
+ }
+
+ public String getCurrentState(FacesContext context, UIComponent component){
+ Number minValue =
NumberUtils.getNumber(component.getAttributes().get("minValue"));
+ Number maxValue =
NumberUtils.getNumber(component.getAttributes().get("maxValue"));
+ Number value =
NumberUtils.getNumber(component.getAttributes().get("value"));
+ if (value.doubleValue() <= minValue.doubleValue()) {
+ return "initialState";
+ } else if (value.doubleValue() > maxValue.doubleValue()) {
+ return "completeState";
+ } else {
+ return "progressState";
+ }
+ }
+
+ public String getShellStyle(FacesContext context, UIComponent component){
+ return (!isSimpleMarkup(component)) ? "rich-progress-bar-shell-dig "
+ : "rich-progress-bar-shell ";
+ }
+
+ public String getWidth(UIComponent component){
+ Number value =
NumberUtils.getNumber(component.getAttributes().get("value"));
+ Number minValue =
NumberUtils.getNumber(component.getAttributes().get("minValue"));
+ Number maxValue =
NumberUtils.getNumber(component.getAttributes().get("maxValue"));
+ Number percent = calculatePercent(value, minValue, maxValue);
+
+ return String.valueOf(percent.intValue());
+ }
+
+ public void renderInitialFacet(FacesContext context, UIComponent component) throws
IOException {
+ renderFacet(context, component, INITIAL_FACET);
+ }
+
+ public void renderCompleteFacet(FacesContext context, UIComponent component) throws
IOException {
+ renderFacet(context, component, COMPLETE_FACET);
+ }
+
+ private void renderFacet(FacesContext context, UIComponent component, String facet)
throws IOException {
+ UIComponent headerFacet = component.getFacet(facet);
+ if(headerFacet != null) {
+ headerFacet.encodeAll(context);
+ }
+ }
+
+
+ /**
+ * Returns parameters attr
+ *
+ * @param component
+ * @param renderer
+ * @param percent
+ * @return
+ */
+ public String getParameters(UIComponent component) {
+ String parameters = (String) component.getAttributes()
+ .get("parameters");
+ return parameters;
+ }
+
+ /**
+ * Returns context for macrosubstitution
+ *
+ * @param component
+ * @return
+ */
+ private JSLiteral getContext(UIComponent component) {
+ StringBuffer buffer = new StringBuffer();
+ String parameters = getParameters(component);
+ JSLiteral literal = null;
+ if (parameters != null) {
+ buffer.append("{").append(parameters).append("}");
+ literal = new JSLiteral(buffer.toString());
+ }
+ return literal;
+ }
+
+ /**
+ * Return true if component has children components
+ *
+ * @param component
+ * @return
+ */
+ private boolean hasChildren(UIComponent component) {
+ return (component.getChildCount() != 0);
+ }
+
+ /**
+ * Returns true if markup should rendered as simple 2 divs
+ *
+ * @param component
+ * @return
+ */
+ public boolean isSimpleMarkup(UIComponent component) {
+ if (hasChildren(component)) {
+ return false;
+ } else {
+ if (component.getAttributes().get("label") != null) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+
+ /**
+ * Calculates percent value according to min & max value
+ *
+ * @param value
+ * @param minValue
+ * @param maxValue
+ * @return
+ */
+ public Number calculatePercent(Number value, Number minValue,
+ Number maxValue) {
+ if (minValue.doubleValue() < value.doubleValue()
+ && value.doubleValue() < maxValue.doubleValue()) {
+ return (Number) ((value.doubleValue() - minValue.doubleValue()) * 100.0 /
(maxValue
+ .doubleValue() - minValue.doubleValue()));
+ } else if (value.doubleValue() <= minValue.doubleValue()) {
+ return 0;
+ } else if (value.doubleValue() >= maxValue.doubleValue()) {
+ return 100;
+ }
+ return 0;
+ }
+
+}
Modified: trunk/ui/output/ui/src/main/resources/META-INF/pn.faces-config.xml
===================================================================
--- trunk/ui/output/ui/src/main/resources/META-INF/pn.faces-config.xml 2010-09-21 17:34:26
UTC (rev 19292)
+++ trunk/ui/output/ui/src/main/resources/META-INF/pn.faces-config.xml 2010-09-21 17:41:11
UTC (rev 19293)
@@ -718,6 +718,14 @@
<renderer-type>org.richfaces.Tab</renderer-type>
<renderer-class>org.richfaces.renderkit.html.TabRenderer</renderer-class>
</renderer>
+ <renderer>
+ <component-family>org.richfaces.ProgressBar</component-family>
+ <renderer-type>org.richfaces.ProgressBarRenderer</renderer-type>
+
<renderer-class>org.richfaces.renderkit.html.ProgressBarRenderer</renderer-class>
+ <renderer-extension>
+ <cdk:renders-children>false</cdk:renders-children>
+ </renderer-extension>
+ </renderer>
</render-kit>
<faces-config-extension>
Modified: trunk/ui/output/ui/src/main/resources/META-INF/pn.taglib.xml
===================================================================
--- trunk/ui/output/ui/src/main/resources/META-INF/pn.taglib.xml 2010-09-21 17:34:26 UTC
(rev 19292)
+++ trunk/ui/output/ui/src/main/resources/META-INF/pn.taglib.xml 2010-09-21 17:41:11 UTC
(rev 19293)
@@ -21,6 +21,13 @@
</component>
</tag>
<tag>
+ <tag-name>progressBar</tag-name>
+ <component>
+ <component-type>org.richfaces.ProgressBar</component-type>
+ <renderer-type>org.richfaces.ProgressBarRenderer</renderer-type>
+ </component>
+ </tag>
+ <tag>
<tag-name>popupPanel</tag-name>
<component>
<component-type>org.richfaces.PopupPanel</component-type>
Added:
trunk/ui/output/ui/src/main/resources/META-INF/resources/org.richfaces/progressBar.ecss
===================================================================
---
trunk/ui/output/ui/src/main/resources/META-INF/resources/org.richfaces/progressBar.ecss
(rev 0)
+++
trunk/ui/output/ui/src/main/resources/META-INF/resources/org.richfaces/progressBar.ecss 2010-09-21
17:41:11 UTC (rev 19293)
@@ -0,0 +1,36 @@
+.rich-progress-bar-height{height : 13px;}
+.rich-progress-bar-width{width : 200px}
+.rich-progress-bar-block{white-space : nowrap;}
+.rich-progress-bar-uploaded{
+background-repeat : repeat-x;
+background-image :
"url(#{resource['org.richfaces.renderkit.html.images.ProgressBarAnimatedBg']})";
+background-color : '#{richSkin.selectControlColor}';
+}
+.rich-progress-bar-uploaded-dig{
+overflow : hidden; position : absolute; top : 0px; left : 0px;
+border-color : '#{richSkin.panelBorderColor}';
+}
+.rich-progress-bar-shell{
+margin-bottom : 2px; border : 1px solid;
+background-color : '#{richSkin.controlBackgroundColor}';
+border-color : '#{richSkin.panelBorderColor}';
+}
+.rich-progress-bar-shell-dig{
+position : relative; margin-bottom : 2px; border : 1px solid; overflow: hidden;
+border-color : '#{richSkin.panelBorderColor}';
+color : '#{richSkin.controlTextColor}';
+font-family : '#{richSkin.generalFamilyFont}';
+font-size : '#{richSkin.generalSizeFont}';
+}
+.rich-progress-bar-remained{
+text-align : center; font-weight : bold; position : relative;
+background-color : '#{richSkin.controlBackgroundColor}';
+text-color : '#{richSkin.controlTextColor}';
+}
+.rich-progress-bar-completed{
+text-align : center; font-weight : bold; background-repeat : repeat-x;
+background-color : '#{richSkin.selectControlColor}';
+text-color : '#{richSkin.controlBackgroundColor}';
+background-image :
"url(#{resource['org.richfaces.renderkit.html.images.ProgressBarAnimatedBg']})";
+}
+.rich-progress-bar-padding{padding: 0px}
\ No newline at end of file
Added:
trunk/ui/output/ui/src/main/resources/META-INF/resources/org.richfaces/progressBar.js
===================================================================
--- trunk/ui/output/ui/src/main/resources/META-INF/resources/org.richfaces/progressBar.js
(rev 0)
+++
trunk/ui/output/ui/src/main/resources/META-INF/resources/org.richfaces/progressBar.js 2010-09-21
17:41:11 UTC (rev 19293)
@@ -0,0 +1,293 @@
+//ProgressBar = {};
+//ProgressBar = Class.create();
+(function ($, rf) {
+
+ rf.ui = rf.ui || {};
+
+ // Constructor definition
+ rf.ui.ProgressBar = function(componentId, options) {
+ // call constructor of parent class
+ $super.constructor.call(this, componentId);
+ this.id = componentId;
+ this.attachToDom(this.id);
+ this.options = $.extend({}, defaultOptions, options);
+ var f = this.getForm();
+ this.formId = (f) ? f.id : null;
+ this.disabled = false;
+ this.state = this.options.state;
+ this.value = this.options.value;
+ this.minValue = this.options.minValue;
+ this.maxValue = this.options.maxValue;
+ var component = this;
+ this.options.beforedomupdate = function(event) {
+ component.onComplete(event.data);
+ }
+
+ };
+
+ // Extend component class and add protected methods from parent class to our container
+ rf.BaseComponent.extend(rf.ui.ProgressBar);
+
+ // define super class link
+ var $super = rf.ui.ProgressBar.$super;
+
+ var defaultOptions = {
+ mode: "ajax",
+ minValue: 0,
+ maxValue: 100,
+ state : "initialState"
+ };
+
+ var getForm = function () {
+ var parentForm = rf.getDomElement(this.id);
+ while (parentForm.tagName && parentForm.tagName.toLowerCase() !=
'form') {
+ parentForm = parentForm.parentNode;
+ }
+ return parentForm;
+ };
+
+ var getValue = function () {
+ return this.value;
+ };
+
+ var getParameter = function (ev, params, paramName) {
+ if (!params) {
+ params = ev;
+ }
+ if (params && params[paramName]) {
+ return params[paramName];
+ }
+ return params;
+ };
+
+ var onComplete = function (data) {
+ if (!rf.getDomElement(this.id) || this.disabled) { return; }
+ if (data) {
+ this.value = data['value'];
+ if (this.state == "progressState") {
+ if (this.value > this.getMaxValue()) {
+ this.options.enabled=false;
+ this.forceState("completeState",null);
+ return;
+ }
+ this.updateComponent(data);
+ this.renderLabel(data['markup'], data['context']);
+ } else if (this.state == "initialState" && this.value >
this.getMinValue()) {
+ this.state = "progressState";
+ this.forceState("progressState");
+ return;
+ }
+ this.poll();
+ }
+
+ };
+ var poll = function () {
+ if(this.options.enabled){
+ this.options.parameters = this.options.parameters || {};
+ this.options.parameters['percent'] = "percent";
+ this.options.parameters[this.id] = this.id;
+ var component = this;
+ window.setTimeout(function(){
+ if(component.options.onsubmit){
+ var onsubmit = eval(component.options.onsubmit)
+ var result = onsubmit.call(component);
+ if (result!=false) {
+ result = true;
+ }
+ if(result){
+ rf.ajax(component.options.pollId, null, component.options);
+ }
+ }else{
+ rf.ajax(component.options.pollId, null, component.options);
+ }
+
+ },this.options.pollinterval);
+ }
+ };
+
+ var updateComponent = function (data) {
+ this.setValue(this.value);
+ if (!data['enabled']) { this.disable(); }
+ this.updateClassName(rf.getDomElement(this.id + ":complete"),
data['completeClass']);
+ this.updateClassName(rf.getDomElement(this.id + ":remain"),
data['remainClass']);
+ this.updateClassName(rf.getDomElement(this.id), data['styleClass']);
+
+ if (this.options.pollinterval != data['interval']) {
+ this.options.pollinterval = data['interval'];
+ }
+ };
+
+ var updateClassName = function (o, newName) {
+ if (!newName) return;
+ if (o && o.className) {
+ if (o.className.indexOf(newName) < 0){
+ o.className = o.className + " " + newName;
+ }
+ }
+ };
+ var getContext = function () {
+ var context = this.context;
+ if (!context) { context = {}; }
+ context['minValue'] = (this.minValue == 0 ? "0" : this.minValue);
+ context['maxValue'] = (this.maxValue == 0 ? "0" : this.maxValue);
+ context['value'] = (this.value == 0 ? "0" : this.value);
+ if (this.progressVar) {
+ context[this.progressVar] = context['value'];
+ }
+ return context;
+ };
+
+ var getMode = function () {
+ return this.mode;
+ };
+ var getMaxValue = function () {
+ return this.maxValue;
+ };
+ var getMinValue = function () {
+ return this.minValue;
+ };
+ var isAjaxMode = function () {
+ return (this.getMode() == "ajax");
+ };
+ var calculatePercent = function(v) {
+ var min = parseFloat(this.getMinValue());
+ var max = parseFloat(this.getMaxValue());
+ var value = parseFloat(v);
+ if (value > min && value < max) {
+ return (100*(value - min))/(max - min);
+ } else if (value <= min) {
+ return 0;
+ } else if (value >= max) {
+ return 100;
+ }
+ };
+ var setValue = function (ev, val) {
+ val = this.getParameter(ev, val, "value");
+ this.value = val;
+ if (!this.isAjaxMode()) {
+ if (parseFloat(val) <= parseFloat(this.getMinValue())) {
+ this.switchState("initialState");
+ }else if (parseFloat(val) > parseFloat(this.getMaxValue())) {
+ this.switchState("completeState");
+ }else {
+ this.switchState("progressState");
+ }
+ }
+ if (!this.isAjaxMode() && this.state != "progressState") return;
+
+ if (this.markup) {
+ this.renderLabel(this.markup, this.getContext());
+ }
+ var p = this.calculatePercent(val);
+ var d = $(rf.getDomElement(this.id + ":upload"));
+ if (d != null) d.css('width', p + "%");
+
+ };
+
+ var renderLabel = function (markup, context) {
+ if (!markup || this.state != "progressState") {
+ return;
+ }
+ if (!context) {
+ context = this.getContext();
+ }
+ var html = this.interpolate(markup, context);
+ var remain = rf.getDomElement(this.id + ":remain");
+ var complete = rf.getDomElement(this.id + ":complete");
+ if(remain && complete){
+ remain.innerHTML = complete.innerHTML = html;
+ }
+
+ };
+ var interpolate = function (placeholders, context) {
+ for(var k in context) {
+ var v = context[k];
+ var regexp = new RegExp("\\{" + k + "\\}", "g");
+ placeholders = placeholders.replace(regexp, v);
+ }
+ return placeholders;
+ };
+
+ var enable = function (ev) {
+ if (!this.isAjaxMode()) {
+ this.switchState("progressState");
+ this.setValue(this.getMinValue() + 1);
+ }else if (!(this.value > this.getMaxValue())) {
+ this.disable();
+ this.poll();
+ }
+ this.disabled = false;
+ };
+ var disable = function () {
+ this.disabled = true;
+ };
+ var finish = function () {
+ if (!this.isAjaxMode()) {
+ this.switchState("completeState");
+ }else {
+ this.disable();
+ this.forceState("complete");
+ }
+ };
+ var hideAll = function () {
+ $(rf.getDomElement(this.id + ":progressState")).hide();
+ $(rf.getDomElement(this.id + ":completeState")).hide();
+ $(rf.getDomElement(this.id + ":initialState")).hide();
+ };
+ var switchState = function (state) {
+ this.state = state;
+ this.hideAll();
+ $(rf.getDomElement(this.id + ":" + state)).show();
+ };
+ var renderState = function (state) {
+ this.state = state;
+ this.hideAll();
+ $(rf.getDomElement(this.id + ":" + state)).show();
+ };
+ var forceState = function (state, oncomplete) {
+ var options = {};
+ options['parameters'] = options['parameters'] || {};
+ options['parameters']['forcePercent'] = state;
+ options['parameters'][this.id] = this.id;
+ if (oncomplete) {
+ options['oncomplete'] = oncomplete;
+ }
+ rf.ajax(this.formId, null, options);
+ };
+
+ /*
+ * Prototype definition
+ */
+ $.extend(rf.ui.ProgressBar.prototype, (function () {
+ return {
+ /*
+ * public API functions
+ */
+ name:"ProgressBar",
+ getForm: getForm,
+ getValue: getValue,
+ getParameter: getParameter,
+ onComplete: onComplete,
+ poll: poll,
+ updateComponent: updateComponent,
+ updateClassName: updateClassName,
+ getContext: getContext,
+ getMode: getMode,
+ getMaxValue: getMaxValue,
+ getMinValue: getMinValue,
+ isAjaxMode: isAjaxMode,
+ calculatePercent: calculatePercent,
+ setValue: setValue,
+ enable: enable,
+ disable: disable,
+ finish: finish,
+ hideAll: hideAll,
+ interpolate: interpolate,
+ renderLabel: renderLabel,
+ switchState: switchState,
+ renderState: renderState,
+ forceState: forceState,
+
+ };
+ })());
+})(jQuery, RichFaces);
Added: trunk/ui/output/ui/src/main/templates/progressBar.template.xml
===================================================================
--- trunk/ui/output/ui/src/main/templates/progressBar.template.xml
(rev 0)
+++ trunk/ui/output/ui/src/main/templates/progressBar.template.xml 2010-09-21 17:41:11 UTC
(rev 19293)
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<cdk:root
xmlns="http://jboss.org/schema/richfaces/cdk/xhtml-el"
+
xmlns:cdk="http://jboss.org/schema/richfaces/cdk/core"
+
xmlns:c="http://jboss.org/schema/richfaces/cdk/jstl/core"
+
xmlns:cc="http://jboss.org/schema/richfaces/cdk/jsf/composite"
+
xmlns:javaee="http://java.sun.com/xml/ns/javaee">
+
+ <cc:interface>
+ <cdk:class>org.richfaces.renderkit.html.ProgressBarRenderer</cdk:class>
+ <cdk:superclass>org.richfaces.renderkit.html.ProgressBarBaseRenderer</cdk:superclass>
+ <cdk:component-family>org.richfaces.ProgressBarRenderer</cdk:component-family>
+ <cdk:renderer-type>org.richfaces.ProgressBarRenderer</cdk:renderer-type>
+ </cc:interface>
+
+ <cc:implementation>
+ <c:choose>
+ <c:when test="#{isAjaxMode(component)}">
+ <cdk:object type="java.lang.String" name="state"
value="#{getCurrentOrForcedState(facesContext, component)}" />
+
+ <c:if test="#{state eq 'initialState'}">
+ <div id="#{clientId}"
class="#{component.attributes['initialClass']}"
style="#{component.attributes['style']}">
+ <cdk:call expression="renderInitialFacet(facesContext,
component)"/>
+ </div>
+ </c:if>
+ <c:if test="#{state eq 'completeState'}">
+ <div id="#{clientId}"
class="#{component.attributes['finishClass']}"
style="#{component.attributes['style']}">
+ <cdk:call expression="renderCompleteFacet(facesContext,
component)"/>
+ </div>
+ </c:if>
+ <c:if test="#{state eq 'progressState'}">
+ <cdk:object type="java.lang.String" name="shellStyle"
value="#{getShellStyle(facesContext, component)}" />
+ <div cdk:passThroughWithExclusions="onclick, ondblclick, onmouseup,
onmousedown, onmousemove, onmouseover, onmouseout" id="#{clientId}"
class="rich-progress-bar-block rich-progress-bar-width #{shellStyle}
#{component.attributes['styleClass']}"
style="#{component.attributes['style']}">
+ <c:if test="#{!isSimpleMarkup(component)}">
+ <div class="rich-progress-bar-width rich-progress-bar-height
rich-progress-bar-remained rich-progress-bar-padding
#{component.attributes['remainClass']}" id="#{clientId}:remain"
style="#{component.attributes['style']}"/>
+ <div class="rich-progress-bar-uploaded-dig"
id="#{clientId}:upload" style="#{component.attributes['style']};
width:#{getWidth(component)}%;">
+ <div class="rich-progress-bar-height rich-progress-bar-width
rich-progress-bar-completed rich-progress-bar-padding
#{component.attributes['completeClass']}" id="#{clientId}:complete"
style="#{component.attributes['style']}"/>
+ </div>
+ </c:if>
+ <c:if test="#{isSimpleMarkup(component)}">
+ <div class="rich-progress-bar-height rich-progress-bar-uploaded
#{component.attributes['completeClass']}" id="#{clientId}:upload"
style="#{component.attributes['style']};
width:#{getWidth(component)}%;"/>
+ </c:if>
+ <script type="text/javascript">
+ #{getInitialScript(facesContext, component, 'progressState')}
+ #{getPollScript(facesContext, component)}
+ </script>
+
+ </div>
+ </c:if>
+ </c:when>
+ <c:otherwise>
+ <div id="#{clientId}" >
+ <div id="#{clientId}:initialState"
class="#{component.attributes['initialClass']}"
style="#{component.attributes['style']} display:none;">
+ <cdk:call expression="renderInitialFacet(facesContext, component)"/>
+ </div>
+ <cdk:object type="java.lang.String" name="shellStyle"
value="#{getShellStyle(facesContext, component)}" />
+ <div cdk:passThroughWithExclusions="onclick, ondblclick, onmouseup,
onmousedown, onmousemove, onmouseover, onmouseout"
id="#{clientId}:progressState" class="rich-progress-bar-block
rich-progress-bar-height rich-progress-bar-width #{shellStyle}
#{component.attributes['styleClass']}"
style="#{component.attributes['style']} display:none;">
+ <c:if test="#{!isSimpleMarkup(component)}">
+ <div class="rich-progress-bar-width rich-progress-bar-remained
rich-progress-bar-padding #{component.attributes['remainClass']}"
id="#{clientId}:remain"
style="#{component.attributes['style']}"/>
+ <div class="rich-progress-bar-uploaded-dig"
id="#{clientId}:upload" style="#{component.attributes['style']};
width=#{getWidth(component)}%;">
+ <div class="rich-progress-bar-height rich-progress-bar-width
rich-progress-bar-completed rich-progress-bar-padding
#{component.attributes['completeClass']}" id="#{clientId}:complete"
style="#{component.attributes['style']}"/>
+ </div>
+ </c:if>
+ <c:if test="#{isSimpleMarkup(component)}">
+ <div class="rich-progress-bar-height rich-progress-bar-uploaded
#{component.attributes['completeClass']}" id="#{clientId}:upload"
style="#{component.attributes['style']};
width=#{getWidth(component)}%;"/>
+ </c:if>
+ </div>
+ <div id="#{clientId}:completeState"
class="#{component.attributes['finishClass']}"
style="#{component.attributes['style']} display:none;">
+ <cdk:call expression="renderCompleteFacet(facesContext,
component)"/>
+ </div>
+ <cdk:object type="java.lang.String" name="state"
value="#{getCurrentState(facesContext, component)}" />
+ <script type="text/javascript">
+ #{getInitialScript(facesContext, component, state)}
+ #{getRenderStateScript(facesContext, component, state)}
+ </script>
+ </div>
+
+ </c:otherwise>
+ </c:choose>
+ </cc:implementation>
+</cdk:root>
\ No newline at end of file