diff --git a/java/src/javazoom/jlgui/basicplayer/BasicController.java b/java/src/javazoom/jlgui/basicplayer/BasicController.java
new file mode 100644
index 0000000..c194ffc
--- /dev/null
+++ b/java/src/javazoom/jlgui/basicplayer/BasicController.java
@@ -0,0 +1,102 @@
+/*
+ * BasicController.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.basicplayer;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * This interface defines player controls available.
+ */
+public interface BasicController
+{
+ /**
+ * Open inputstream to play.
+ * @param in
+ * @throws BasicPlayerException
+ */
+ public void open(InputStream in) throws BasicPlayerException;
+
+ /**
+ * Open file to play.
+ * @param file
+ * @throws BasicPlayerException
+ */
+ public void open(File file) throws BasicPlayerException;
+
+ /**
+ * Open URL to play.
+ * @param url
+ * @throws BasicPlayerException
+ */
+ public void open(URL url) throws BasicPlayerException;
+
+ /**
+ * Skip bytes.
+ * @param bytes
+ * @return bytes skipped according to audio frames constraint.
+ * @throws BasicPlayerException
+ */
+ public long seek(long bytes) throws BasicPlayerException;
+
+ /**
+ * Start playback.
+ * @throws BasicPlayerException
+ */
+ public void play() throws BasicPlayerException;
+
+ /**
+ * Stop playback.
+ * @throws BasicPlayerException
+ */
+ public void stop() throws BasicPlayerException;
+
+ /**
+ * Pause playback.
+ * @throws BasicPlayerException
+ */
+ public void pause() throws BasicPlayerException;
+
+ /**
+ * Resume playback.
+ * @throws BasicPlayerException
+ */
+ public void resume() throws BasicPlayerException;
+
+ /**
+ * Sets Pan (Balance) value.
+ * Linear scale : -1.0 <--> +1.0
+ * @param pan value from -1.0 to +1.0
+ * @throws BasicPlayerException
+ */
+ public void setPan(double pan) throws BasicPlayerException;
+
+ /**
+ * Sets Gain value.
+ * Linear scale 0.0 <--> 1.0
+ * @param gain value from 0.0 to 1.0
+ * @throws BasicPlayerException
+ */
+ public void setGain(double gain) throws BasicPlayerException;
+}
diff --git a/java/src/javazoom/jlgui/basicplayer/BasicPlayer.java b/java/src/javazoom/jlgui/basicplayer/BasicPlayer.java
new file mode 100644
index 0000000..24bb85e
--- /dev/null
+++ b/java/src/javazoom/jlgui/basicplayer/BasicPlayer.java
@@ -0,0 +1,1038 @@
+/*
+ * BasicPlayer.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.basicplayer;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Control;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.FloatControl;
+import javax.sound.sampled.Line;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.Mixer;
+import javax.sound.sampled.SourceDataLine;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import javazoom.spi.PropertiesContainer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.tritonus.share.sampled.TAudioFormat;
+import org.tritonus.share.sampled.file.TAudioFileFormat;
+
+/**
+ * BasicPlayer is a threaded simple player class based on JavaSound API.
+ * It has been successfully tested under J2SE 1.3.x, 1.4.x and 1.5.x.
+ */
+public class BasicPlayer implements BasicController, Runnable
+{
+ public static int EXTERNAL_BUFFER_SIZE = 4000 * 4;
+ public static int SKIP_INACCURACY_SIZE = 1200;
+ protected Thread m_thread = null;
+ protected Object m_dataSource;
+ protected AudioInputStream m_encodedaudioInputStream;
+ protected int encodedLength = -1;
+ protected AudioInputStream m_audioInputStream;
+ protected AudioFileFormat m_audioFileFormat;
+ protected SourceDataLine m_line;
+ protected FloatControl m_gainControl;
+ protected FloatControl m_panControl;
+ protected String m_mixerName = null;
+ private int m_lineCurrentBufferSize = -1;
+ private int lineBufferSize = -1;
+ private long threadSleep = -1;
+ private static Log log = LogFactory.getLog(BasicPlayer.class);
+ /**
+ * These variables are used to distinguish stopped, paused, playing states.
+ * We need them to control Thread.
+ */
+ public static final int UNKNOWN = -1;
+ public static final int PLAYING = 0;
+ public static final int PAUSED = 1;
+ public static final int STOPPED = 2;
+ public static final int OPENED = 3;
+ public static final int SEEKING = 4;
+ private int m_status = UNKNOWN;
+ // Listeners to be notified.
+ private Collection m_listeners = null;
+ private Map empty_map = new HashMap();
+
+ /**
+ * Constructs a Basic Player.
+ */
+ public BasicPlayer()
+ {
+ m_dataSource = null;
+ m_listeners = new ArrayList();
+ reset();
+ }
+
+ protected void reset()
+ {
+ m_status = UNKNOWN;
+ if (m_audioInputStream != null)
+ {
+ synchronized (m_audioInputStream)
+ {
+ closeStream();
+ }
+ }
+ m_audioInputStream = null;
+ m_audioFileFormat = null;
+ m_encodedaudioInputStream = null;
+ encodedLength = -1;
+ if (m_line != null)
+ {
+ m_line.stop();
+ m_line.close();
+ m_line = null;
+ }
+ m_gainControl = null;
+ m_panControl = null;
+ }
+
+ /**
+ * Add listener to be notified.
+ * @param bpl
+ */
+ public void addBasicPlayerListener(BasicPlayerListener bpl)
+ {
+ m_listeners.add(bpl);
+ }
+
+ /**
+ * Return registered listeners.
+ * @return
+ */
+ public Collection getListeners()
+ {
+ return m_listeners;
+ }
+
+ /**
+ * Remove registered listener.
+ * @param bpl
+ */
+ public void removeBasicPlayerListener(BasicPlayerListener bpl)
+ {
+ if (m_listeners != null)
+ {
+ m_listeners.remove(bpl);
+ }
+ }
+
+ /**
+ * Set SourceDataLine buffer size. It affects audio latency.
+ * (the delay between line.write(data) and real sound).
+ * Minimum value should be over 10000 bytes.
+ * @param size -1 means maximum buffer size available.
+ */
+ public void setLineBufferSize(int size)
+ {
+ lineBufferSize = size;
+ }
+
+ /**
+ * Return SourceDataLine buffer size.
+ * @return -1 maximum buffer size.
+ */
+ public int getLineBufferSize()
+ {
+ return lineBufferSize;
+ }
+
+ /**
+ * Return SourceDataLine current buffer size.
+ * @return
+ */
+ public int getLineCurrentBufferSize()
+ {
+ return m_lineCurrentBufferSize;
+ }
+
+ /**
+ * Set thread sleep time.
+ * Default is -1 (no sleep time).
+ * @param time in milliseconds.
+ */
+ public void setSleepTime(long time)
+ {
+ threadSleep = time;
+ }
+
+ /**
+ * Return thread sleep time in milliseconds.
+ * @return -1 means no sleep time.
+ */
+ public long getSleepTime()
+ {
+ return threadSleep;
+ }
+
+ /**
+ * Returns BasicPlayer status.
+ * @return status
+ */
+ public int getStatus()
+ {
+ return m_status;
+ }
+
+ /**
+ * Open file to play.
+ */
+ public void open(File file) throws BasicPlayerException
+ {
+ log.info("open(" + file + ")");
+ if (file != null)
+ {
+ m_dataSource = file;
+ initAudioInputStream();
+ }
+ }
+
+ /**
+ * Open URL to play.
+ */
+ public void open(URL url) throws BasicPlayerException
+ {
+ log.info("open(" + url + ")");
+ if (url != null)
+ {
+ m_dataSource = url;
+ initAudioInputStream();
+ }
+ }
+
+ /**
+ * Open inputstream to play.
+ */
+ public void open(InputStream inputStream) throws BasicPlayerException
+ {
+ log.info("open(" + inputStream + ")");
+ if (inputStream != null)
+ {
+ m_dataSource = inputStream;
+ initAudioInputStream();
+ }
+ }
+
+ /**
+ * Inits AudioInputStream and AudioFileFormat from the data source.
+ * @throws BasicPlayerException
+ */
+ protected void initAudioInputStream() throws BasicPlayerException
+ {
+ try
+ {
+ reset();
+ notifyEvent(BasicPlayerEvent.OPENING, getEncodedStreamPosition(), -1, m_dataSource);
+ if (m_dataSource instanceof URL)
+ {
+ initAudioInputStream((URL) m_dataSource);
+ }
+ else if (m_dataSource instanceof File)
+ {
+ initAudioInputStream((File) m_dataSource);
+ }
+ else if (m_dataSource instanceof InputStream)
+ {
+ initAudioInputStream((InputStream) m_dataSource);
+ }
+ createLine();
+ // Notify listeners with AudioFileFormat properties.
+ Map properties = null;
+ if (m_audioFileFormat instanceof TAudioFileFormat)
+ {
+ // Tritonus SPI compliant audio file format.
+ properties = ((TAudioFileFormat) m_audioFileFormat).properties();
+ // Clone the Map because it is not mutable.
+ properties = deepCopy(properties);
+ }
+ else properties = new HashMap();
+ // Add JavaSound properties.
+ if (m_audioFileFormat.getByteLength() > 0) properties.put("audio.length.bytes", new Integer(m_audioFileFormat.getByteLength()));
+ if (m_audioFileFormat.getFrameLength() > 0) properties.put("audio.length.frames", new Integer(m_audioFileFormat.getFrameLength()));
+ if (m_audioFileFormat.getType() != null) properties.put("audio.type", (m_audioFileFormat.getType().toString()));
+ // Audio format.
+ AudioFormat audioFormat = m_audioFileFormat.getFormat();
+ if (audioFormat.getFrameRate() > 0) properties.put("audio.framerate.fps", new Float(audioFormat.getFrameRate()));
+ if (audioFormat.getFrameSize() > 0) properties.put("audio.framesize.bytes", new Integer(audioFormat.getFrameSize()));
+ if (audioFormat.getSampleRate() > 0) properties.put("audio.samplerate.hz", new Float(audioFormat.getSampleRate()));
+ if (audioFormat.getSampleSizeInBits() > 0) properties.put("audio.samplesize.bits", new Integer(audioFormat.getSampleSizeInBits()));
+ if (audioFormat.getChannels() > 0) properties.put("audio.channels", new Integer(audioFormat.getChannels()));
+ if (audioFormat instanceof TAudioFormat)
+ {
+ // Tritonus SPI compliant audio format.
+ Map addproperties = ((TAudioFormat) audioFormat).properties();
+ properties.putAll(addproperties);
+ }
+ // Add SourceDataLine
+ properties.put("basicplayer.sourcedataline", m_line);
+ Iterator it = m_listeners.iterator();
+ while (it.hasNext())
+ {
+ BasicPlayerListener bpl = (BasicPlayerListener) it.next();
+ bpl.opened(m_dataSource, properties);
+ }
+ m_status = OPENED;
+ notifyEvent(BasicPlayerEvent.OPENED, getEncodedStreamPosition(), -1, null);
+ }
+ catch (LineUnavailableException e)
+ {
+ throw new BasicPlayerException(e);
+ }
+ catch (UnsupportedAudioFileException e)
+ {
+ throw new BasicPlayerException(e);
+ }
+ catch (IOException e)
+ {
+ throw new BasicPlayerException(e);
+ }
+ }
+
+ /**
+ * Inits Audio ressources from file.
+ */
+ protected void initAudioInputStream(File file) throws UnsupportedAudioFileException, IOException
+ {
+ m_audioInputStream = AudioSystem.getAudioInputStream(file);
+ m_audioFileFormat = AudioSystem.getAudioFileFormat(file);
+ }
+
+ /**
+ * Inits Audio ressources from URL.
+ */
+ protected void initAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException
+ {
+ m_audioInputStream = AudioSystem.getAudioInputStream(url);
+ m_audioFileFormat = AudioSystem.getAudioFileFormat(url);
+ }
+
+ /**
+ * Inits Audio ressources from InputStream.
+ */
+ protected void initAudioInputStream(InputStream inputStream) throws UnsupportedAudioFileException, IOException
+ {
+ m_audioInputStream = AudioSystem.getAudioInputStream(inputStream);
+ m_audioFileFormat = AudioSystem.getAudioFileFormat(inputStream);
+ }
+
+ /**
+ * Inits Audio ressources from AudioSystem.
+ */
+ protected void initLine() throws LineUnavailableException
+ {
+ log.info("initLine()");
+ if (m_line == null) createLine();
+ if (!m_line.isOpen())
+ {
+ openLine();
+ }
+ else
+ {
+ AudioFormat lineAudioFormat = m_line.getFormat();
+ AudioFormat audioInputStreamFormat = m_audioInputStream == null ? null : m_audioInputStream.getFormat();
+ if (!lineAudioFormat.equals(audioInputStreamFormat))
+ {
+ m_line.close();
+ openLine();
+ }
+ }
+ }
+
+ /**
+ * Inits a DateLine.
+ *
+ * We check if the line supports Gain and Pan controls.
+ *
+ * From the AudioInputStream, i.e. from the sound file, we
+ * fetch information about the format of the audio data. These
+ * information include the sampling frequency, the number of
+ * channels and the size of the samples. There information
+ * are needed to ask JavaSound for a suitable output line
+ * for this audio file.
+ * Furthermore, we have to give JavaSound a hint about how
+ * big the internal buffer for the line should be. Here,
+ * we say AudioSystem.NOT_SPECIFIED, signaling that we don't
+ * care about the exact size. JavaSound will use some default
+ * value for the buffer size.
+ */
+ protected void createLine() throws LineUnavailableException
+ {
+ log.info("Create Line");
+ if (m_line == null)
+ {
+ AudioFormat sourceFormat = m_audioInputStream.getFormat();
+ log.info("Create Line : Source format : " + sourceFormat.toString());
+ int nSampleSizeInBits = sourceFormat.getSampleSizeInBits();
+ if (nSampleSizeInBits <= 0) nSampleSizeInBits = 16;
+ if ((sourceFormat.getEncoding() == AudioFormat.Encoding.ULAW) || (sourceFormat.getEncoding() == AudioFormat.Encoding.ALAW)) nSampleSizeInBits = 16;
+ if (nSampleSizeInBits != 8) nSampleSizeInBits = 16;
+ AudioFormat targetFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, sourceFormat.getSampleRate(), nSampleSizeInBits, sourceFormat.getChannels(), sourceFormat.getChannels() * (nSampleSizeInBits / 8), sourceFormat.getSampleRate(), false);
+ log.info("Create Line : Target format: " + targetFormat);
+ // Keep a reference on encoded stream to progress notification.
+ m_encodedaudioInputStream = m_audioInputStream;
+ try
+ {
+ // Get total length in bytes of the encoded stream.
+ encodedLength = m_encodedaudioInputStream.available();
+ }
+ catch (IOException e)
+ {
+ log.error("Cannot get m_encodedaudioInputStream.available()", e);
+ }
+ // Create decoded stream.
+ m_audioInputStream = AudioSystem.getAudioInputStream(targetFormat, m_audioInputStream);
+ AudioFormat audioFormat = m_audioInputStream.getFormat();
+ DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat, AudioSystem.NOT_SPECIFIED);
+ Mixer mixer = getMixer(m_mixerName);
+ if (mixer != null)
+ {
+ log.info("Mixer : "+mixer.getMixerInfo().toString());
+ m_line = (SourceDataLine) mixer.getLine(info);
+ }
+ else
+ {
+ m_line = (SourceDataLine) AudioSystem.getLine(info);
+ m_mixerName = null;
+ }
+ log.info("Line : " + m_line.toString());
+ log.debug("Line Info : " + m_line.getLineInfo().toString());
+ log.debug("Line AudioFormat: " + m_line.getFormat().toString());
+ }
+ }
+
+ /**
+ * Opens the line.
+ */
+ protected void openLine() throws LineUnavailableException
+ {
+ if (m_line != null)
+ {
+ AudioFormat audioFormat = m_audioInputStream.getFormat();
+ int buffersize = lineBufferSize;
+ if (buffersize <= 0) buffersize = m_line.getBufferSize();
+ m_lineCurrentBufferSize = buffersize;
+ m_line.open(audioFormat, buffersize);
+ log.info("Open Line : BufferSize=" + buffersize);
+ /*-- Display supported controls --*/
+ Control[] c = m_line.getControls();
+ for (int p = 0; p < c.length; p++)
+ {
+ log.debug("Controls : " + c[p].toString());
+ }
+ /*-- Is Gain Control supported ? --*/
+ if (m_line.isControlSupported(FloatControl.Type.MASTER_GAIN))
+ {
+ m_gainControl = (FloatControl) m_line.getControl(FloatControl.Type.MASTER_GAIN);
+ log.info("Master Gain Control : [" + m_gainControl.getMinimum() + "," + m_gainControl.getMaximum() + "] " + m_gainControl.getPrecision());
+ }
+ /*-- Is Pan control supported ? --*/
+ if (m_line.isControlSupported(FloatControl.Type.PAN))
+ {
+ m_panControl = (FloatControl) m_line.getControl(FloatControl.Type.PAN);
+ log.info("Pan Control : [" + m_panControl.getMinimum() + "," + m_panControl.getMaximum() + "] " + m_panControl.getPrecision());
+ }
+ }
+ }
+
+ /**
+ * Stops the playback.
+ *
+ * Player Status = STOPPED.
+ * Thread should free Audio ressources.
+ */
+ protected void stopPlayback()
+ {
+ if ((m_status == PLAYING) || (m_status == PAUSED))
+ {
+ if (m_line != null)
+ {
+ m_line.flush();
+ m_line.stop();
+ }
+ m_status = STOPPED;
+ notifyEvent(BasicPlayerEvent.STOPPED, getEncodedStreamPosition(), -1, null);
+ synchronized (m_audioInputStream)
+ {
+ closeStream();
+ }
+ log.info("stopPlayback() completed");
+ }
+ }
+
+ /**
+ * Pauses the playback.
+ *
+ * Player Status = PAUSED.
+ */
+ protected void pausePlayback()
+ {
+ if (m_line != null)
+ {
+ if (m_status == PLAYING)
+ {
+ m_line.flush();
+ m_line.stop();
+ m_status = PAUSED;
+ log.info("pausePlayback() completed");
+ notifyEvent(BasicPlayerEvent.PAUSED, getEncodedStreamPosition(), -1, null);
+ }
+ }
+ }
+
+ /**
+ * Resumes the playback.
+ *
+ * Player Status = PLAYING.
+ */
+ protected void resumePlayback()
+ {
+ if (m_line != null)
+ {
+ if (m_status == PAUSED)
+ {
+ m_line.start();
+ m_status = PLAYING;
+ log.info("resumePlayback() completed");
+ notifyEvent(BasicPlayerEvent.RESUMED, getEncodedStreamPosition(), -1, null);
+ }
+ }
+ }
+
+ /**
+ * Starts playback.
+ */
+ protected void startPlayback() throws BasicPlayerException
+ {
+ if (m_status == STOPPED) initAudioInputStream();
+ if (m_status == OPENED)
+ {
+ log.info("startPlayback called");
+ if (!(m_thread == null || !m_thread.isAlive()))
+ {
+ log.info("WARNING: old thread still running!!");
+ int cnt = 0;
+ while (m_status != OPENED)
+ {
+ try
+ {
+ if (m_thread != null)
+ {
+ log.info("Waiting ... " + cnt);
+ cnt++;
+ Thread.sleep(1000);
+ if (cnt > 2)
+ {
+ m_thread.interrupt();
+ }
+ }
+ }
+ catch (InterruptedException e)
+ {
+ throw new BasicPlayerException(BasicPlayerException.WAITERROR, e);
+ }
+ }
+ }
+ // Open SourceDataLine.
+ try
+ {
+ initLine();
+ }
+ catch (LineUnavailableException e)
+ {
+ throw new BasicPlayerException(BasicPlayerException.CANNOTINITLINE, e);
+ }
+ log.info("Creating new thread");
+ m_thread = new Thread(this, "BasicPlayer");
+ m_thread.start();
+ if (m_line != null)
+ {
+ m_line.start();
+ m_status = PLAYING;
+ notifyEvent(BasicPlayerEvent.PLAYING, getEncodedStreamPosition(), -1, null);
+ }
+ }
+ }
+
+ /**
+ * Main loop.
+ *
+ * Player Status == STOPPED || SEEKING => End of Thread + Freeing Audio Ressources.
+ * Player Status == PLAYING => Audio stream data sent to Audio line.
+ * Player Status == PAUSED => Waiting for another status.
+ */
+ public void run()
+ {
+ log.info("Thread Running");
+ int nBytesRead = 1;
+ byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
+ // Lock stream while playing.
+ synchronized (m_audioInputStream)
+ {
+ // Main play/pause loop.
+ while ((nBytesRead != -1) && (m_status != STOPPED) && (m_status != SEEKING) && (m_status != UNKNOWN))
+ {
+ if (m_status == PLAYING)
+ {
+ // Play.
+ try
+ {
+ nBytesRead = m_audioInputStream.read(abData, 0, abData.length);
+ if (nBytesRead >= 0)
+ {
+ byte[] pcm = new byte[nBytesRead];
+ System.arraycopy(abData, 0, pcm, 0, nBytesRead);
+ if (m_line.available() >= m_line.getBufferSize()) log.debug("Underrun : "+m_line.available()+"/"+m_line.getBufferSize());
+ int nBytesWritten = m_line.write(abData, 0, nBytesRead);
+ // Compute position in bytes in encoded stream.
+ int nEncodedBytes = getEncodedStreamPosition();
+ // Notify listeners
+ Iterator it = m_listeners.iterator();
+ while (it.hasNext())
+ {
+ BasicPlayerListener bpl = (BasicPlayerListener) it.next();
+ if (m_audioInputStream instanceof PropertiesContainer)
+ {
+ // Pass audio parameters such as instant bitrate, ...
+ Map properties = ((PropertiesContainer) m_audioInputStream).properties();
+ bpl.progress(nEncodedBytes, m_line.getMicrosecondPosition(), pcm, properties);
+ }
+ else bpl.progress(nEncodedBytes, m_line.getMicrosecondPosition(), pcm, empty_map);
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ log.error("Thread cannot run()", e);
+ m_status = STOPPED;
+ notifyEvent(BasicPlayerEvent.STOPPED, getEncodedStreamPosition(), -1, null);
+ }
+ // Nice CPU usage.
+ if (threadSleep > 0)
+ {
+ try
+ {
+ Thread.sleep(threadSleep);
+ }
+ catch (InterruptedException e)
+ {
+ log.error("Thread cannot sleep(" + threadSleep + ")", e);
+ }
+ }
+ }
+ else
+ {
+ // Pause
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e)
+ {
+ log.error("Thread cannot sleep(1000)", e);
+ }
+ }
+ }
+ // Free audio resources.
+ if (m_line != null)
+ {
+ m_line.drain();
+ m_line.stop();
+ m_line.close();
+ m_line = null;
+ }
+ // Notification of "End Of Media"
+ if (nBytesRead == -1)
+ {
+ notifyEvent(BasicPlayerEvent.EOM, getEncodedStreamPosition(), -1, null);
+ }
+ // Close stream.
+ closeStream();
+ }
+ m_status = STOPPED;
+ notifyEvent(BasicPlayerEvent.STOPPED, getEncodedStreamPosition(), -1, null);
+ log.info("Thread completed");
+ }
+
+ /**
+ * Skip bytes in the File inputstream.
+ * It will skip N frames matching to bytes, so it will never skip given bytes length exactly.
+ * @param bytes
+ * @return value>0 for File and value=0 for URL and InputStream
+ * @throws BasicPlayerException
+ */
+ protected long skipBytes(long bytes) throws BasicPlayerException
+ {
+ long totalSkipped = 0;
+ if (m_dataSource instanceof File)
+ {
+ log.info("Bytes to skip : " + bytes);
+ int previousStatus = m_status;
+ m_status = SEEKING;
+ long skipped = 0;
+ try
+ {
+ synchronized (m_audioInputStream)
+ {
+ notifyEvent(BasicPlayerEvent.SEEKING, getEncodedStreamPosition(), -1, null);
+ initAudioInputStream();
+ if (m_audioInputStream != null)
+ {
+ // Loop until bytes are really skipped.
+ while (totalSkipped < (bytes - SKIP_INACCURACY_SIZE))
+ {
+ skipped = m_audioInputStream.skip(bytes - totalSkipped);
+ if (skipped == 0) break;
+ totalSkipped = totalSkipped + skipped;
+ log.info("Skipped : " + totalSkipped + "/" + bytes);
+ if (totalSkipped == -1) throw new BasicPlayerException(BasicPlayerException.SKIPNOTSUPPORTED);
+ }
+ }
+ }
+ notifyEvent(BasicPlayerEvent.SEEKED, getEncodedStreamPosition(), -1, null);
+ m_status = OPENED;
+ if (previousStatus == PLAYING) startPlayback();
+ else if (previousStatus == PAUSED)
+ {
+ startPlayback();
+ pausePlayback();
+ }
+ }
+ catch (IOException e)
+ {
+ throw new BasicPlayerException(e);
+ }
+ }
+ return totalSkipped;
+ }
+
+ /**
+ * Notify listeners about a BasicPlayerEvent.
+ * @param code event code.
+ * @param position in the stream when the event occurs.
+ */
+ protected void notifyEvent(int code, int position, double value, Object description)
+ {
+ BasicPlayerEventLauncher trigger = new BasicPlayerEventLauncher(code, position, value, description, new ArrayList(m_listeners), this);
+ trigger.start();
+ }
+
+ protected int getEncodedStreamPosition()
+ {
+ int nEncodedBytes = -1;
+ if (m_dataSource instanceof File)
+ {
+ try
+ {
+ if (m_encodedaudioInputStream != null)
+ {
+ nEncodedBytes = encodedLength - m_encodedaudioInputStream.available();
+ }
+ }
+ catch (IOException e)
+ {
+ //log.debug("Cannot get m_encodedaudioInputStream.available()",e);
+ }
+ }
+ return nEncodedBytes;
+ }
+
+ protected void closeStream()
+ {
+ // Close stream.
+ try
+ {
+ if (m_audioInputStream != null)
+ {
+ m_audioInputStream.close();
+ log.info("Stream closed");
+ }
+ }
+ catch (IOException e)
+ {
+ log.info("Cannot close stream", e);
+ }
+ }
+
+ /**
+ * Returns true if Gain control is supported.
+ */
+ public boolean hasGainControl()
+ {
+ if (m_gainControl == null)
+ {
+ // Try to get Gain control again (to support J2SE 1.5)
+ if ( (m_line != null) && (m_line.isControlSupported(FloatControl.Type.MASTER_GAIN))) m_gainControl = (FloatControl) m_line.getControl(FloatControl.Type.MASTER_GAIN);
+ }
+ return m_gainControl != null;
+ }
+
+ /**
+ * Returns Gain value.
+ */
+ public float getGainValue()
+ {
+ if (hasGainControl())
+ {
+ return m_gainControl.getValue();
+ }
+ else
+ {
+ return 0.0F;
+ }
+ }
+
+ /**
+ * Gets max Gain value.
+ */
+ public float getMaximumGain()
+ {
+ if (hasGainControl())
+ {
+ return m_gainControl.getMaximum();
+ }
+ else
+ {
+ return 0.0F;
+ }
+ }
+
+ /**
+ * Gets min Gain value.
+ */
+ public float getMinimumGain()
+ {
+ if (hasGainControl())
+ {
+ return m_gainControl.getMinimum();
+ }
+ else
+ {
+ return 0.0F;
+ }
+ }
+
+ /**
+ * Returns true if Pan control is supported.
+ */
+ public boolean hasPanControl()
+ {
+ if (m_panControl == null)
+ {
+ // Try to get Pan control again (to support J2SE 1.5)
+ if ((m_line != null)&& (m_line.isControlSupported(FloatControl.Type.PAN))) m_panControl = (FloatControl) m_line.getControl(FloatControl.Type.PAN);
+ }
+ return m_panControl != null;
+ }
+
+ /**
+ * Returns Pan precision.
+ */
+ public float getPrecision()
+ {
+ if (hasPanControl())
+ {
+ return m_panControl.getPrecision();
+ }
+ else
+ {
+ return 0.0F;
+ }
+ }
+
+ /**
+ * Returns Pan value.
+ */
+ public float getPan()
+ {
+ if (hasPanControl())
+ {
+ return m_panControl.getValue();
+ }
+ else
+ {
+ return 0.0F;
+ }
+ }
+
+ /**
+ * Deep copy of a Map.
+ * @param src
+ * @return
+ */
+ protected Map deepCopy(Map src)
+ {
+ HashMap map = new HashMap();
+ if (src != null)
+ {
+ Iterator it = src.keySet().iterator();
+ while (it.hasNext())
+ {
+ Object key = it.next();
+ Object value = src.get(key);
+ map.put(key, value);
+ }
+ }
+ return map;
+ }
+
+ /**
+ * @see javazoom.jlgui.basicplayer.BasicController#seek(long)
+ */
+ public long seek(long bytes) throws BasicPlayerException
+ {
+ return skipBytes(bytes);
+ }
+
+ /**
+ * @see javazoom.jlgui.basicplayer.BasicController#play()
+ */
+ public void play() throws BasicPlayerException
+ {
+ startPlayback();
+ }
+
+ /**
+ * @see javazoom.jlgui.basicplayer.BasicController#stop()
+ */
+ public void stop() throws BasicPlayerException
+ {
+ stopPlayback();
+ }
+
+ /**
+ * @see javazoom.jlgui.basicplayer.BasicController#pause()
+ */
+ public void pause() throws BasicPlayerException
+ {
+ pausePlayback();
+ }
+
+ /**
+ * @see javazoom.jlgui.basicplayer.BasicController#resume()
+ */
+ public void resume() throws BasicPlayerException
+ {
+ resumePlayback();
+ }
+
+ /**
+ * Sets Pan value.
+ * Line should be opened before calling this method.
+ * Linear scale : -1.0 <--> +1.0
+ */
+ public void setPan(double fPan) throws BasicPlayerException
+ {
+ if (hasPanControl())
+ {
+ log.debug("Pan : " + fPan);
+ m_panControl.setValue((float) fPan);
+ notifyEvent(BasicPlayerEvent.PAN, getEncodedStreamPosition(), fPan, null);
+ }
+ else throw new BasicPlayerException(BasicPlayerException.PANCONTROLNOTSUPPORTED);
+ }
+
+ /**
+ * Sets Gain value.
+ * Line should be opened before calling this method.
+ * Linear scale 0.0 <--> 1.0
+ * Threshold Coef. : 1/2 to avoid saturation.
+ */
+ public void setGain(double fGain) throws BasicPlayerException
+ {
+ if (hasGainControl())
+ {
+ double minGainDB = getMinimumGain();
+ double ampGainDB = ((10.0f / 20.0f) * getMaximumGain()) - getMinimumGain();
+ double cste = Math.log(10.0) / 20;
+ double valueDB = minGainDB + (1 / cste) * Math.log(1 + (Math.exp(cste * ampGainDB) - 1) * fGain);
+ log.debug("Gain : " + valueDB);
+ m_gainControl.setValue((float) valueDB);
+ notifyEvent(BasicPlayerEvent.GAIN, getEncodedStreamPosition(), fGain, null);
+ }
+ else throw new BasicPlayerException(BasicPlayerException.GAINCONTROLNOTSUPPORTED);
+ }
+
+ public List getMixers()
+ {
+ ArrayList mixers = new ArrayList();
+ Mixer.Info[] mInfos = AudioSystem.getMixerInfo();
+ if (mInfos != null)
+ {
+ for (int i = 0; i < mInfos.length; i++)
+ {
+ Line.Info lineInfo = new Line.Info(SourceDataLine.class);
+ Mixer mixer = AudioSystem.getMixer(mInfos[i]);
+ if (mixer.isLineSupported(lineInfo))
+ {
+ mixers.add(mInfos[i].getName());
+ }
+ }
+ }
+ return mixers;
+ }
+
+ public Mixer getMixer(String name)
+ {
+ Mixer mixer = null;
+ if (name != null)
+ {
+ Mixer.Info[] mInfos = AudioSystem.getMixerInfo();
+ if (mInfos != null)
+ {
+ for (int i = 0; i < mInfos.length; i++)
+ {
+ if (mInfos[i].getName().equals(name))
+ {
+ mixer = AudioSystem.getMixer(mInfos[i]);
+ break;
+ }
+ }
+ }
+ }
+ return mixer;
+ }
+
+ public String getMixerName()
+ {
+ return m_mixerName;
+ }
+
+ public void setMixerName(String name)
+ {
+ m_mixerName = name;
+ }
+}
diff --git a/java/src/javazoom/jlgui/basicplayer/BasicPlayerEvent.java b/java/src/javazoom/jlgui/basicplayer/BasicPlayerEvent.java
new file mode 100644
index 0000000..9726c3b
--- /dev/null
+++ b/java/src/javazoom/jlgui/basicplayer/BasicPlayerEvent.java
@@ -0,0 +1,121 @@
+/*
+ * BasicPlayerEvent.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.basicplayer;
+
+/**
+ * This class implements player events.
+ */
+public class BasicPlayerEvent
+{
+ public static final int UNKNOWN = -1;
+ public static final int OPENING = 0;
+ public static final int OPENED = 1;
+ public static final int PLAYING = 2;
+ public static final int STOPPED = 3;
+ public static final int PAUSED = 4;
+ public static final int RESUMED = 5;
+ public static final int SEEKING = 6;
+ public static final int SEEKED = 7;
+ public static final int EOM = 8;
+ public static final int PAN = 9;
+ public static final int GAIN = 10;
+ private int code = UNKNOWN;
+ private int position = -1;
+ private double value = -1.0;
+ private Object source = null;
+ private Object description = null;
+
+ /**
+ * Constructor
+ * @param source of the event
+ * @param code of the envent
+ * @param position optional stream position
+ * @param value opitional control value
+ * @param desc optional description
+ */
+ public BasicPlayerEvent(Object source, int code, int position, double value, Object desc)
+ {
+ this.value = value;
+ this.position = position;
+ this.source = source;
+ this.code = code;
+ this.description = desc;
+ }
+
+ /**
+ * Return code of the event triggered.
+ * @return
+ */
+ public int getCode()
+ {
+ return code;
+ }
+
+ /**
+ * Return position in the stream when event occured.
+ * @return
+ */
+ public int getPosition()
+ {
+ return position;
+ }
+
+ /**
+ * Return value related to event triggered.
+ * @return
+ */
+ public double getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Return description.
+ * @return
+ */
+ public Object getDescription()
+ {
+ return description;
+ }
+
+ public Object getSource()
+ {
+ return source;
+ }
+
+ public String toString()
+ {
+ if (code == OPENED) return "OPENED:" + position;
+ else if (code == OPENING) return "OPENING:" + position + ":" + description;
+ else if (code == PLAYING) return "PLAYING:" + position;
+ else if (code == STOPPED) return "STOPPED:" + position;
+ else if (code == PAUSED) return "PAUSED:" + position;
+ else if (code == RESUMED) return "RESUMED:" + position;
+ else if (code == SEEKING) return "SEEKING:" + position;
+ else if (code == SEEKED) return "SEEKED:" + position;
+ else if (code == EOM) return "EOM:" + position;
+ else if (code == PAN) return "PAN:" + value;
+ else if (code == GAIN) return "GAIN:" + value;
+ else return "UNKNOWN:" + position;
+ }
+}
diff --git a/java/src/javazoom/jlgui/basicplayer/BasicPlayerEventLauncher.java b/java/src/javazoom/jlgui/basicplayer/BasicPlayerEventLauncher.java
new file mode 100644
index 0000000..d3ef1ef
--- /dev/null
+++ b/java/src/javazoom/jlgui/basicplayer/BasicPlayerEventLauncher.java
@@ -0,0 +1,73 @@
+/*
+ * BasicPlayerEventLauncher.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.basicplayer;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * This class implements a threaded events launcher.
+ */
+public class BasicPlayerEventLauncher extends Thread
+{
+ private int code = -1;
+ private int position = -1;
+ private double value = 0.0;
+ private Object description = null;
+ private Collection listeners = null;
+ private Object source = null;
+
+ /**
+ * Contructor.
+ * @param code
+ * @param position
+ * @param value
+ * @param description
+ * @param listeners
+ * @param source
+ */
+ public BasicPlayerEventLauncher(int code, int position, double value, Object description, Collection listeners, Object source)
+ {
+ super();
+ this.code = code;
+ this.position = position;
+ this.value = value;
+ this.description = description;
+ this.listeners = listeners;
+ this.source = source;
+ }
+
+ public void run()
+ {
+ if (listeners != null)
+ {
+ Iterator it = listeners.iterator();
+ while (it.hasNext())
+ {
+ BasicPlayerListener bpl = (BasicPlayerListener) it.next();
+ BasicPlayerEvent event = new BasicPlayerEvent(source, code, position, value, description);
+ bpl.stateUpdated(event);
+ }
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/basicplayer/BasicPlayerException.java b/java/src/javazoom/jlgui/basicplayer/BasicPlayerException.java
new file mode 100644
index 0000000..e2f2893
--- /dev/null
+++ b/java/src/javazoom/jlgui/basicplayer/BasicPlayerException.java
@@ -0,0 +1,107 @@
+/*
+ * BasicPlayerException.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.basicplayer;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * This class implements custom exception for basicplayer.
+ */
+public class BasicPlayerException extends Exception
+{
+ public static final String GAINCONTROLNOTSUPPORTED = "Gain control not supported";
+ public static final String PANCONTROLNOTSUPPORTED = "Pan control not supported";
+ public static final String WAITERROR = "Wait error";
+ public static final String CANNOTINITLINE = "Cannot init line";
+ public static final String SKIPNOTSUPPORTED = "Skip not supported";
+ private Throwable cause = null;
+
+ public BasicPlayerException()
+ {
+ super();
+ }
+
+ public BasicPlayerException(String msg)
+ {
+ super(msg);
+ }
+
+ public BasicPlayerException(Throwable cause)
+ {
+ super();
+ this.cause = cause;
+ }
+
+ public BasicPlayerException(String msg, Throwable cause)
+ {
+ super(msg);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+
+ /**
+ * Returns the detail message string of this throwable. If it was
+ * created with a null message, returns the following:
+ * (cause==null ? null : cause.toString()).
+ */
+ public String getMessage()
+ {
+ if (super.getMessage() != null)
+ {
+ return super.getMessage();
+ }
+ else if (cause != null)
+ {
+ return cause.toString();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public void printStackTrace()
+ {
+ printStackTrace(System.err);
+ }
+
+ public void printStackTrace(PrintStream out)
+ {
+ synchronized (out)
+ {
+ PrintWriter pw = new PrintWriter(out, false);
+ printStackTrace(pw);
+ pw.flush();
+ }
+ }
+
+ public void printStackTrace(PrintWriter out)
+ {
+ if (cause != null) cause.printStackTrace(out);
+ }
+}
diff --git a/java/src/javazoom/jlgui/basicplayer/BasicPlayerListener.java b/java/src/javazoom/jlgui/basicplayer/BasicPlayerListener.java
new file mode 100644
index 0000000..9e05d2e
--- /dev/null
+++ b/java/src/javazoom/jlgui/basicplayer/BasicPlayerListener.java
@@ -0,0 +1,72 @@
+/*
+ * BasicPlayerListener.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.basicplayer;
+
+import java.util.Map;
+
+/**
+ * This interface defines callbacks methods that will be notified
+ * for all registered BasicPlayerListener of BasicPlayer.
+ */
+public interface BasicPlayerListener
+{
+ /**
+ * Open callback, stream is ready to play.
+ *
+ * properties map includes audio format dependant features such as
+ * bitrate, duration, frequency, channels, number of frames, vbr flag,
+ * id3v2/id3v1 (for MP3 only), comments (for Ogg Vorbis), ...
+ *
+ * @param stream could be File, URL or InputStream
+ * @param properties audio stream properties.
+ */
+ public void opened(Object stream, Map properties);
+
+ /**
+ * Progress callback while playing.
+ *
+ * This method is called severals time per seconds while playing.
+ * properties map includes audio format features such as
+ * instant bitrate, microseconds position, current frame number, ...
+ *
+ * @param bytesread from encoded stream.
+ * @param microseconds elapsed (reseted after a seek !).
+ * @param pcmdata PCM samples.
+ * @param properties audio stream parameters.
+ */
+ public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties);
+
+ /**
+ * Notification callback for basicplayer events such as opened, eom ...
+ *
+ * @param event
+ */
+ public void stateUpdated(BasicPlayerEvent event);
+
+ /**
+ * A handle to the BasicPlayer, plugins may control the player through
+ * the controller (play, stop, ...)
+ * @param controller : a handle to the player
+ */
+ public void setController(BasicController controller);
+}
diff --git a/java/src/javazoom/jlgui/player/amp/Loader.java b/java/src/javazoom/jlgui/player/amp/Loader.java
new file mode 100644
index 0000000..dd70ea9
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/Loader.java
@@ -0,0 +1,40 @@
+/*
+ * Loader.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp;
+
+import java.awt.Point;
+
+public interface Loader
+{
+ public void loaded();
+
+ public void close();
+
+ public void minimize();
+
+ public Point getLocation();
+
+ public void togglePlaylist(boolean enabled);
+
+ public void toggleEqualizer(boolean enabled);
+}
diff --git a/java/src/javazoom/jlgui/player/amp/PlayerActionEvent.java b/java/src/javazoom/jlgui/player/amp/PlayerActionEvent.java
new file mode 100644
index 0000000..0c1b98c
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/PlayerActionEvent.java
@@ -0,0 +1,99 @@
+/*
+ * PlayerActionEvent.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp;
+
+import java.awt.event.ActionEvent;
+
+public class PlayerActionEvent extends ActionEvent
+{
+ public static final String ACPREVIOUS = "Previous";
+ public static final String ACPLAY = "Play";
+ public static final String ACPAUSE = "Pause";
+ public static final String ACSTOP = "Stop";
+ public static final String ACNEXT = "Next";
+ public static final String ACEJECT = "Eject";
+ public static final String ACEQUALIZER = "EqualizerUI";
+ public static final String ACPLAYLIST = "Playlist";
+ public static final String ACSHUFFLE = "Shuffle";
+ public static final String ACREPEAT = "Repeat";
+ public static final String ACVOLUME = "Volume";
+ public static final String ACBALANCE = "Balance";
+ public static final String ACTITLEBAR = "TitleBar";
+ public static final String ACEXIT = "Exit";
+ public static final String ACMINIMIZE = "Minimize";
+ public static final String ACPOSBAR = "Seek";
+ public static final String MIPLAYFILE = "PlayFileMI";
+ public static final String MIPLAYLOCATION = "PlayLocationMI";
+ public static final String MIPLAYLIST = "PlaylistMI";
+ public static final String MIEQUALIZER = "EqualizerMI";
+ public static final String MIPREFERENCES = "PreferencesMI";
+ public static final String MISKINBROWSER = "SkinBrowserMI";
+ public static final String MILOADSKIN = "LoadSkinMI";
+ public static final String MIJUMPFILE = "JumpFileMI";
+ public static final String MISTOP = "StopMI";
+ public static final String EQSLIDER = "SliderEQ";
+ public static final String ACEQPRESETS = "PresetsEQ";
+ public static final String ACEQONOFF = "OnOffEQ";
+ public static final String ACEQAUTO = "AutoEQ";
+ public static final String ACPLUP = "ScrollUpPL";
+ public static final String ACPLDOWN = "ScrollDownPL";
+ public static final String ACPLINFO = "InfoPL";
+ public static final String ACPLPLAY = "PlayPL";
+ public static final String ACPLREMOVE = "RemovePL";
+ public static final String ACPLADDPOPUP = "AddPopupPL";
+ public static final String ACPLADDFILE = "AddFilePL";
+ public static final String ACPLADDDIR = "AddDirPL";
+ public static final String ACPLADDURL = "AddURLPL";
+ public static final String ACPLREMOVEPOPUP = "RemovePopupPL";
+ public static final String ACPLREMOVEMISC = "RemoveMiscPL";
+ public static final String ACPLREMOVESEL = "RemoveSelPL";
+ public static final String ACPLREMOVEALL = "RemoveAllPL";
+ public static final String ACPLREMOVECROP = "RemoveCropPL";
+ public static final String ACPLSELPOPUP = "SelectPopupPL";
+ public static final String ACPLSELALL = "SelectAllPL";
+ public static final String ACPLSELZERO = "SelectZeroPL";
+ public static final String ACPLSELINV = "SelectInvPL";
+ public static final String ACPLMISCPOPUP = "MiscPopupPL";
+ public static final String ACPLMISCOPTS = "MiscOptsPL";
+ public static final String ACPLMISCFILE = "MiscFilePL";
+ public static final String ACPLMISCSORT = "MiscSortPL";
+ public static final String ACPLLISTPOPUP = "ListPopupPL";
+ public static final String ACPLLISTLOAD = "ListLoadPL";
+ public static final String ACPLLISTSAVE = "ListSavePL";
+ public static final String ACPLLISTNEW = "ListNewPL";
+
+ public PlayerActionEvent(Object source, int id, String command)
+ {
+ super(source, id, command);
+ }
+
+ public PlayerActionEvent(Object source, int id, String command, int modifiers)
+ {
+ super(source, id, command, modifiers);
+ }
+
+ public PlayerActionEvent(Object source, int id, String command, long when, int modifiers)
+ {
+ super(source, id, command, when, modifiers);
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/PlayerUI.java b/java/src/javazoom/jlgui/player/amp/PlayerUI.java
new file mode 100644
index 0000000..9cf9df4
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/PlayerUI.java
@@ -0,0 +1,1827 @@
+/*
+ * PlayerUI.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp;
+
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTarget;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.StringTokenizer;
+import javax.sound.sampled.SourceDataLine;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javazoom.jlgui.basicplayer.BasicController;
+import javazoom.jlgui.basicplayer.BasicPlayer;
+import javazoom.jlgui.basicplayer.BasicPlayerEvent;
+import javazoom.jlgui.basicplayer.BasicPlayerException;
+import javazoom.jlgui.basicplayer.BasicPlayerListener;
+import javazoom.jlgui.player.amp.equalizer.ui.EqualizerUI;
+import javazoom.jlgui.player.amp.playlist.Playlist;
+import javazoom.jlgui.player.amp.playlist.PlaylistFactory;
+import javazoom.jlgui.player.amp.playlist.PlaylistItem;
+import javazoom.jlgui.player.amp.playlist.ui.PlaylistUI;
+import javazoom.jlgui.player.amp.skin.AbsoluteLayout;
+import javazoom.jlgui.player.amp.skin.DropTargetAdapter;
+import javazoom.jlgui.player.amp.skin.ImageBorder;
+import javazoom.jlgui.player.amp.skin.PopupAdapter;
+import javazoom.jlgui.player.amp.skin.Skin;
+import javazoom.jlgui.player.amp.skin.UrlDialog;
+import javazoom.jlgui.player.amp.tag.ui.TagSearch;
+import javazoom.jlgui.player.amp.util.Config;
+import javazoom.jlgui.player.amp.util.FileSelector;
+import javazoom.jlgui.player.amp.util.ui.Preferences;
+import javazoom.jlgui.player.amp.visual.ui.SpectrumTimeAnalyzer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class PlayerUI extends JPanel implements ActionListener, ChangeListener, BasicPlayerListener
+{
+ private static Log log = LogFactory.getLog(PlayerUI.class);
+ public static final int INIT = 0;
+ public static final int OPEN = 1;
+ public static final int PLAY = 2;
+ public static final int PAUSE = 3;
+ public static final int STOP = 4;
+ public static final int TEXT_LENGTH_MAX = 30;
+ public static final long SCROLL_PERIOD = 250;
+ private Skin ui = null;
+ private Loader loader = null;
+ private Config config = null;
+ /*-- Pop up menus --*/
+ private JPopupMenu mainpopup = null;
+ private JPopupMenu ejectpopup = null;
+ private JCheckBoxMenuItem miPlaylist = null;
+ private JCheckBoxMenuItem miEqualizer = null;
+ private JMenuItem miPlayFile = null;
+ private JMenuItem miPlayLocation = null;
+ private PopupAdapter popupAdapter = null;
+ private PopupAdapter ejectpopupAdapter = null;
+ /*-- Sound player --*/
+ private BasicController theSoundPlayer = null;
+ private Map audioInfo = null;
+ private int playerState = INIT;
+ /*-- Title text --*/
+ private String titleText = Skin.TITLETEXT.toUpperCase();
+ private String currentTitle = Skin.TITLETEXT.toUpperCase();
+ private String[] titleScrollLabel = null;
+ private int scrollIndex = 0;
+ private long lastScrollTime = 0L;
+ private boolean scrollRight = true;
+ private long secondsAmount = 0;
+ /*-- Playlist --*/
+ private Playlist playlist = null;
+ private PlaylistUI playlistUI = null;
+ private String currentFileOrURL = null;
+ private String currentSongName = null;
+ private PlaylistItem currentPlaylistItem = null;
+ private boolean currentIsFile;
+ /*-- PosBar members --*/
+ private boolean posValueJump = false;
+ private boolean posDragging = false;
+ private double posValue = 0.0;
+ /*-- EqualizerUI --*/
+ private EqualizerUI equalizerUI = null;
+
+ public PlayerUI()
+ {
+ super();
+ setDoubleBuffered(true);
+ ui = new Skin();
+ }
+
+ public void setEqualizerUI(EqualizerUI eq)
+ {
+ equalizerUI = eq;
+ }
+
+ public EqualizerUI getEqualizerUI()
+ {
+ return equalizerUI;
+ }
+
+ public PlaylistUI getPlaylistUI()
+ {
+ return playlistUI;
+ }
+
+ public void setPlaylistUI(PlaylistUI playlistUI)
+ {
+ this.playlistUI = playlistUI;
+ }
+
+ public Playlist getPlaylist()
+ {
+ return playlist;
+ }
+
+ /**
+ * Return config.
+ * @return
+ */
+ public Config getConfig()
+ {
+ return config;
+ }
+
+ /**
+ * Return skin.
+ * @return
+ */
+ public Skin getSkin()
+ {
+ return ui;
+ }
+
+ /**
+ * Return parent loader.
+ * @return
+ */
+ public Loader getLoader()
+ {
+ return loader;
+ }
+
+ /**
+ * A handle to the BasicPlayer, plugins may control the player through
+ * the controller (play, stop, ...)
+ * @param controller
+ */
+ public void setController(BasicController controller)
+ {
+ theSoundPlayer = controller;
+ }
+
+ /**
+ * Return player controller.
+ * @return
+ */
+ public BasicController getController()
+ {
+ return theSoundPlayer;
+ }
+
+ /**
+ * Load main player.
+ * @param loader
+ */
+ public void loadUI(Loader loader)
+ {
+ this.loader = loader;
+ setLayout(new AbsoluteLayout());
+ config = Config.getInstance();
+ ui.setConfig(config);
+ playlistUI = new PlaylistUI();
+ playlistUI.setSkin(ui);
+ playlistUI.setPlayer(this);
+ equalizerUI = new EqualizerUI();
+ equalizerUI.setSkin(ui);
+ loadSkin();
+ // DnD support.
+ DropTargetAdapter dnd = new DropTargetAdapter()
+ {
+ public void processDrop(Object data)
+ {
+ processDnD(data);
+ }
+ };
+ DropTarget dt = new DropTarget(this, DnDConstants.ACTION_COPY, dnd, true);
+ }
+
+ public void loadSkin()
+ {
+ log.info("Load PlayerUI (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ removeAll();
+ // Load skin specified in args
+ if (ui.getPath() != null)
+ {
+ log.info("Load default skin from " + ui.getPath());
+ ui.loadSkin(ui.getPath());
+ config.setDefaultSkin(ui.getPath());
+ }
+ // Load skin specified in jlgui.ini
+ else if ((config.getDefaultSkin() != null) && (!config.getDefaultSkin().trim().equals("")))
+ {
+ log.info("Load default skin from " + config.getDefaultSkin());
+ ui.loadSkin(config.getDefaultSkin());
+ }
+ // Default included skin
+ else
+ {
+ ClassLoader cl = getClass().getClassLoader();
+ InputStream sis = cl.getResourceAsStream("javazoom/jlgui/player/amp/metrix.wsz");
+ log.info("Load default skin for JAR");
+ ui.loadSkin(sis);
+ }
+ // Background
+ ImageBorder border = new ImageBorder();
+ border.setImage(ui.getMainImage());
+ setBorder(border);
+ // Buttons
+ add(ui.getAcPrevious(), ui.getAcPrevious().getConstraints());
+ ui.getAcPrevious().removeActionListener(this);
+ ui.getAcPrevious().addActionListener(this);
+ add(ui.getAcPlay(), ui.getAcPlay().getConstraints());
+ ui.getAcPlay().removeActionListener(this);
+ ui.getAcPlay().addActionListener(this);
+ add(ui.getAcPause(), ui.getAcPause().getConstraints());
+ ui.getAcPause().removeActionListener(this);
+ ui.getAcPause().addActionListener(this);
+ add(ui.getAcStop(), ui.getAcStop().getConstraints());
+ ui.getAcStop().removeActionListener(this);
+ ui.getAcStop().addActionListener(this);
+ add(ui.getAcNext(), ui.getAcNext().getConstraints());
+ ui.getAcNext().removeActionListener(this);
+ ui.getAcNext().addActionListener(this);
+ add(ui.getAcEject(), ui.getAcEject().getConstraints());
+ ui.getAcEject().removeActionListener(this);
+ ui.getAcEject().addActionListener(this);
+ // EqualizerUI toggle
+ add(ui.getAcEqualizer(), ui.getAcEqualizer().getConstraints());
+ ui.getAcEqualizer().removeActionListener(this);
+ ui.getAcEqualizer().addActionListener(this);
+ // Playlist toggle
+ add(ui.getAcPlaylist(), ui.getAcPlaylist().getConstraints());
+ ui.getAcPlaylist().removeActionListener(this);
+ ui.getAcPlaylist().addActionListener(this);
+ // Shuffle toggle
+ add(ui.getAcShuffle(), ui.getAcShuffle().getConstraints());
+ ui.getAcShuffle().removeActionListener(this);
+ ui.getAcShuffle().addActionListener(this);
+ // Repeat toggle
+ add(ui.getAcRepeat(), ui.getAcRepeat().getConstraints());
+ ui.getAcRepeat().removeActionListener(this);
+ ui.getAcRepeat().addActionListener(this);
+ // Volume
+ add(ui.getAcVolume(), ui.getAcVolume().getConstraints());
+ ui.getAcVolume().removeChangeListener(this);
+ ui.getAcVolume().addChangeListener(this);
+ // Balance
+ add(ui.getAcBalance(), ui.getAcBalance().getConstraints());
+ ui.getAcBalance().removeChangeListener(this);
+ ui.getAcBalance().addChangeListener(this);
+ // Seek bar
+ add(ui.getAcPosBar(), ui.getAcPosBar().getConstraints());
+ ui.getAcPosBar().removeChangeListener(this);
+ ui.getAcPosBar().addChangeListener(this);
+ // Mono
+ add(ui.getAcMonoIcon(), ui.getAcMonoIcon().getConstraints());
+ // Stereo
+ add(ui.getAcStereoIcon(), ui.getAcStereoIcon().getConstraints());
+ // Title label
+ add(ui.getAcTitleLabel(), ui.getAcTitleLabel().getConstraints());
+ // Sample rate label
+ add(ui.getAcSampleRateLabel(), ui.getAcSampleRateLabel().getConstraints());
+ // Bit rate label
+ add(ui.getAcBitRateLabel(), ui.getAcBitRateLabel().getConstraints());
+ // Play icon
+ add(ui.getAcPlayIcon(), ui.getAcPlayIcon().getConstraints());
+ // Time icon
+ add(ui.getAcTimeIcon(), ui.getAcTimeIcon().getConstraints());
+ // MinuteH number
+ add(ui.getAcMinuteH(), ui.getAcMinuteH().getConstraints());
+ // MinuteL number
+ add(ui.getAcMinuteL(), ui.getAcMinuteL().getConstraints());
+ // SecondH number
+ add(ui.getAcSecondH(), ui.getAcSecondH().getConstraints());
+ // SecondL number
+ add(ui.getAcSecondL(), ui.getAcSecondL().getConstraints());
+ // TitleBar
+ add(ui.getAcTitleBar(), ui.getAcTitleBar().getConstraints());
+ add(ui.getAcMinimize(), ui.getAcMinimize().getConstraints());
+ ui.getAcMinimize().removeActionListener(this);
+ ui.getAcMinimize().addActionListener(this);
+ add(ui.getAcExit(), ui.getAcExit().getConstraints());
+ ui.getAcExit().removeActionListener(this);
+ ui.getAcExit().addActionListener(this);
+ // DSP
+ if (ui.getAcAnalyzer() != null)
+ {
+ add(ui.getAcAnalyzer(), ui.getAcAnalyzer().getConstraints());
+ }
+ // Popup menu
+ mainpopup = new JPopupMenu(ui.getResource("popup.title"));
+ JMenuItem mi = new JMenuItem(Skin.TITLETEXT + "- JavaZOOM");
+ //mi.removeActionListener(this);
+ //mi.addActionListener(this);
+ mainpopup.add(mi);
+ mainpopup.addSeparator();
+ JMenu playSubMenu = new JMenu(ui.getResource("popup.play"));
+ miPlayFile = new JMenuItem(ui.getResource("popup.play.file"));
+ miPlayFile.setActionCommand(PlayerActionEvent.MIPLAYFILE);
+ miPlayFile.removeActionListener(this);
+ miPlayFile.addActionListener(this);
+ miPlayLocation = new JMenuItem(ui.getResource("popup.play.location"));
+ miPlayLocation.setActionCommand(PlayerActionEvent.MIPLAYLOCATION);
+ miPlayLocation.removeActionListener(this);
+ miPlayLocation.addActionListener(this);
+ playSubMenu.add(miPlayFile);
+ playSubMenu.add(miPlayLocation);
+ mainpopup.add(playSubMenu);
+ mainpopup.addSeparator();
+ miPlaylist = new JCheckBoxMenuItem(ui.getResource("popup.playlist"));
+ miPlaylist.setActionCommand(PlayerActionEvent.MIPLAYLIST);
+ if (config.isPlaylistEnabled()) miPlaylist.setState(true);
+ miPlaylist.removeActionListener(this);
+ miPlaylist.addActionListener(this);
+ mainpopup.add(miPlaylist);
+ miEqualizer = new JCheckBoxMenuItem(ui.getResource("popup.equalizer"));
+ miEqualizer.setActionCommand(PlayerActionEvent.MIEQUALIZER);
+ if (config.isEqualizerEnabled()) miEqualizer.setState(true);
+ miEqualizer.removeActionListener(this);
+ miEqualizer.addActionListener(this);
+ mainpopup.add(miEqualizer);
+ mainpopup.addSeparator();
+ mi = new JMenuItem(ui.getResource("popup.preferences"));
+ mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.CTRL_MASK, false));
+ mi.setActionCommand(PlayerActionEvent.MIPREFERENCES);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ mainpopup.add(mi);
+ JMenu skinsSubMenu = new JMenu(ui.getResource("popup.skins"));
+ mi = new JMenuItem(ui.getResource("popup.skins.browser"));
+ mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.ALT_MASK, false));
+ mi.setActionCommand(PlayerActionEvent.MISKINBROWSER);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ skinsSubMenu.add(mi);
+ mi = new JMenuItem(ui.getResource("popup.skins.load"));
+ mi.setActionCommand(PlayerActionEvent.MILOADSKIN);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ skinsSubMenu.add(mi);
+ mainpopup.add(skinsSubMenu);
+ JMenu playbackSubMenu = new JMenu(ui.getResource("popup.playback"));
+ mi = new JMenuItem(ui.getResource("popup.playback.jump"));
+ mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_J, 0, false));
+ mi.setActionCommand(PlayerActionEvent.MIJUMPFILE);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ playbackSubMenu.add(mi);
+ mi = new JMenuItem(ui.getResource("popup.playback.stop"));
+ mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, 0, false));
+ mi.setActionCommand(PlayerActionEvent.MISTOP);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ playbackSubMenu.add(mi);
+ mainpopup.add(playbackSubMenu);
+ mainpopup.addSeparator();
+ mi = new JMenuItem(ui.getResource("popup.exit"));
+ mi.setActionCommand(PlayerActionEvent.ACEXIT);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ mainpopup.add(mi);
+ // Popup menu on TitleBar
+ ui.getAcTitleBar().removeMouseListener(popupAdapter);
+ popupAdapter = new PopupAdapter(mainpopup);
+ ui.getAcTitleBar().addMouseListener(popupAdapter);
+ // Popup menu on Eject button
+ ejectpopup = new JPopupMenu();
+ mi = new JMenuItem(ui.getResource("popup.eject.openfile"));
+ mi.setActionCommand(PlayerActionEvent.MIPLAYFILE);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ ejectpopup.add(mi);
+ mi = new JMenuItem(ui.getResource("popup.eject.openlocation"));
+ mi.setActionCommand(PlayerActionEvent.MIPLAYLOCATION);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ ejectpopup.add(mi);
+ ui.getAcEject().removeMouseListener(ejectpopupAdapter);
+ ejectpopupAdapter = new PopupAdapter(ejectpopup);
+ ui.getAcEject().addMouseListener(ejectpopupAdapter);
+ // EqualizerUI
+ if (equalizerUI != null) equalizerUI.loadUI();
+ if (playlistUI != null) playlistUI.loadUI();
+ validate();
+ loader.loaded();
+ }
+
+ /**
+ * Load playlist.
+ * @param playlistName
+ * @return
+ */
+ public boolean loadPlaylist(String playlistName)
+ {
+ boolean loaded = false;
+ PlaylistFactory plf = PlaylistFactory.getInstance();
+ playlist = plf.getPlaylist();
+ if (playlist == null)
+ {
+ config.setPlaylistClassName("javazoom.jlgui.player.amp.playlist.BasePlaylist");
+ playlist = plf.getPlaylist();
+ }
+ playlistUI.setPlaylist(playlist);
+ if ((playlistName != null) && (!playlistName.equals("")))
+ {
+ // M3U file or URL.
+ if ((playlistName.toLowerCase().endsWith(ui.getResource("playlist.extension.m3u"))) || (playlistName.toLowerCase().endsWith(ui.getResource("playlist.extension.pls")))) loaded = playlist.load(playlistName);
+ // Simple song.
+ else
+ {
+ String name = playlistName;
+ if (!Config.startWithProtocol(playlistName))
+ {
+ int indn = playlistName.lastIndexOf(java.io.File.separatorChar);
+ if (indn != -1) name = playlistName.substring(indn + 1);
+ PlaylistItem pli = new PlaylistItem(name, playlistName, -1, true);
+ playlist.appendItem(pli);
+ loaded = true;
+ }
+ else
+ {
+ PlaylistItem pli = new PlaylistItem(name, playlistName, -1, false);
+ playlist.appendItem(pli);
+ loaded = true;
+ }
+ }
+ }
+ return loaded;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
+ */
+ public void stateChanged(ChangeEvent e)
+ {
+ Object src = e.getSource();
+ //log.debug("State (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ // Volume
+ if (src == ui.getAcVolume())
+ {
+ Object[] args = { String.valueOf(ui.getAcVolume().getValue()) };
+ String volumeText = MessageFormat.format(ui.getResource("slider.volume.text"), args);
+ ui.getAcTitleLabel().setAcText(volumeText);
+ try
+ {
+ int gainValue = ui.getAcVolume().getValue();
+ int maxGain = ui.getAcVolume().getMaximum();
+ if (gainValue == 0) theSoundPlayer.setGain(0);
+ else theSoundPlayer.setGain(((double) gainValue / (double) maxGain));
+ config.setVolume(gainValue);
+ }
+ catch (BasicPlayerException ex)
+ {
+ log.debug("Cannot set gain", ex);
+ }
+ }
+ // Balance
+ else if (src == ui.getAcBalance())
+ {
+ Object[] args = { String.valueOf(Math.abs(ui.getAcBalance().getValue() * 100 / Skin.BALANCEMAX)) };
+ String balanceText = null;
+ if (ui.getAcBalance().getValue() > 0)
+ {
+ balanceText = MessageFormat.format(ui.getResource("slider.balance.text.right"), args);
+ }
+ else if (ui.getAcBalance().getValue() < 0)
+ {
+ balanceText = MessageFormat.format(ui.getResource("slider.balance.text.left"), args);
+ }
+ else
+ {
+ balanceText = MessageFormat.format(ui.getResource("slider.balance.text.center"), args);
+ }
+ ui.getAcTitleLabel().setAcText(balanceText);
+ try
+ {
+ float balanceValue = ui.getAcBalance().getValue() * 1.0f / Skin.BALANCEMAX;
+ theSoundPlayer.setPan(balanceValue);
+ }
+ catch (BasicPlayerException ex)
+ {
+ log.debug("Cannot set pan", ex);
+ }
+ }
+ else if (src == ui.getAcPosBar())
+ {
+ if (ui.getAcPosBar().getValueIsAdjusting() == false)
+ {
+ if (posDragging == true)
+ {
+ posDragging = false;
+ posValue = ui.getAcPosBar().getValue() * 1.0 / Skin.POSBARMAX;
+ processSeek(posValue);
+ }
+ }
+ else
+ {
+ posDragging = true;
+ posValueJump = true;
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ final ActionEvent evt = e;
+ if (e.getActionCommand().equals(PlayerActionEvent.ACPAUSE))
+ {
+ processActionEvent(e);
+ }
+ else if ((e.getActionCommand().equals(PlayerActionEvent.ACPLAY)) && (playerState == PAUSE))
+ {
+ processActionEvent(e);
+ }
+ else
+ {
+ new Thread("PlayerUIActionEvent")
+ {
+ public void run()
+ {
+ processActionEvent(evt);
+ }
+ }.start();
+ }
+ }
+
+ /**
+ * Process action event.
+ * @param e
+ */
+ public void processActionEvent(ActionEvent e)
+ {
+ String cmd = e.getActionCommand();
+ log.debug("Action=" + cmd + " (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ // Preferences.
+ if (cmd.equalsIgnoreCase(PlayerActionEvent.MIPREFERENCES))
+ {
+ processPreferences(e.getModifiers());
+ }
+ // Skin browser
+ else if (cmd.equals(PlayerActionEvent.MISKINBROWSER))
+ {
+ processSkinBrowser(e.getModifiers());
+ }
+ // Jump to file
+ else if (cmd.equals(PlayerActionEvent.MIJUMPFILE))
+ {
+ processJumpToFile(e.getModifiers());
+ }
+ // Stop
+ else if (cmd.equals(PlayerActionEvent.MISTOP))
+ {
+ processStop(MouseEvent.BUTTON1_MASK);
+ }
+ // Load skin
+ else if (e.getActionCommand().equals(PlayerActionEvent.MILOADSKIN))
+ {
+ File[] file = FileSelector.selectFile(loader, FileSelector.OPEN, false, ui.getResource("skin.extension"), ui.getResource("loadskin.dialog.filtername"), new File(config.getLastDir()));
+ if (FileSelector.getInstance().getDirectory() != null) config.setLastDir(FileSelector.getInstance().getDirectory().getPath());
+ if (file != null)
+ {
+ String fsFile = file[0].getName();
+ ui.setPath(config.getLastDir() + fsFile);
+ loadSkin();
+ config.setDefaultSkin(ui.getPath());
+ }
+ }
+ // Shuffle
+ else if (cmd.equals(PlayerActionEvent.ACSHUFFLE))
+ {
+ if (ui.getAcShuffle().isSelected())
+ {
+ config.setShuffleEnabled(true);
+ if (playlist != null)
+ {
+ playlist.shuffle();
+ playlistUI.initPlayList();
+ // Play from the top
+ PlaylistItem pli = playlist.getCursor();
+ setCurrentSong(pli);
+ }
+ }
+ else
+ {
+ config.setShuffleEnabled(false);
+ }
+ }
+ // Repeat
+ else if (cmd.equals(PlayerActionEvent.ACREPEAT))
+ {
+ if (ui.getAcRepeat().isSelected())
+ {
+ config.setRepeatEnabled(true);
+ }
+ else
+ {
+ config.setRepeatEnabled(false);
+ }
+ }
+ // Play file
+ else if (cmd.equals(PlayerActionEvent.MIPLAYFILE))
+ {
+ processEject(MouseEvent.BUTTON1_MASK);
+ }
+ // Play URL
+ else if (cmd.equals(PlayerActionEvent.MIPLAYLOCATION))
+ {
+ processEject(MouseEvent.BUTTON3_MASK);
+ }
+ // Playlist menu item
+ else if (cmd.equals(PlayerActionEvent.MIPLAYLIST))
+ {
+ ui.getAcPlaylist().setSelected(miPlaylist.getState());
+ togglePlaylist();
+ }
+ // Playlist toggle button
+ else if (cmd.equals(PlayerActionEvent.ACPLAYLIST))
+ {
+ togglePlaylist();
+ }
+ // EqualizerUI menu item
+ else if (cmd.equals(PlayerActionEvent.MIEQUALIZER))
+ {
+ ui.getAcEqualizer().setSelected(miEqualizer.getState());
+ toggleEqualizer();
+ }
+ // EqualizerUI
+ else if (cmd.equals(PlayerActionEvent.ACEQUALIZER))
+ {
+ toggleEqualizer();
+ }
+ // Exit player
+ else if (cmd.equals(PlayerActionEvent.ACEXIT))
+ {
+ closePlayer();
+ }
+ // Minimize
+ else if (cmd.equals(PlayerActionEvent.ACMINIMIZE))
+ {
+ loader.minimize();
+ }
+ // Eject
+ else if (cmd.equals(PlayerActionEvent.ACEJECT))
+ {
+ processEject(e.getModifiers());
+ }
+ // Play
+ else if (cmd.equals(PlayerActionEvent.ACPLAY))
+ {
+ processPlay(e.getModifiers());
+ }
+ // Pause
+ else if (cmd.equals(PlayerActionEvent.ACPAUSE))
+ {
+ processPause(e.getModifiers());
+ }
+ // Stop
+ else if (cmd.equals(PlayerActionEvent.ACSTOP))
+ {
+ processStop(e.getModifiers());
+ }
+ // Next
+ else if (cmd.equals(PlayerActionEvent.ACNEXT))
+ {
+ processNext(e.getModifiers());
+ }
+ // Previous
+ else if (cmd.equals(PlayerActionEvent.ACPREVIOUS))
+ {
+ processPrevious(e.getModifiers());
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javazoom.jlgui.basicplayer.BasicPlayerListener#opened(java.lang.Object, java.util.Map)
+ */
+ public void opened(Object stream, Map properties)
+ {
+ // Not in EDT.
+ audioInfo = properties;
+ log.debug(properties.toString());
+ }
+
+ /* (non-Javadoc)
+ * @see javazoom.jlgui.basicplayer.BasicPlayerListener#stateUpdated(javazoom.jlgui.basicplayer.BasicPlayerEvent)
+ */
+ public void stateUpdated(final BasicPlayerEvent event)
+ {
+ // Not in EDT.
+ processStateUpdated(event);
+ }
+
+ /* (non-Javadoc)
+ * @see javazoom.jlgui.basicplayer.BasicPlayerListener#progress(int, long, byte[], java.util.Map)
+ */
+ public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties)
+ {
+ // Not in EDT.
+ processProgress(bytesread, microseconds, pcmdata, properties);
+ }
+
+ /**
+ * Process PREFERENCES event.
+ * @param modifiers
+ */
+ protected void processPreferences(int modifiers)
+ {
+ Preferences preferences = Preferences.getInstance(this);
+ preferences.setLocation(loader.getLocation().x, loader.getLocation().y);
+ preferences.setSize(512, 350);
+ preferences.setVisible(true);
+ }
+
+ /**
+ * Process SKINS BROWSER event.
+ * @param modifiers
+ */
+ protected void processSkinBrowser(int modifiers)
+ {
+ Preferences preferences = Preferences.getInstance(this);
+ preferences.selectSkinBrowserPane();
+ preferences.setLocation(loader.getLocation().x, loader.getLocation().y);
+ preferences.setSize(512, 350);
+ preferences.setVisible(true);
+ }
+
+ /**
+ * Process JUMP FILE event.
+ * @param modifiers
+ */
+ protected void processJumpToFile(int modifiers)
+ {
+ TagSearch ts = new TagSearch(this);
+ ts.setIconImage(config.getIconParent().getImage());
+ ts.setSize(400, 300);
+ ts.setLocation(loader.getLocation());
+ ts.display();
+ }
+
+ /**
+ * Process EJECT event.
+ * @param modifiers
+ */
+ protected void processEject(int modifiers)
+ {
+ if ((playerState == PLAY) || (playerState == PAUSE))
+ {
+ try
+ {
+ if (theSoundPlayer != null)
+ {
+ theSoundPlayer.stop();
+ }
+ }
+ catch (BasicPlayerException e)
+ {
+ log.info("Cannot stop", e);
+ }
+ playerState = STOP;
+ }
+ if ((playerState == INIT) || (playerState == STOP) || (playerState == OPEN))
+ {
+ PlaylistItem pli = null;
+ // Local File.
+ if (modifiers == MouseEvent.BUTTON1_MASK)
+ {
+ File[] file = FileSelector.selectFile(loader, FileSelector.OPEN, false, config.getExtensions(), ui.getResource("button.eject.filedialog.filtername"), new File(config.getLastDir()));
+ if (FileSelector.getInstance().getDirectory() != null) config.setLastDir(FileSelector.getInstance().getDirectory().getPath());
+ if (file != null)
+ {
+ String fsFile = file[0].getName();
+ if (fsFile != null)
+ {
+ // Loads a new playlist.
+ if ((fsFile.toLowerCase().endsWith(ui.getResource("playlist.extension.m3u"))) || (fsFile.toLowerCase().endsWith(ui.getResource("playlist.extension.pls"))))
+ {
+ if (loadPlaylist(config.getLastDir() + fsFile))
+ {
+ config.setPlaylistFilename(config.getLastDir() + fsFile);
+ playlist.begin();
+ playlistUI.initPlayList();
+ setCurrentSong(playlist.getCursor());
+ playlistUI.repaint();
+ }
+ }
+ else if (fsFile.toLowerCase().endsWith(ui.getResource("skin.extension")))
+ {
+ ui.setPath(config.getLastDir() + fsFile);
+ loadSkin();
+ config.setDefaultSkin(ui.getPath());
+ }
+ else pli = new PlaylistItem(fsFile, config.getLastDir() + fsFile, -1, true);
+ }
+ }
+ }
+ // Remote File.
+ else if (modifiers == MouseEvent.BUTTON3_MASK)
+ {
+ UrlDialog UD = new UrlDialog(config.getTopParent(), ui.getResource("button.eject.urldialog.title"), loader.getLocation().x, loader.getLocation().y + 10, config.getLastURL());
+ UD.show();
+ if (UD.getFile() != null)
+ {
+ showTitle(ui.getResource("title.loading"));
+ // Remote playlist ?
+ if ((UD.getURL().toLowerCase().endsWith(ui.getResource("playlist.extension.m3u"))) || (UD.getURL().toLowerCase().endsWith(ui.getResource("playlist.extension.pls"))))
+ {
+ if (loadPlaylist(UD.getURL()))
+ {
+ config.setPlaylistFilename(UD.getURL());
+ playlist.begin();
+ playlistUI.initPlayList();
+ setCurrentSong(playlist.getCursor());
+ playlistUI.repaint();
+ }
+ }
+ // Remote file or stream.
+ else
+ {
+ pli = new PlaylistItem(UD.getFile(), UD.getURL(), -1, false);
+ }
+ config.setLastURL(UD.getURL());
+ }
+ }
+ if ((pli != null) && (playlist != null))
+ {
+ playlist.removeAllItems();
+ playlist.appendItem(pli);
+ playlist.nextCursor();
+ playlistUI.initPlayList();
+ setCurrentSong(pli);
+ playlistUI.repaint();
+ }
+ }
+ // Display play/time icons.
+ ui.getAcPlayIcon().setIcon(2);
+ ui.getAcTimeIcon().setIcon(1);
+ }
+
+ /**
+ * Process PLAY event.
+ * @param modifiers
+ */
+ protected void processPlay(int modifiers)
+ {
+ if (playlist.isModified()) // playlist has been modified since we were last there, must update our cursor pos etc.
+ {
+ PlaylistItem pli = playlist.getCursor();
+ if (pli == null)
+ {
+ playlist.begin();
+ pli = playlist.getCursor();
+ }
+ setCurrentSong(pli);
+ playlist.setModified(false);
+ playlistUI.repaint();
+ }
+ // Resume is paused.
+ if (playerState == PAUSE)
+ {
+ try
+ {
+ theSoundPlayer.resume();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.error("Cannot resume", e);
+ }
+ playerState = PLAY;
+ ui.getAcPlayIcon().setIcon(0);
+ ui.getAcTimeIcon().setIcon(0);
+ }
+ // Stop if playing.
+ else if (playerState == PLAY)
+ {
+ try
+ {
+ theSoundPlayer.stop();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.error("Cannot stop", e);
+ }
+ playerState = PLAY;
+ secondsAmount = 0;
+ ui.getAcMinuteH().setAcText("0");
+ ui.getAcMinuteL().setAcText("0");
+ ui.getAcSecondH().setAcText("0");
+ ui.getAcSecondL().setAcText("0");
+ if (currentFileOrURL != null)
+ {
+ try
+ {
+ if (currentIsFile == true) theSoundPlayer.open(openFile(currentFileOrURL));
+ else
+ {
+ theSoundPlayer.open(new URL(currentFileOrURL));
+ }
+ theSoundPlayer.play();
+ }
+ catch (Exception ex)
+ {
+ log.error("Cannot read file : " + currentFileOrURL, ex);
+ showMessage(ui.getResource("title.invalidfile"));
+ }
+ }
+ }
+ else if ((playerState == STOP) || (playerState == OPEN))
+ {
+ try
+ {
+ theSoundPlayer.stop();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.error("Stop failed", e);
+ }
+ if (currentFileOrURL != null)
+ {
+ try
+ {
+ if (currentIsFile == true) theSoundPlayer.open(openFile(currentFileOrURL));
+ else theSoundPlayer.open(new URL(currentFileOrURL));
+ theSoundPlayer.play();
+ titleText = currentSongName.toUpperCase();
+ // Get bitrate, samplingrate, channels, time in the following order :
+ // PlaylistItem, BasicPlayer (JavaSound SPI), Manual computation.
+ int bitRate = -1;
+ if (currentPlaylistItem != null) bitRate = currentPlaylistItem.getBitrate();
+ if ((bitRate <= 0) && (audioInfo.containsKey("bitrate"))) bitRate = ((Integer) audioInfo.get("bitrate")).intValue();
+ if ((bitRate <= 0) && (audioInfo.containsKey("audio.framerate.fps")) && (audioInfo.containsKey("audio.framesize.bytes")))
+ {
+ float FR = ((Float) audioInfo.get("audio.framerate.fps")).floatValue();
+ int FS = ((Integer) audioInfo.get("audio.framesize.bytes")).intValue();
+ bitRate = Math.round(FS * FR * 8);
+ }
+ int channels = -1;
+ if (currentPlaylistItem != null) channels = currentPlaylistItem.getChannels();
+ if ((channels <= 0) && (audioInfo.containsKey("audio.channels"))) channels = ((Integer) audioInfo.get("audio.channels")).intValue();
+ float sampleRate = -1.0f;
+ if (currentPlaylistItem != null) sampleRate = currentPlaylistItem.getSamplerate();
+ if ((sampleRate <= 0) && (audioInfo.containsKey("audio.samplerate.hz"))) sampleRate = ((Float) audioInfo.get("audio.samplerate.hz")).floatValue();
+ long lenghtInSecond = -1L;
+ if (currentPlaylistItem != null) lenghtInSecond = currentPlaylistItem.getLength();
+ if ((lenghtInSecond <= 0) && (audioInfo.containsKey("duration"))) lenghtInSecond = ((Long) audioInfo.get("duration")).longValue() / 1000000;
+ if ((lenghtInSecond <= 0) && (audioInfo.containsKey("audio.length.bytes")))
+ {
+ // Try to compute time length.
+ lenghtInSecond = (long) Math.round(getTimeLengthEstimation(audioInfo) / 1000);
+ if (lenghtInSecond > 0)
+ {
+ int minutes = (int) Math.floor(lenghtInSecond / 60);
+ int hours = (int) Math.floor(minutes / 60);
+ minutes = minutes - hours * 60;
+ int seconds = (int) (lenghtInSecond - minutes * 60 - hours * 3600);
+ if (seconds >= 10) titleText = "(" + minutes + ":" + seconds + ") " + titleText;
+ else titleText = "(" + minutes + ":0" + seconds + ") " + titleText;
+ }
+ }
+ bitRate = Math.round((bitRate / 1000));
+ ui.getAcSampleRateLabel().setAcText(String.valueOf(Math.round((sampleRate / 1000))));
+ if (bitRate > 999)
+ {
+ bitRate = (int) (bitRate / 100);
+ ui.getAcBitRateLabel().setAcText(bitRate + "H");
+ }
+ else
+ {
+ ui.getAcBitRateLabel().setAcText(String.valueOf(bitRate));
+ }
+ if (channels == 2)
+ {
+ ui.getAcStereoIcon().setIcon(1);
+ ui.getAcMonoIcon().setIcon(0);
+ }
+ else if (channels == 1)
+ {
+ ui.getAcStereoIcon().setIcon(0);
+ ui.getAcMonoIcon().setIcon(1);
+ }
+ showTitle(titleText);
+ ui.getAcMinuteH().setAcText("0");
+ ui.getAcMinuteL().setAcText("0");
+ ui.getAcSecondH().setAcText("0");
+ ui.getAcSecondL().setAcText("0");
+ ui.getAcPlayIcon().setIcon(0);
+ ui.getAcTimeIcon().setIcon(0);
+ }
+ catch (BasicPlayerException bpe)
+ {
+ log.info("Stream error :" + currentFileOrURL, bpe);
+ showMessage(ui.getResource("title.invalidfile"));
+ }
+ catch (MalformedURLException mue)
+ {
+ log.info("Stream error :" + currentFileOrURL, mue);
+ showMessage(ui.getResource("title.invalidfile"));
+ }
+ // Set pan/gain.
+ try
+ {
+ theSoundPlayer.setGain(((double) ui.getAcVolume().getValue() / (double) ui.getAcVolume().getMaximum()));
+ theSoundPlayer.setPan((float) ui.getAcBalance().getValue() / 10.0f);
+ }
+ catch (BasicPlayerException e)
+ {
+ log.info("Cannot set control", e);
+ }
+ playerState = PLAY;
+ log.info(titleText);
+ }
+ }
+ }
+
+ /**
+ * Process PAUSE event.
+ * @param modifiers
+ */
+ public void processPause(int modifiers)
+ {
+ if (playerState == PLAY)
+ {
+ try
+ {
+ theSoundPlayer.pause();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.error("Cannot pause", e);
+ }
+ playerState = PAUSE;
+ ui.getAcPlayIcon().setIcon(1);
+ ui.getAcTimeIcon().setIcon(1);
+ }
+ else if (playerState == PAUSE)
+ {
+ try
+ {
+ theSoundPlayer.resume();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.info("Cannot resume", e);
+ }
+ playerState = PLAY;
+ ui.getAcPlayIcon().setIcon(0);
+ ui.getAcTimeIcon().setIcon(0);
+ }
+ }
+
+ /**
+ * Process STOP event.
+ * @param modifiers
+ */
+ public void processStop(int modifiers)
+ {
+ if ((playerState == PAUSE) || (playerState == PLAY))
+ {
+ try
+ {
+ theSoundPlayer.stop();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.info("Cannot stop", e);
+ }
+ playerState = STOP;
+ secondsAmount = 0;
+ ui.getAcPosBar().setValue(0);
+ ui.getAcPlayIcon().setIcon(2);
+ ui.getAcTimeIcon().setIcon(1);
+ }
+ }
+
+ /**
+ * Process NEXT event.
+ * @param modifiers
+ */
+ public void processNext(int modifiers)
+ {
+ // Try to get next song from the playlist
+ playlist.nextCursor();
+ playlistUI.nextCursor();
+ PlaylistItem pli = playlist.getCursor();
+ setCurrentSong(pli);
+ }
+
+ /**
+ * Process PREVIOUS event.
+ * @param modifiers
+ */
+ public void processPrevious(int modifiers)
+ {
+ // Try to get previous song from the playlist
+ playlist.previousCursor();
+ playlistUI.nextCursor();
+ PlaylistItem pli = playlist.getCursor();
+ setCurrentSong(pli);
+ }
+
+ /**
+ * Process STATEUPDATED event.
+ * @param event
+ */
+ public void processStateUpdated(BasicPlayerEvent event)
+ {
+ log.debug("Player:" + event + " (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ /*-- End Of Media reached --*/
+ int state = event.getCode();
+ Object obj = event.getDescription();
+ if (state == BasicPlayerEvent.EOM)
+ {
+ if ((playerState == PAUSE) || (playerState == PLAY))
+ {
+ playlist.nextCursor();
+ playlistUI.nextCursor();
+ PlaylistItem pli = playlist.getCursor();
+ setCurrentSong(pli);
+ }
+ }
+ else if (state == BasicPlayerEvent.PLAYING)
+ {
+ lastScrollTime = System.currentTimeMillis();
+ posValueJump = false;
+ if (audioInfo.containsKey("basicplayer.sourcedataline"))
+ {
+ if (ui.getAcAnalyzer() != null)
+ {
+ ui.getAcAnalyzer().setupDSP((SourceDataLine) audioInfo.get("basicplayer.sourcedataline"));
+ ui.getAcAnalyzer().startDSP((SourceDataLine) audioInfo.get("basicplayer.sourcedataline"));
+ }
+ }
+ }
+ else if (state == BasicPlayerEvent.SEEKING)
+ {
+ posValueJump = true;
+ }
+ else if (state == BasicPlayerEvent.SEEKED)
+ {
+ try
+ {
+ theSoundPlayer.setGain(((double) ui.getAcVolume().getValue() / (double) ui.getAcVolume().getMaximum()));
+ theSoundPlayer.setPan((float) ui.getAcBalance().getValue() / 10.0f);
+ }
+ catch (BasicPlayerException e)
+ {
+ log.debug(e);
+ }
+ }
+ else if (state == BasicPlayerEvent.OPENING)
+ {
+ if ((obj instanceof URL) || (obj instanceof InputStream))
+ {
+ showTitle(ui.getResource("title.buffering"));
+ }
+ }
+ else if (state == BasicPlayerEvent.STOPPED)
+ {
+ if (ui.getAcAnalyzer() != null)
+ {
+ ui.getAcAnalyzer().stopDSP();
+ ui.getAcAnalyzer().repaint();
+ }
+ }
+ }
+
+ /**
+ * Process PROGRESS event.
+ * @param bytesread
+ * @param microseconds
+ * @param pcmdata
+ * @param properties
+ */
+ public void processProgress(int bytesread, long microseconds, byte[] pcmdata, Map properties)
+ {
+ //log.debug("Player: Progress (EDT="+SwingUtilities.isEventDispatchThread()+")");
+ int byteslength = -1;
+ long total = -1;
+ // Try to get time from playlist item.
+ if (currentPlaylistItem != null) total = currentPlaylistItem.getLength();
+ // If it fails then try again with JavaSound SPI.
+ if (total <= 0) total = (long) Math.round(getTimeLengthEstimation(audioInfo) / 1000);
+ // If it fails again then it might be stream => Total = -1
+ if (total <= 0) total = -1;
+ if (audioInfo.containsKey("basicplayer.sourcedataline"))
+ {
+ // Spectrum/time analyzer
+ if (ui.getAcAnalyzer() != null) ui.getAcAnalyzer().writeDSP(pcmdata);
+ }
+ if (audioInfo.containsKey("audio.length.bytes"))
+ {
+ byteslength = ((Integer) audioInfo.get("audio.length.bytes")).intValue();
+ }
+ float progress = -1.0f;
+ if ((bytesread > 0) && ((byteslength > 0))) progress = bytesread * 1.0f / byteslength * 1.0f;
+ if (audioInfo.containsKey("audio.type"))
+ {
+ String audioformat = (String) audioInfo.get("audio.type");
+ if (audioformat.equalsIgnoreCase("mp3"))
+ {
+ //if (properties.containsKey("mp3.position.microseconds")) secondsAmount = (long) Math.round(((Long) properties.get("mp3.position.microseconds")).longValue()/1000000);
+ // Shoutcast stream title.
+ if (properties.containsKey("mp3.shoutcast.metadata.StreamTitle"))
+ {
+ String shoutTitle = ((String) properties.get("mp3.shoutcast.metadata.StreamTitle")).trim();
+ if (shoutTitle.length() > 0)
+ {
+ if (currentPlaylistItem != null)
+ {
+ String sTitle = " (" + currentPlaylistItem.getFormattedDisplayName() + ")";
+ if (!currentPlaylistItem.getFormattedName().equals(shoutTitle + sTitle))
+ {
+ currentPlaylistItem.setFormattedDisplayName(shoutTitle + sTitle);
+ showTitle((shoutTitle + sTitle).toUpperCase());
+ playlistUI.paintList();
+ }
+ }
+ }
+ }
+ // EqualizerUI
+ if (properties.containsKey("mp3.equalizer")) equalizerUI.setBands((float[]) properties.get("mp3.equalizer"));
+ if (total > 0) secondsAmount = (long) (total * progress);
+ else secondsAmount = -1;
+ }
+ else if (audioformat.equalsIgnoreCase("wave"))
+ {
+ secondsAmount = (long) (total * progress);
+ }
+ else
+ {
+ secondsAmount = (long) Math.round(microseconds / 1000000);
+ equalizerUI.setBands(null);
+ }
+ }
+ else
+ {
+ secondsAmount = (long) Math.round(microseconds / 1000000);
+ equalizerUI.setBands(null);
+ }
+ if (secondsAmount < 0) secondsAmount = (long) Math.round(microseconds / 1000000);
+ /*-- Display elapsed time --*/
+ int secondD = 0, second = 0, minuteD = 0, minute = 0;
+ int seconds = (int) secondsAmount;
+ int minutes = (int) Math.floor(seconds / 60);
+ int hours = (int) Math.floor(minutes / 60);
+ minutes = minutes - hours * 60;
+ seconds = seconds - minutes * 60 - hours * 3600;
+ if (seconds < 10)
+ {
+ secondD = 0;
+ second = seconds;
+ }
+ else
+ {
+ secondD = ((int) seconds / 10);
+ second = ((int) (seconds - (((int) seconds / 10)) * 10));
+ }
+ if (minutes < 10)
+ {
+ minuteD = 0;
+ minute = minutes;
+ }
+ else
+ {
+ minuteD = ((int) minutes / 10);
+ minute = ((int) (minutes - (((int) minutes / 10)) * 10));
+ }
+ ui.getAcMinuteH().setAcText(String.valueOf(minuteD));
+ ui.getAcMinuteL().setAcText(String.valueOf(minute));
+ ui.getAcSecondH().setAcText(String.valueOf(secondD));
+ ui.getAcSecondL().setAcText(String.valueOf(second));
+ // Update PosBar location.
+ if (total != 0)
+ {
+ if (posValueJump == false)
+ {
+ int posValue = ((int) Math.round(secondsAmount * Skin.POSBARMAX / total));
+ ui.getAcPosBar().setValue(posValue);
+ }
+ }
+ else ui.getAcPosBar().setValue(0);
+ long ctime = System.currentTimeMillis();
+ long lctime = lastScrollTime;
+ // Scroll title ?
+ if ((titleScrollLabel != null) && (titleScrollLabel.length > 0))
+ {
+ if (ctime - lctime > SCROLL_PERIOD)
+ {
+ lastScrollTime = ctime;
+ if (scrollRight == true)
+ {
+ scrollIndex++;
+ if (scrollIndex >= titleScrollLabel.length)
+ {
+ scrollIndex--;
+ scrollRight = false;
+ }
+ }
+ else
+ {
+ scrollIndex--;
+ if (scrollIndex <= 0)
+ {
+ scrollRight = true;
+ }
+ }
+ // TODO : Improve
+ ui.getAcTitleLabel().setAcText(titleScrollLabel[scrollIndex]);
+ }
+ }
+ }
+
+ /**
+ * Process seek feature.
+ * @param rate
+ */
+ protected void processSeek(double rate)
+ {
+ try
+ {
+ if ((audioInfo != null) && (audioInfo.containsKey("audio.type")))
+ {
+ String type = (String) audioInfo.get("audio.type");
+ // Seek support for MP3.
+ if ((type.equalsIgnoreCase("mp3")) && (audioInfo.containsKey("audio.length.bytes")))
+ {
+ long skipBytes = (long) Math.round(((Integer) audioInfo.get("audio.length.bytes")).intValue() * rate);
+ log.debug("Seek value (MP3) : " + skipBytes);
+ theSoundPlayer.seek(skipBytes);
+ }
+ // Seek support for WAV.
+ else if ((type.equalsIgnoreCase("wave")) && (audioInfo.containsKey("audio.length.bytes")))
+ {
+ long skipBytes = (long) Math.round(((Integer) audioInfo.get("audio.length.bytes")).intValue() * rate);
+ log.debug("Seek value (WAVE) : " + skipBytes);
+ theSoundPlayer.seek(skipBytes);
+ }
+ else posValueJump = false;
+ }
+ else posValueJump = false;
+ }
+ catch (BasicPlayerException ioe)
+ {
+ log.error("Cannot skip", ioe);
+ posValueJump = false;
+ }
+ }
+
+ /**
+ * Process Drag&Drop
+ * @param data
+ */
+ public void processDnD(Object data)
+ {
+ log.debug("Player DnD");
+ // Looking for files to drop.
+ if (data instanceof List)
+ {
+ List al = (List) data;
+ if ((al != null) && (al.size() > 0))
+ {
+ ArrayList fileList = new ArrayList();
+ ArrayList folderList = new ArrayList();
+ ListIterator li = al.listIterator();
+ while (li.hasNext())
+ {
+ File f = (File) li.next();
+ if ((f.exists()) && (f.canRead()))
+ {
+ if (f.isFile()) fileList.add(f);
+ else if (f.isDirectory()) folderList.add(f);
+ }
+ }
+ playFiles(fileList);
+ // TODO : Add dir support
+ }
+ }
+ else if (data instanceof String)
+ {
+ String files = (String) data;
+ if ((files.length() > 0))
+ {
+ ArrayList fileList = new ArrayList();
+ ArrayList folderList = new ArrayList();
+ StringTokenizer st = new StringTokenizer(files, System.getProperty("line.separator"));
+ // Transfer files dropped.
+ while (st.hasMoreTokens())
+ {
+ String path = st.nextToken();
+ if (path.startsWith("file://"))
+ {
+ path = path.substring(7, path.length());
+ if (path.endsWith("\r")) path = path.substring(0, (path.length() - 1));
+ }
+ File f = new File(path);
+ if ((f.exists()) && (f.canRead()))
+ {
+ if (f.isFile()) fileList.add(f);
+ else if (f.isDirectory()) folderList.add(f);
+ }
+ }
+ playFiles(fileList);
+ // TODO : Add dir support
+ }
+ }
+ else
+ {
+ log.info("Unknown dropped objects");
+ }
+ }
+
+ /**
+ * Play files from a list.
+ * @param files
+ */
+ protected void playFiles(List files)
+ {
+ if (files.size() > 0)
+ {
+ // Clean the playlist.
+ playlist.removeAllItems();
+ // Add all dropped files to playlist.
+ ListIterator li = files.listIterator();
+ while (li.hasNext())
+ {
+ File file = (File) li.next();
+ PlaylistItem pli = null;
+ if (file != null)
+ {
+ pli = new PlaylistItem(file.getName(), file.getAbsolutePath(), -1, true);
+ if (pli != null) playlist.appendItem(pli);
+ }
+ }
+ // Start the playlist from the top.
+ playlist.nextCursor();
+ playlistUI.initPlayList();
+ setCurrentSong(playlist.getCursor());
+ }
+ }
+
+ /**
+ * Sets the current song to play and start playing if needed.
+ * @param pli
+ */
+ public void setCurrentSong(PlaylistItem pli)
+ {
+ int playerStateMem = playerState;
+ if ((playerState == PAUSE) || (playerState == PLAY))
+ {
+ try
+ {
+ theSoundPlayer.stop();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.error("Cannot stop", e);
+ }
+ playerState = STOP;
+ secondsAmount = 0;
+ // Display play/time icons.
+ ui.getAcPlayIcon().setIcon(2);
+ ui.getAcTimeIcon().setIcon(0);
+ }
+ playerState = OPEN;
+ if (pli != null)
+ {
+ // Read tag info.
+ pli.getTagInfo();
+ currentSongName = pli.getFormattedName();
+ currentFileOrURL = pli.getLocation();
+ currentIsFile = pli.isFile();
+ currentPlaylistItem = pli;
+ }
+ // Playlist ended.
+ else
+ {
+ // Try to repeat ?
+ if (config.isRepeatEnabled())
+ {
+ if (playlist != null)
+ {
+ // PlaylistItems available ?
+ if (playlist.getPlaylistSize() > 0)
+ {
+ playlist.begin();
+ PlaylistItem rpli = playlist.getCursor();
+ if (rpli != null)
+ {
+ // OK, Repeat the playlist.
+ rpli.getTagInfo();
+ currentSongName = rpli.getFormattedName();
+ currentFileOrURL = rpli.getLocation();
+ currentIsFile = rpli.isFile();
+ currentPlaylistItem = rpli;
+ }
+ }
+ // No, so display Title.
+ else
+ {
+ currentSongName = Skin.TITLETEXT;
+ currentFileOrURL = null;
+ currentIsFile = false;
+ currentPlaylistItem = null;
+ }
+ }
+ }
+ // No, so display Title.
+ else
+ {
+ currentSongName = Skin.TITLETEXT;
+ currentFileOrURL = null;
+ currentIsFile = false;
+ currentPlaylistItem = null;
+ }
+ }
+ if (currentIsFile == true)
+ {
+ ui.getAcPosBar().setEnabled(true);
+ ui.getAcPosBar().setHideThumb(false);
+ }
+ else
+ {
+ config.setLastURL(currentFileOrURL);
+ ui.getAcPosBar().setEnabled(false);
+ ui.getAcPosBar().setHideThumb(true);
+ }
+ titleText = currentSongName.toUpperCase();
+ showMessage(titleText);
+ // Start playing if needed.
+ if ((playerStateMem == PLAY) || (playerStateMem == PAUSE))
+ {
+ processPlay(MouseEvent.BUTTON1_MASK);
+ }
+ }
+
+ /**
+ * Display text in title area.
+ * @param str
+ */
+ public void showTitle(String str)
+ {
+ if (str != null)
+ {
+ currentTitle = str;
+ titleScrollLabel = null;
+ scrollIndex = 0;
+ scrollRight = true;
+ if (str.length() > TEXT_LENGTH_MAX)
+ {
+ int a = ((str.length()) - (TEXT_LENGTH_MAX)) + 1;
+ titleScrollLabel = new String[a];
+ for (int k = 0; k < a; k++)
+ {
+ String sText = str.substring(k, TEXT_LENGTH_MAX + k);
+ titleScrollLabel[k] = sText;
+ }
+ str = str.substring(0, TEXT_LENGTH_MAX);
+ }
+ ui.getAcTitleLabel().setAcText(str);
+ }
+ }
+
+ /**
+ * Shows message in title an updates bitRate,sampleRate, Mono/Stereo,time features.
+ * @param txt
+ */
+ public void showMessage(String txt)
+ {
+ showTitle(txt);
+ ui.getAcSampleRateLabel().setAcText(" ");
+ ui.getAcBitRateLabel().setAcText(" ");
+ ui.getAcStereoIcon().setIcon(0);
+ ui.getAcMonoIcon().setIcon(0);
+ ui.getAcMinuteH().setAcText("0");
+ ui.getAcMinuteL().setAcText("0");
+ ui.getAcSecondH().setAcText("0");
+ ui.getAcSecondL().setAcText("0");
+ }
+
+ /**
+ * Toggle playlistUI.
+ */
+ protected void togglePlaylist()
+ {
+ if (ui.getAcPlaylist().isSelected())
+ {
+ miPlaylist.setState(true);
+ config.setPlaylistEnabled(true);
+ loader.togglePlaylist(true);
+ }
+ else
+ {
+ miPlaylist.setState(false);
+ config.setPlaylistEnabled(false);
+ loader.togglePlaylist(false);
+ }
+ }
+
+ /**
+ * Toggle equalizerUI.
+ */
+ protected void toggleEqualizer()
+ {
+ if (ui.getAcEqualizer().isSelected())
+ {
+ miEqualizer.setState(true);
+ config.setEqualizerEnabled(true);
+ loader.toggleEqualizer(true);
+ }
+ else
+ {
+ miEqualizer.setState(false);
+ config.setEqualizerEnabled(false);
+ loader.toggleEqualizer(false);
+ }
+ }
+
+ /**
+ * Returns a File from a filename.
+ * @param file
+ * @return
+ */
+ protected File openFile(String file)
+ {
+ return new File(file);
+ }
+
+ /**
+ * Free resources and close the player.
+ */
+ protected void closePlayer()
+ {
+ if ((playerState == PAUSE) || (playerState == PLAY))
+ {
+ try
+ {
+ if (theSoundPlayer != null)
+ {
+ theSoundPlayer.stop();
+ }
+ }
+ catch (BasicPlayerException e)
+ {
+ log.error("Cannot stop", e);
+ }
+ }
+ if (theSoundPlayer != null)
+ {
+ config.setAudioDevice(((BasicPlayer) theSoundPlayer).getMixerName());
+ }
+ if (ui.getAcAnalyzer() != null)
+ {
+ if (ui.getAcAnalyzer().getDisplayMode() == SpectrumTimeAnalyzer.DISPLAY_MODE_OFF) config.setVisualMode("off");
+ else if (ui.getAcAnalyzer().getDisplayMode() == SpectrumTimeAnalyzer.DISPLAY_MODE_SCOPE) config.setVisualMode("oscillo");
+ else config.setVisualMode("spectrum");
+ }
+ if (playlist != null)
+ {
+ playlist.save("default.m3u");
+ config.setPlaylistFilename("default.m3u");
+ }
+ loader.close();
+ }
+
+ /**
+ * Return current title in player.
+ * @return
+ */
+ public String getCurrentTitle()
+ {
+ return currentTitle;
+ }
+
+ /**
+ * Try to compute time length in milliseconds.
+ * @param properties
+ * @return
+ */
+ public long getTimeLengthEstimation(Map properties)
+ {
+ long milliseconds = -1;
+ int byteslength = -1;
+ if (properties != null)
+ {
+ if (properties.containsKey("audio.length.bytes"))
+ {
+ byteslength = ((Integer) properties.get("audio.length.bytes")).intValue();
+ }
+ if (properties.containsKey("duration"))
+ {
+ milliseconds = (int) (((Long) properties.get("duration")).longValue()) / 1000;
+ }
+ else
+ {
+ // Try to compute duration
+ int bitspersample = -1;
+ int channels = -1;
+ float samplerate = -1.0f;
+ int framesize = -1;
+ if (properties.containsKey("audio.samplesize.bits"))
+ {
+ bitspersample = ((Integer) properties.get("audio.samplesize.bits")).intValue();
+ }
+ if (properties.containsKey("audio.channels"))
+ {
+ channels = ((Integer) properties.get("audio.channels")).intValue();
+ }
+ if (properties.containsKey("audio.samplerate.hz"))
+ {
+ samplerate = ((Float) properties.get("audio.samplerate.hz")).floatValue();
+ }
+ if (properties.containsKey("audio.framesize.bytes"))
+ {
+ framesize = ((Integer) properties.get("audio.framesize.bytes")).intValue();
+ }
+ if (bitspersample > 0)
+ {
+ milliseconds = (int) (1000.0f * byteslength / (samplerate * channels * (bitspersample / 8)));
+ }
+ else
+ {
+ milliseconds = (int) (1000.0f * byteslength / (samplerate * framesize));
+ }
+ }
+ }
+ return milliseconds;
+ }
+
+ /**
+ * Simulates "Play" selection.
+ */
+ public void pressStart()
+ {
+ ui.getAcPlay().doClick();
+ }
+
+ /**
+ * Simulates "Pause" selection.
+ */
+ public void pressPause()
+ {
+ ui.getAcPause().doClick();
+ }
+
+ /**
+ * Simulates "Stop" selection.
+ */
+ public void pressStop()
+ {
+ ui.getAcStop().doClick();
+ }
+
+ /**
+ * Simulates "Next" selection.
+ */
+ public void pressNext()
+ {
+ ui.getAcNext().doClick();
+ }
+
+ /**
+ * Simulates "Previous" selection.
+ */
+ public void pressPrevious()
+ {
+ ui.getAcPrevious().doClick();
+ }
+
+ /**
+ * Simulates "Eject" selection.
+ */
+ public void pressEject()
+ {
+ ui.getAcEject().doClick();
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/StandalonePlayer.java b/java/src/javazoom/jlgui/player/amp/StandalonePlayer.java
new file mode 100644
index 0000000..c77ae5f
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/StandalonePlayer.java
@@ -0,0 +1,500 @@
+/*
+ * StandalonePlayer.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp;
+
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.List;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ImageIcon;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JWindow;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javazoom.jlgui.basicplayer.BasicPlayer;
+import javazoom.jlgui.player.amp.skin.DragAdapter;
+import javazoom.jlgui.player.amp.skin.Skin;
+import javazoom.jlgui.player.amp.util.Config;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class StandalonePlayer extends JFrame implements Loader
+{
+ private static Log log = LogFactory.getLog(StandalonePlayer.class);
+ /*-- Run parameters --*/
+ private String initConfig = "jlgui.ini";
+ private String initSong = null;
+ private String showPlaylist = null;
+ private String showEqualizer = null;
+ private String showDsp = null;
+ private String skinPath = null;
+ private String skinVersion = "1"; // 1, 2, for different Volume.bmp
+ private boolean autoRun = false;
+ /*-- Front-end --*/
+ private PlayerUI mp = null;
+ private JWindow eqWin = null;
+ private JWindow plWin = null;
+ private int eqFactor = 2;
+ private Config config = null;
+ private boolean playlistfound = false;
+
+ public StandalonePlayer()
+ {
+ super();
+ }
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args)
+ {
+ final StandalonePlayer player = new StandalonePlayer();
+ player.parseParameters(args);
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ player.loadUI();
+ player.loadJS();
+ player.loadPlaylist();
+ player.boot();
+ }
+ });
+ }
+
+ /**
+ * Initialize the player front-end.
+ * @param args
+ */
+ private void parseParameters(String[] args)
+ {
+ String currentArg = null;
+ String currentValue = null;
+ for (int i = 0; i < args.length; i++)
+ {
+ currentArg = args[i];
+ if (currentArg.startsWith("-"))
+ {
+ if (currentArg.toLowerCase().equals("-init"))
+ {
+ i++;
+ if (i >= args.length) usage("init value missing");
+ currentValue = args[i];
+ if (Config.startWithProtocol(currentValue)) initConfig = currentValue;
+ else initConfig = currentValue.replace('\\', '/').replace('/', java.io.File.separatorChar);
+ }
+ else if (currentArg.toLowerCase().equals("-song"))
+ {
+ i++;
+ if (i >= args.length) usage("song value missing");
+ currentValue = args[i];
+ if (Config.startWithProtocol(currentValue)) initSong = currentValue;
+ else initSong = currentValue.replace('\\', '/').replace('/', java.io.File.separatorChar);
+ }
+ else if (currentArg.toLowerCase().equals("-start"))
+ {
+ autoRun = true;
+ }
+ else if (currentArg.toLowerCase().equals("-showplaylist"))
+ {
+ showPlaylist = "true";
+ }
+ else if (currentArg.toLowerCase().equals("-showequalizer"))
+ {
+ showEqualizer = "true";
+ }
+ else if (currentArg.toLowerCase().equals("-disabledsp"))
+ {
+ showDsp = "false";
+ }
+ else if (currentArg.toLowerCase().equals("-skin"))
+ {
+ i++;
+ if (i >= args.length) usage("skin value missing");
+ currentValue = args[i];
+ if (Config.startWithProtocol(currentValue)) skinPath = currentValue;
+ else skinPath = currentValue.replace('\\', '/').replace('/', java.io.File.separatorChar);
+ }
+ else if (currentArg.toLowerCase().equals("-v"))
+ {
+ i++;
+ if (i >= args.length) usage("skin version value missing");
+ skinVersion = args[i];
+ }
+ else usage("Unknown parameter : " + currentArg);
+ }
+ else
+ {
+ usage("Invalid parameter :" + currentArg);
+ }
+ }
+ }
+
+ private void boot()
+ {
+ // Go to playlist begining if needed.
+ /*if ((playlist != null) && (playlistfound == true))
+ {
+ if (playlist.getPlaylistSize() > 0) mp.pressNext();
+ } */
+ // Start playing if needed.
+ if (autoRun == true)
+ {
+ mp.pressStart();
+ }
+ }
+
+ /**
+ * Instantiate low-level player.
+ */
+ public void loadJS()
+ {
+ BasicPlayer bplayer = new BasicPlayer();
+ List mixers = bplayer.getMixers();
+ if (mixers != null)
+ {
+ Iterator it = mixers.iterator();
+ String mixer = config.getAudioDevice();
+ boolean mixerFound = false;
+ if ((mixer != null) && (mixer.length() > 0))
+ {
+ // Check if mixer is valid.
+ while (it.hasNext())
+ {
+ if (((String) it.next()).equals(mixer))
+ {
+ bplayer.setMixerName(mixer);
+ mixerFound = true;
+ break;
+ }
+ }
+ }
+ if (mixerFound == false)
+ {
+ // Use first mixer available.
+ it = mixers.iterator();
+ if (it.hasNext())
+ {
+ mixer = (String) it.next();
+ bplayer.setMixerName(mixer);
+ }
+ }
+ }
+ // Register the front-end to low-level player events.
+ bplayer.addBasicPlayerListener(mp);
+ // Adds controls for front-end to low-level player.
+ mp.setController(bplayer);
+ }
+
+ /**
+ * Load playlist.
+ */
+ public void loadPlaylist()
+ {
+ if ((initSong != null) && (!initSong.equals(""))) playlistfound = mp.loadPlaylist(initSong);
+ else playlistfound = mp.loadPlaylist(config.getPlaylistFilename());
+ }
+
+ /**
+ * Load player front-end.
+ */
+ public void loadUI()
+ {
+ try
+ {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ }
+ catch (Exception ex)
+ {
+ log.debug(ex);
+ }
+ config = Config.getInstance();
+ config.load(initConfig);
+ config.setTopParent(this);
+ if (showPlaylist != null)
+ {
+ if (showPlaylist.equalsIgnoreCase("true"))
+ {
+ config.setPlaylistEnabled(true);
+ }
+ else
+ {
+ config.setPlaylistEnabled(false);
+ }
+ }
+ if (showEqualizer != null)
+ {
+ if (showEqualizer.equalsIgnoreCase("true"))
+ {
+ config.setEqualizerEnabled(true);
+ }
+ else
+ {
+ config.setEqualizerEnabled(false);
+ }
+ }
+ if (config.isPlaylistEnabled()) eqFactor = 2;
+ else eqFactor = 1;
+ setTitle(Skin.TITLETEXT);
+ ClassLoader cl = this.getClass().getClassLoader();
+ URL iconURL = cl.getResource("javazoom/jlgui/player/amp/jlguiicon.gif");
+ if (iconURL != null)
+ {
+ ImageIcon jlguiIcon = new ImageIcon(iconURL);
+ setIconImage(jlguiIcon.getImage());
+ config.setIconParent(jlguiIcon);
+ }
+ setUndecorated(true);
+ mp = new PlayerUI();
+ if ((showDsp != null) && (showDsp.equalsIgnoreCase("false")))
+ {
+ mp.getSkin().setDspEnabled(false);
+ }
+ if (skinPath != null)
+ {
+ mp.getSkin().setPath(skinPath);
+ }
+ mp.getSkin().setSkinVersion(skinVersion);
+ mp.loadUI(this);
+ setContentPane(mp);
+ setSize(new Dimension(mp.getSkin().getMainWidth(), mp.getSkin().getMainHeight()));
+ eqWin = new JWindow(this);
+ eqWin.setContentPane(mp.getEqualizerUI());
+ eqWin.setSize(new Dimension(mp.getSkin().getMainWidth(), mp.getSkin().getMainHeight()));
+ eqWin.setVisible(false);
+ plWin = new JWindow(this);
+ plWin.setContentPane(mp.getPlaylistUI());
+ plWin.setSize(new Dimension(mp.getSkin().getMainWidth(), mp.getSkin().getMainHeight()));
+ plWin.setVisible(false);
+ // Window listener
+ addWindowListener(new WindowAdapter()
+ {
+ public void windowClosing(WindowEvent e)
+ {
+ // Closing window (Alt+F4 under Win32)
+ close();
+ }
+ });
+ // Keyboard shortcut
+ setKeyBoardShortcut();
+ // Display front-end
+ setLocation(config.getXLocation(), config.getYLocation());
+ setVisible(true);
+ if (config.isPlaylistEnabled()) plWin.setVisible(true);
+ if (config.isEqualizerEnabled()) eqWin.setVisible(true);
+ }
+
+ /**
+ * Install keyboard shortcuts.
+ */
+ public void setKeyBoardShortcut()
+ {
+ KeyStroke jKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_J, 0, false);
+ KeyStroke ctrlPKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_MASK, false);
+ KeyStroke altSKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.ALT_MASK, false);
+ KeyStroke vKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_V, 0, false);
+ String searchID = "TAGSEARCH";
+ String preferenceID = "PREFERENCES";
+ String skinbrowserID = "SKINBROWSER";
+ String stopplayerID = "STOPPLAYER";
+ Action searchAction = new AbstractAction()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (mp != null) mp.processJumpToFile(e.getModifiers());
+ }
+ };
+ Action preferencesAction = new AbstractAction()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (mp != null) mp.processPreferences(e.getModifiers());
+ }
+ };
+ Action skinbrowserAction = new AbstractAction()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (mp != null) mp.processSkinBrowser(e.getModifiers());
+ }
+ };
+ Action stopplayerAction = new AbstractAction()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (mp != null) mp.processStop(MouseEvent.BUTTON1_MASK);
+ }
+ };
+ setKeyboardAction(searchID, jKeyStroke, searchAction);
+ setKeyboardAction(preferenceID, ctrlPKeyStroke, preferencesAction);
+ setKeyboardAction(skinbrowserID, altSKeyStroke, skinbrowserAction);
+ setKeyboardAction(stopplayerID, vKeyStroke, stopplayerAction);
+ }
+
+ /**
+ * Set keyboard key shortcut for the whole player.
+ * @param id
+ * @param key
+ * @param action
+ */
+ public void setKeyboardAction(String id, KeyStroke key, Action action)
+ {
+ mp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(key, id);
+ mp.getActionMap().put(id, action);
+ mp.getPlaylistUI().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(key, id);
+ mp.getPlaylistUI().getActionMap().put(id, action);
+ mp.getEqualizerUI().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(key, id);
+ mp.getEqualizerUI().getActionMap().put(id, action);
+ }
+
+ public void loaded()
+ {
+ DragAdapter dragAdapter = new DragAdapter(this);
+ mp.getSkin().getAcTitleBar().addMouseListener(dragAdapter);
+ mp.getSkin().getAcTitleBar().addMouseMotionListener(dragAdapter);
+ }
+
+ public void close()
+ {
+ log.info("Close player");
+ config.setLocation(getLocation().x, getLocation().y);
+ config.save();
+ dispose();
+ exit(0);
+ }
+
+ /* (non-Javadoc)
+ * @see javazoom.jlgui.player.amp.skin.Loader#togglePlaylist(boolean)
+ */
+ public void togglePlaylist(boolean enabled)
+ {
+ if (plWin != null)
+ {
+ if (enabled)
+ {
+ if (config.isEqualizerEnabled())
+ {
+ eqFactor = 2;
+ eqWin.setLocation(getLocation().x, getLocation().y + mp.getSkin().getMainHeight() * eqFactor);
+ }
+ plWin.setVisible(true);
+ }
+ else
+ {
+ plWin.setVisible(false);
+ if (config.isEqualizerEnabled())
+ {
+ eqFactor = 1;
+ eqWin.setLocation(getLocation().x, getLocation().y + mp.getSkin().getMainHeight() * eqFactor);
+ }
+ }
+ }
+ }
+
+ public void toggleEqualizer(boolean enabled)
+ {
+ if (eqWin != null)
+ {
+ if (enabled)
+ {
+ if (config.isPlaylistEnabled()) eqFactor = 2;
+ else eqFactor = 1;
+ eqWin.setLocation(getLocation().x, getLocation().y + mp.getSkin().getMainHeight() * eqFactor);
+ eqWin.setVisible(true);
+ }
+ else
+ {
+ eqWin.setVisible(false);
+ }
+ }
+ }
+
+ public void minimize()
+ {
+ setState(JFrame.ICONIFIED);
+ }
+
+ public void setLocation(int x, int y)
+ {
+ super.setLocation(x, y);
+ if (plWin != null)
+ {
+ plWin.setLocation(getLocation().x, getLocation().y + getHeight());
+ }
+ if (eqWin != null)
+ {
+ eqWin.setLocation(getLocation().x, getLocation().y + eqFactor * getHeight());
+ }
+ }
+
+ public Point getLocation()
+ {
+ return super.getLocation();
+ }
+
+ /**
+ * Kills the player.
+ * @param status
+ */
+ public void exit(int status)
+ {
+ System.exit(status);
+ }
+
+ /**
+ * Displays usage.
+ * @param msg
+ */
+ protected static void usage(String msg)
+ {
+ System.out.println(Skin.TITLETEXT + " : " + msg);
+ System.out.println("");
+ System.out.println(Skin.TITLETEXT + " : Usage");
+ System.out.println(" java javazoom.jlgui.player.amp.Player [-skin skinFilename] [-song audioFilename] [-start] [-showplaylist] [-showequalizer] [-disabledsp] [-init configFilename] [-v skinversion]");
+ System.out.println("");
+ System.out.println(" skinFilename : Filename or URL to a Winamp Skin2.x");
+ System.out.println(" audioFilename : Filename or URL to initial song or playlist");
+ System.out.println(" start : Starts playing song (from the playlist)");
+ System.out.println(" showplaylist : Show playlist");
+ System.out.println(" showequalizer : Show equalizer");
+ System.out.println(" disabledsp : Disable spectrum/time visual");
+ System.out.println("");
+ System.out.println(" Advanced parameters :");
+ System.out.println(" skinversion : 1 or 2 (default 1)");
+ System.out.println(" configFilename : Filename or URL to jlGui initial configuration (playlist,skin,parameters ...)");
+ System.out.println(" Initial configuration won't be overriden by -skin and -song arguments");
+ System.out.println("");
+ System.out.println("Homepage : http://www.javazoom.net");
+ System.exit(0);
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/equalizer/ui/ControlCurve.java b/java/src/javazoom/jlgui/player/amp/equalizer/ui/ControlCurve.java
new file mode 100644
index 0000000..951d879
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/equalizer/ui/ControlCurve.java
@@ -0,0 +1,139 @@
+/*
+ * ControlCurve.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.equalizer.ui;
+
+import java.awt.Polygon;
+
+public abstract class ControlCurve
+{
+ static final int EPSILON = 36; /* square of distance for picking */
+ protected Polygon pts;
+ protected int selection = -1;
+ int maxHeight = -1;
+ int minHeight = -1;
+
+ public ControlCurve()
+ {
+ pts = new Polygon();
+ }
+
+ public int boundY(int y)
+ {
+ int ny = y;
+ if ((minHeight >= 0) && (y < minHeight))
+ {
+ ny = 0;
+ }
+ if ((maxHeight >= 0) && (y >= maxHeight))
+ {
+ ny = maxHeight - 1;
+ }
+ return ny;
+ }
+
+ public void setMaxHeight(int h)
+ {
+ maxHeight = h;
+ }
+
+ public void setMinHeight(int h)
+ {
+ minHeight = h;
+ }
+
+ /**
+ * Return index of control point near to (x,y) or -1 if nothing near.
+ * @param x
+ * @param y
+ * @return
+ */
+ public int selectPoint(int x, int y)
+ {
+ int mind = Integer.MAX_VALUE;
+ selection = -1;
+ for (int i = 0; i < pts.npoints; i++)
+ {
+ int d = sqr(pts.xpoints[i] - x) + sqr(pts.ypoints[i] - y);
+ if (d < mind && d < EPSILON)
+ {
+ mind = d;
+ selection = i;
+ }
+ }
+ return selection;
+ }
+
+ /**
+ * Square of an int.
+ * @param x
+ * @return
+ */
+ static int sqr(int x)
+ {
+ return x * x;
+ }
+
+ /**
+ * Add a control point, return index of new control point.
+ * @param x
+ * @param y
+ * @return
+ */
+ public int addPoint(int x, int y)
+ {
+ pts.addPoint(x, y);
+ return selection = pts.npoints - 1;
+ }
+
+ /**
+ * Set selected control point.
+ * @param x
+ * @param y
+ */
+ public void setPoint(int x, int y)
+ {
+ if (selection >= 0)
+ {
+ pts.xpoints[selection] = x;
+ pts.ypoints[selection] = y;
+ }
+ }
+
+ /**
+ * Remove selected control point.
+ */
+ public void removePoint()
+ {
+ if (selection >= 0)
+ {
+ pts.npoints--;
+ for (int i = selection; i < pts.npoints; i++)
+ {
+ pts.xpoints[i] = pts.xpoints[i + 1];
+ pts.ypoints[i] = pts.ypoints[i + 1];
+ }
+ }
+ }
+
+ public abstract Polygon getPolyline();
+}
diff --git a/java/src/javazoom/jlgui/player/amp/equalizer/ui/Cubic.java b/java/src/javazoom/jlgui/player/amp/equalizer/ui/Cubic.java
new file mode 100644
index 0000000..f2471e4
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/equalizer/ui/Cubic.java
@@ -0,0 +1,46 @@
+/*
+ * Cubic.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.equalizer.ui;
+
+public class Cubic
+{
+ float a, b, c, d; /* a + b*u + c*u^2 +d*u^3 */
+
+ public Cubic(float a, float b, float c, float d)
+ {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.d = d;
+ }
+
+ /**
+ * Evaluate cubic.
+ * @param u
+ * @return
+ */
+ public float eval(float u)
+ {
+ return (((d * u) + c) * u + b) * u + a;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/equalizer/ui/EqualizerUI.java b/java/src/javazoom/jlgui/player/amp/equalizer/ui/EqualizerUI.java
new file mode 100644
index 0000000..7410296
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/equalizer/ui/EqualizerUI.java
@@ -0,0 +1,441 @@
+/*
+ * EqualizerUI.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.equalizer.ui;
+
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTarget;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javazoom.jlgui.player.amp.PlayerActionEvent;
+import javazoom.jlgui.player.amp.PlayerUI;
+import javazoom.jlgui.player.amp.skin.AbsoluteLayout;
+import javazoom.jlgui.player.amp.skin.DropTargetAdapter;
+import javazoom.jlgui.player.amp.skin.ImageBorder;
+import javazoom.jlgui.player.amp.skin.Skin;
+import javazoom.jlgui.player.amp.util.Config;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class implements an equalizer UI.
+ *
+ * The equalizer consists of 32 band-pass filters.
+ * Each band of the equalizer can take on a fractional value between
+ * -1.0 and +1.0.
+ * At -1.0, the input signal is attenuated by 6dB, at +1.0 the signal is
+ * amplified by 6dB.
+ */
+public class EqualizerUI extends JPanel implements ActionListener, ChangeListener
+{
+ private static Log log = LogFactory.getLog(EqualizerUI.class);
+ private int minGain = 0;
+ private int maxGain = 100;
+ private int[] gainValue = { 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 };
+ private int[] PRESET_NORMAL = { 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 };
+ private int[] PRESET_CLASSICAL = { 50, 50, 50, 50, 50, 50, 70, 70, 70, 76 };
+ private int[] PRESET_CLUB = { 50, 50, 42, 34, 34, 34, 42, 50, 50, 50 };
+ private int[] PRESET_DANCE = { 26, 34, 46, 50, 50, 66, 70, 70, 50, 50 };
+ private int[] PRESET_FULLBASS = { 26, 26, 26, 36, 46, 62, 76, 78, 78, 78 };
+ private int[] PRESET_FULLBASSTREBLE = { 34, 34, 50, 68, 62, 46, 28, 22, 18, 18 };
+ private int[] PRESET_FULLTREBLE = { 78, 78, 78, 62, 42, 24, 8, 8, 8, 8 };
+ private int[] PRESET_LAPTOP = { 38, 22, 36, 60, 58, 46, 38, 24, 16, 14 };
+ private int[] PRESET_LIVE = { 66, 50, 40, 36, 34, 34, 40, 42, 42, 42 };
+ private int[] PRESET_PARTY = { 32, 32, 50, 50, 50, 50, 50, 50, 32, 32 };
+ private int[] PRESET_POP = { 56, 38, 32, 30, 38, 54, 56, 56, 54, 54 };
+ private int[] PRESET_REGGAE = { 48, 48, 50, 66, 48, 34, 34, 48, 48, 48 };
+ private int[] PRESET_ROCK = { 32, 38, 64, 72, 56, 40, 28, 24, 24, 24 };
+ private int[] PRESET_TECHNO = { 30, 34, 48, 66, 64, 48, 30, 24, 24, 28 };
+ private Config config = null;
+ private PlayerUI player = null;
+ private Skin ui = null;
+ private JPopupMenu mainpopup = null;
+ public static final int LINEARDIST = 1;
+ public static final int OVERDIST = 2;
+ private float[] bands = null;
+ private int[] eqgains = null;
+ private int eqdist = OVERDIST;
+
+ public EqualizerUI()
+ {
+ super();
+ setDoubleBuffered(true);
+ config = Config.getInstance();
+ eqgains = new int[10];
+ setLayout(new AbsoluteLayout());
+ int[] vals = config.getLastEqualizer();
+ if (vals != null)
+ {
+ for (int h = 0; h < vals.length; h++)
+ {
+ gainValue[h] = vals[h];
+ }
+ }
+ // DnD support disabled.
+ DropTargetAdapter dnd = new DropTargetAdapter()
+ {
+ public void processDrop(Object data)
+ {
+ return;
+ }
+ };
+ DropTarget dt = new DropTarget(this, DnDConstants.ACTION_COPY, dnd, false);
+ }
+
+ /**
+ * Return skin.
+ * @return
+ */
+ public Skin getSkin()
+ {
+ return ui;
+ }
+
+ /**
+ * Set skin.
+ * @param ui
+ */
+ public void setSkin(Skin ui)
+ {
+ this.ui = ui;
+ }
+
+ /**
+ * Set parent player.
+ * @param mp
+ */
+ public void setPlayer(PlayerUI mp)
+ {
+ player = mp;
+ }
+
+ public void loadUI()
+ {
+ log.info("Load EqualizerUI (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ removeAll();
+ // Background
+ ImageBorder border = new ImageBorder();
+ border.setImage(ui.getEqualizerImage());
+ setBorder(border);
+ // On/Off
+ add(ui.getAcEqOnOff(), ui.getAcEqOnOff().getConstraints());
+ ui.getAcEqOnOff().removeActionListener(this);
+ ui.getAcEqOnOff().addActionListener(this);
+ // Auto
+ add(ui.getAcEqAuto(), ui.getAcEqAuto().getConstraints());
+ ui.getAcEqAuto().removeActionListener(this);
+ ui.getAcEqAuto().addActionListener(this);
+ // Sliders
+ add(ui.getAcEqPresets(), ui.getAcEqPresets().getConstraints());
+ for (int i = 0; i < ui.getAcEqSliders().length; i++)
+ {
+ add(ui.getAcEqSliders()[i], ui.getAcEqSliders()[i].getConstraints());
+ ui.getAcEqSliders()[i].setValue(maxGain - gainValue[i]);
+ ui.getAcEqSliders()[i].removeChangeListener(this);
+ ui.getAcEqSliders()[i].addChangeListener(this);
+ }
+ if (ui.getSpline() != null)
+ {
+ ui.getSpline().setValues(gainValue);
+ add(ui.getSpline(), ui.getSpline().getConstraints());
+ }
+ // Popup menu on TitleBar
+ mainpopup = new JPopupMenu();
+ String[] presets = { "Normal", "Classical", "Club", "Dance", "Full Bass", "Full Bass & Treble", "Full Treble", "Laptop", "Live", "Party", "Pop", "Reggae", "Rock", "Techno" };
+ JMenuItem mi;
+ for (int p = 0; p < presets.length; p++)
+ {
+ mi = new JMenuItem(presets[p]);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ mainpopup.add(mi);
+ }
+ ui.getAcEqPresets().removeActionListener(this);
+ ui.getAcEqPresets().addActionListener(this);
+ validate();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
+ */
+ public void stateChanged(ChangeEvent e)
+ {
+ for (int i = 0; i < ui.getAcEqSliders().length; i++)
+ {
+ gainValue[i] = maxGain - ui.getAcEqSliders()[i].getValue();
+ }
+ if (ui.getSpline() != null) ui.getSpline().repaint();
+ // Apply equalizer values.
+ synchronizeEqualizer();
+ }
+
+ /**
+ * Set bands array for equalizer.
+ *
+ * @param bands
+ */
+ public void setBands(float[] bands)
+ {
+ this.bands = bands;
+ }
+
+ /**
+ * Apply equalizer function.
+ *
+ * @param gains
+ * @param min
+ * @param max
+ */
+ public void updateBands(int[] gains, int min, int max)
+ {
+ if ((gains != null) && (bands != null))
+ {
+ int j = 0;
+ float gvalj = (gains[j] * 2.0f / (max - min) * 1.0f) - 1.0f;
+ float gvalj1 = (gains[j + 1] * 2.0f / (max - min) * 1.0f) - 1.0f;
+ // Linear distribution : 10 values => 32 values.
+ if (eqdist == LINEARDIST)
+ {
+ float a = (gvalj1 - gvalj) * 1.0f;
+ float b = gvalj * 1.0f - (gvalj1 - gvalj) * j;
+ // x=s*x'
+ float s = (gains.length - 1) * 1.0f / (bands.length - 1) * 1.0f;
+ for (int i = 0; i < bands.length; i++)
+ {
+ float ind = s * i;
+ if (ind > (j + 1))
+ {
+ j++;
+ gvalj = (gains[j] * 2.0f / (max - min) * 1.0f) - 1.0f;
+ gvalj1 = (gains[j + 1] * 2.0f / (max - min) * 1.0f) - 1.0f;
+ a = (gvalj1 - gvalj) * 1.0f;
+ b = gvalj * 1.0f - (gvalj1 - gvalj) * j;
+ }
+ // a*x+b
+ bands[i] = a * i * 1.0f * s + b;
+ }
+ }
+ // Over distribution : 10 values => 10 first value of 32 values.
+ else if (eqdist == OVERDIST)
+ {
+ for (int i = 0; i < gains.length; i++)
+ {
+ bands[i] = (gains[i] * 2.0f / (max - min) * 1.0f) - 1.0f;
+ }
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ String cmd = e.getActionCommand();
+ log.debug("Action=" + cmd + " (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ // On/Off
+ if (cmd.equals(PlayerActionEvent.ACEQONOFF))
+ {
+ if (ui.getAcEqOnOff().isSelected())
+ {
+ config.setEqualizerOn(true);
+ }
+ else
+ {
+ config.setEqualizerOn(false);
+ }
+ synchronizeEqualizer();
+ }
+ // Auto
+ else if (cmd.equals(PlayerActionEvent.ACEQAUTO))
+ {
+ if (ui.getAcEqAuto().isSelected())
+ {
+ config.setEqualizerAuto(true);
+ }
+ else
+ {
+ config.setEqualizerAuto(false);
+ }
+ }
+ // Presets
+ else if (cmd.equals(PlayerActionEvent.ACEQPRESETS))
+ {
+ if (e.getModifiers() == MouseEvent.BUTTON1_MASK)
+ {
+ mainpopup.show(this, ui.getAcEqPresets().getLocation().x, ui.getAcEqPresets().getLocation().y);
+ }
+ }
+ else if (cmd.equals("Normal"))
+ {
+ updateSliders(PRESET_NORMAL);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Classical"))
+ {
+ updateSliders(PRESET_CLASSICAL);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Club"))
+ {
+ updateSliders(PRESET_CLUB);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Dance"))
+ {
+ updateSliders(PRESET_DANCE);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Full Bass"))
+ {
+ updateSliders(PRESET_FULLBASS);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Full Bass & Treble"))
+ {
+ updateSliders(PRESET_FULLBASSTREBLE);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Full Treble"))
+ {
+ updateSliders(PRESET_FULLTREBLE);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Laptop"))
+ {
+ updateSliders(PRESET_LAPTOP);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Live"))
+ {
+ updateSliders(PRESET_LIVE);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Party"))
+ {
+ updateSliders(PRESET_PARTY);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Pop"))
+ {
+ updateSliders(PRESET_POP);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Reggae"))
+ {
+ updateSliders(PRESET_REGGAE);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Rock"))
+ {
+ updateSliders(PRESET_ROCK);
+ synchronizeEqualizer();
+ }
+ else if (cmd.equals("Techno"))
+ {
+ updateSliders(PRESET_TECHNO);
+ synchronizeEqualizer();
+ }
+ }
+
+ /**
+ * Update sliders from gains array.
+ *
+ * @param gains
+ */
+ public void updateSliders(int[] gains)
+ {
+ if (gains != null)
+ {
+ for (int i = 0; i < gains.length; i++)
+ {
+ gainValue[i + 1] = gains[i];
+ ui.getAcEqSliders()[i + 1].setValue(maxGain - gainValue[i + 1]);
+ }
+ }
+ }
+
+ /**
+ * Apply equalizer values.
+ */
+ public void synchronizeEqualizer()
+ {
+ config.setLastEqualizer(gainValue);
+ if (config.isEqualizerOn())
+ {
+ for (int j = 0; j < eqgains.length; j++)
+ {
+ eqgains[j] = -gainValue[j + 1] + maxGain;
+ }
+ updateBands(eqgains, minGain, maxGain);
+ }
+ else
+ {
+ for (int j = 0; j < eqgains.length; j++)
+ {
+ eqgains[j] = (maxGain - minGain) / 2;
+ }
+ updateBands(eqgains, minGain, maxGain);
+ }
+ }
+
+ /**
+ * Return equalizer bands distribution.
+ * @return
+ */
+ public int getEqdist()
+ {
+ return eqdist;
+ }
+
+ /**
+ * Set equalizer bands distribution.
+ * @param i
+ */
+ public void setEqdist(int i)
+ {
+ eqdist = i;
+ }
+
+ /**
+ * Simulates "On/Off" selection.
+ */
+ public void pressOnOff()
+ {
+ ui.getAcEqOnOff().doClick();
+ }
+
+ /**
+ * Simulates "Auto" selection.
+ */
+ public void pressAuto()
+ {
+ ui.getAcEqAuto().doClick();
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/equalizer/ui/NaturalSpline.java b/java/src/javazoom/jlgui/player/amp/equalizer/ui/NaturalSpline.java
new file mode 100644
index 0000000..6e0ba31
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/equalizer/ui/NaturalSpline.java
@@ -0,0 +1,108 @@
+/*
+ * NaturalSpline.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.equalizer.ui;
+
+import java.awt.Polygon;
+
+public class NaturalSpline extends ControlCurve
+{
+ public final int STEPS = 12;
+
+ public NaturalSpline()
+ {
+ super();
+ }
+
+ /*
+ * calculates the natural cubic spline that interpolates y[0], y[1], ...
+ * y[n] The first segment is returned as C[0].a + C[0].b*u + C[0].c*u^2 +
+ * C[0].d*u^3 0<=u <1 the other segments are in C[1], C[2], ... C[n-1]
+ */
+ Cubic[] calcNaturalCubic(int n, int[] x)
+ {
+ float[] gamma = new float[n + 1];
+ float[] delta = new float[n + 1];
+ float[] D = new float[n + 1];
+ int i;
+ /*
+ * We solve the equation [2 1 ] [D[0]] [3(x[1] - x[0]) ] |1 4 1 | |D[1]|
+ * |3(x[2] - x[0]) | | 1 4 1 | | . | = | . | | ..... | | . | | . | | 1 4
+ * 1| | . | |3(x[n] - x[n-2])| [ 1 2] [D[n]] [3(x[n] - x[n-1])]
+ *
+ * by using row operations to convert the matrix to upper triangular and
+ * then back sustitution. The D[i] are the derivatives at the knots.
+ */
+ gamma[0] = 1.0f / 2.0f;
+ for (i = 1; i < n; i++)
+ {
+ gamma[i] = 1 / (4 - gamma[i - 1]);
+ }
+ gamma[n] = 1 / (2 - gamma[n - 1]);
+ delta[0] = 3 * (x[1] - x[0]) * gamma[0];
+ for (i = 1; i < n; i++)
+ {
+ delta[i] = (3 * (x[i + 1] - x[i - 1]) - delta[i - 1]) * gamma[i];
+ }
+ delta[n] = (3 * (x[n] - x[n - 1]) - delta[n - 1]) * gamma[n];
+ D[n] = delta[n];
+ for (i = n - 1; i >= 0; i--)
+ {
+ D[i] = delta[i] - gamma[i] * D[i + 1];
+ }
+ /* now compute the coefficients of the cubics */
+ Cubic[] C = new Cubic[n];
+ for (i = 0; i < n; i++)
+ {
+ C[i] = new Cubic((float) x[i], D[i], 3 * (x[i + 1] - x[i]) - 2 * D[i] - D[i + 1], 2 * (x[i] - x[i + 1]) + D[i] + D[i + 1]);
+ }
+ return C;
+ }
+
+ /**
+ * Return a cubic spline.
+ */
+ public Polygon getPolyline()
+ {
+ Polygon p = new Polygon();
+ if (pts.npoints >= 2)
+ {
+ Cubic[] X = calcNaturalCubic(pts.npoints - 1, pts.xpoints);
+ Cubic[] Y = calcNaturalCubic(pts.npoints - 1, pts.ypoints);
+ // very crude technique - just break each segment up into steps lines
+ int x = (int) Math.round(X[0].eval(0));
+ int y = (int) Math.round(Y[0].eval(0));
+ p.addPoint(x, boundY(y));
+ for (int i = 0; i < X.length; i++)
+ {
+ for (int j = 1; j <= STEPS; j++)
+ {
+ float u = j / (float) STEPS;
+ x = Math.round(X[i].eval(u));
+ y = Math.round(Y[i].eval(u));
+ p.addPoint(x, boundY(y));
+ }
+ }
+ }
+ return p;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/equalizer/ui/SplinePanel.java b/java/src/javazoom/jlgui/player/amp/equalizer/ui/SplinePanel.java
new file mode 100644
index 0000000..df2a091
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/equalizer/ui/SplinePanel.java
@@ -0,0 +1,133 @@
+/*
+ * SplinePanel.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.equalizer.ui;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Polygon;
+import javax.swing.JPanel;
+import javazoom.jlgui.player.amp.skin.AbsoluteConstraints;
+
+public class SplinePanel extends JPanel
+{
+ private AbsoluteConstraints constraints = null;
+ private Image backgroundImage = null;
+ private Image barImage = null;
+ private int[] values = null;
+ private Color[] gradient = null;
+
+ public SplinePanel()
+ {
+ super();
+ setDoubleBuffered(true);
+ setLayout(null);
+ }
+
+ public Color[] getGradient()
+ {
+ return gradient;
+ }
+
+ public void setGradient(Color[] gradient)
+ {
+ this.gradient = gradient;
+ }
+
+ public void setConstraints(AbsoluteConstraints cnts)
+ {
+ constraints = cnts;
+ }
+
+ public AbsoluteConstraints getConstraints()
+ {
+ return constraints;
+ }
+
+ public Image getBarImage()
+ {
+ return barImage;
+ }
+
+ public void setBarImage(Image barImage)
+ {
+ this.barImage = barImage;
+ }
+
+ public Image getBackgroundImage()
+ {
+ return backgroundImage;
+ }
+
+ public void setBackgroundImage(Image backgroundImage)
+ {
+ this.backgroundImage = backgroundImage;
+ }
+
+ public int[] getValues()
+ {
+ return values;
+ }
+
+ public void setValues(int[] values)
+ {
+ this.values = values;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
+ */
+ public void paintComponent(Graphics g)
+ {
+ if (backgroundImage != null) g.drawImage(backgroundImage, 0, 0, null);
+ if (barImage != null) g.drawImage(barImage, 0, getHeight()/2, null);
+ if ((values != null) && (values.length > 0))
+ {
+ NaturalSpline curve = new NaturalSpline();
+ float dx = 1.0f * getWidth() / (values.length - 2);
+ int h = getHeight();
+ curve.setMaxHeight(h);
+ curve.setMinHeight(0);
+ for (int i = 1; i < values.length; i++)
+ {
+ int x1 = (int) Math.round(dx * (i - 1));
+ int y1 = ((int) Math.round((h * values[i] / 100)));
+ y1 = curve.boundY(y1);
+ curve.addPoint(x1, y1);
+ }
+ Polygon spline = curve.getPolyline();
+ if (gradient != null)
+ {
+ for (int i=0;i<(spline.npoints-1);i++)
+ {
+ g.setColor(gradient[spline.ypoints[i]]);
+ g.drawLine(spline.xpoints[i], spline.ypoints[i],spline.xpoints[i+1], spline.ypoints[i+1]);
+ }
+ }
+ else
+ {
+ g.drawPolyline(spline.xpoints, spline.ypoints, spline.npoints);
+ }
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/jlguiicon.gif b/java/src/javazoom/jlgui/player/amp/jlguiicon.gif
new file mode 100644
index 0000000..d44ea31
Binary files /dev/null and b/java/src/javazoom/jlgui/player/amp/jlguiicon.gif differ
diff --git a/java/src/javazoom/jlgui/player/amp/metrix.wsz b/java/src/javazoom/jlgui/player/amp/metrix.wsz
new file mode 100644
index 0000000..58fd9ad
Binary files /dev/null and b/java/src/javazoom/jlgui/player/amp/metrix.wsz differ
diff --git a/java/src/javazoom/jlgui/player/amp/playlist/BasePlaylist.java b/java/src/javazoom/jlgui/player/amp/playlist/BasePlaylist.java
new file mode 100644
index 0000000..ee21df1
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/playlist/BasePlaylist.java
@@ -0,0 +1,586 @@
+/*
+ * BasePlaylist.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.playlist;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import javazoom.jlgui.player.amp.util.Config;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * BasePlaylist implementation.
+ * This class implements Playlist interface using a Vector.
+ * It support .m3u and .pls playlist format.
+ */
+public class BasePlaylist implements Playlist
+{
+ protected Vector _playlist = null;
+ protected int _cursorPos = -1;
+ protected boolean isModified;
+ protected String M3UHome = null;
+ protected String PLSHome = null;
+ private static Log log = LogFactory.getLog(BasePlaylist.class);
+
+ /**
+ * Constructor.
+ */
+ public BasePlaylist()
+ {
+ _playlist = new Vector();
+ }
+
+ public boolean isModified()
+ {
+ return isModified;
+ }
+
+ /**
+ * Loads playlist as M3U format.
+ */
+ public boolean load(String filename)
+ {
+ setModified(true);
+ boolean loaded = false;
+ if ((filename != null) && (filename.toLowerCase().endsWith(".m3u")))
+ {
+ loaded = loadM3U(filename);
+ }
+ else if ((filename != null) && (filename.toLowerCase().endsWith(".pls")))
+ {
+ loaded = loadPLS(filename);
+ }
+ return loaded;
+ }
+
+ /**
+ * Load playlist from M3U format.
+ *
+ * @param filename
+ * @return
+ */
+ protected boolean loadM3U(String filename)
+ {
+ Config config = Config.getInstance();
+ _playlist = new Vector();
+ boolean loaded = false;
+ BufferedReader br = null;
+ try
+ {
+ // Playlist from URL ? (http:, ftp:, file: ....)
+ if (Config.startWithProtocol(filename))
+ {
+ br = new BufferedReader(new InputStreamReader((new URL(filename)).openStream()));
+ }
+ else
+ {
+ br = new BufferedReader(new FileReader(filename));
+ }
+ String line = null;
+ String songName = null;
+ String songFile = null;
+ String songLength = null;
+ while ((line = br.readLine()) != null)
+ {
+ if (line.trim().length() == 0) continue;
+ if (line.startsWith("#"))
+ {
+ if (line.toUpperCase().startsWith("#EXTINF"))
+ {
+ int indA = line.indexOf(",", 0);
+ if (indA != -1)
+ {
+ songName = line.substring(indA + 1, line.length());
+ }
+ int indB = line.indexOf(":", 0);
+ if (indB != -1)
+ {
+ if (indB < indA) songLength = (line.substring(indB + 1, indA)).trim();
+ }
+ }
+ }
+ else
+ {
+ songFile = line;
+ if (songName == null) songName = songFile;
+ if (songLength == null) songLength = "-1";
+ PlaylistItem pli = null;
+ if (Config.startWithProtocol(songFile))
+ {
+ // URL.
+ pli = new PlaylistItem(songName, songFile, Long.parseLong(songLength), false);
+ }
+ else
+ {
+ // File.
+ File f = new File(songFile);
+ if (f.exists())
+ {
+ pli = new PlaylistItem(songName, songFile, Long.parseLong(songLength), true);
+ }
+ else
+ {
+ // Try relative path.
+ f = new File(config.getLastDir() + songFile);
+ if (f.exists())
+ {
+ pli = new PlaylistItem(songName, config.getLastDir() + songFile, Long.parseLong(songLength), true);
+ }
+ else
+ {
+ // Try optional M3U home.
+ if (M3UHome != null)
+ {
+ if (Config.startWithProtocol(M3UHome))
+ {
+ pli = new PlaylistItem(songName, M3UHome + songFile, Long.parseLong(songLength), false);
+ }
+ else
+ {
+ pli = new PlaylistItem(songName, M3UHome + songFile, Long.parseLong(songLength), true);
+ }
+ }
+ }
+ }
+ }
+ if (pli != null) this.appendItem(pli);
+ songFile = null;
+ songName = null;
+ songLength = null;
+ }
+ }
+ loaded = true;
+ }
+ catch (Exception e)
+ {
+ log.debug("Can't load .m3u playlist", e);
+ }
+ finally
+ {
+ try
+ {
+ if (br != null)
+ {
+ br.close();
+ }
+ }
+ catch (Exception ioe)
+ {
+ log.info("Can't close .m3u playlist", ioe);
+ }
+ }
+ return loaded;
+ }
+
+ /**
+ * Load playlist in PLS format.
+ *
+ * @param filename
+ * @return
+ */
+ protected boolean loadPLS(String filename)
+ {
+ Config config = Config.getInstance();
+ _playlist = new Vector();
+ boolean loaded = false;
+ BufferedReader br = null;
+ try
+ {
+ // Playlist from URL ? (http:, ftp:, file: ....)
+ if (Config.startWithProtocol(filename))
+ {
+ br = new BufferedReader(new InputStreamReader((new URL(filename)).openStream()));
+ }
+ else
+ {
+ br = new BufferedReader(new FileReader(filename));
+ }
+ String line = null;
+ String songName = null;
+ String songFile = null;
+ String songLength = null;
+ while ((line = br.readLine()) != null)
+ {
+ if (line.trim().length() == 0) continue;
+ if ((line.toLowerCase().startsWith("file")))
+ {
+ StringTokenizer st = new StringTokenizer(line, "=");
+ st.nextToken();
+ songFile = st.nextToken().trim();
+ }
+ else if ((line.toLowerCase().startsWith("title")))
+ {
+ StringTokenizer st = new StringTokenizer(line, "=");
+ st.nextToken();
+ songName = st.nextToken().trim();
+ }
+ else if ((line.toLowerCase().startsWith("length")))
+ {
+ StringTokenizer st = new StringTokenizer(line, "=");
+ st.nextToken();
+ songLength = st.nextToken().trim();
+ }
+ // New entry ?
+ if (songFile != null)
+ {
+ PlaylistItem pli = null;
+ if (songName == null) songName = songFile;
+ if (songLength == null) songLength = "-1";
+ if (Config.startWithProtocol(songFile))
+ {
+ // URL.
+ pli = new PlaylistItem(songName, songFile, Long.parseLong(songLength), false);
+ }
+ else
+ {
+ // File.
+ File f = new File(songFile);
+ if (f.exists())
+ {
+ pli = new PlaylistItem(songName, songFile, Long.parseLong(songLength), true);
+ }
+ else
+ {
+ // Try relative path.
+ f = new File(config.getLastDir() + songFile);
+ if (f.exists())
+ {
+ pli = new PlaylistItem(songName, config.getLastDir() + songFile, Long.parseLong(songLength), true);
+ }
+ else
+ {
+ // Try optional PLS home.
+ if (PLSHome != null)
+ {
+ if (Config.startWithProtocol(PLSHome))
+ {
+ pli = new PlaylistItem(songName, PLSHome + songFile, Long.parseLong(songLength), false);
+ }
+ else
+ {
+ pli = new PlaylistItem(songName, PLSHome + songFile, Long.parseLong(songLength), true);
+ }
+ }
+ }
+ }
+ }
+ if (pli != null) this.appendItem(pli);
+ songName = null;
+ songFile = null;
+ songLength = null;
+ }
+ }
+ loaded = true;
+ }
+ catch (Exception e)
+ {
+ log.debug("Can't load .pls playlist", e);
+ }
+ finally
+ {
+ try
+ {
+ if (br != null)
+ {
+ br.close();
+ }
+ }
+ catch (Exception ioe)
+ {
+ log.info("Can't close .pls playlist", ioe);
+ }
+ }
+ return loaded;
+ }
+
+ /**
+ * Saves playlist in M3U format.
+ */
+ public boolean save(String filename)
+ {
+ // Implemented by C.K
+ if (_playlist != null)
+ {
+ BufferedWriter bw = null;
+ try
+ {
+ bw = new BufferedWriter(new FileWriter(filename));
+ bw.write("#EXTM3U");
+ bw.newLine();
+ Iterator it = _playlist.iterator();
+ while (it.hasNext())
+ {
+ PlaylistItem pli = (PlaylistItem) it.next();
+ bw.write("#EXTINF:" + pli.getM3UExtInf());
+ bw.newLine();
+ bw.write(pli.getLocation());
+ bw.newLine();
+ }
+ return true;
+ }
+ catch (IOException e)
+ {
+ log.info("Can't save playlist", e);
+ }
+ finally
+ {
+ try
+ {
+ if (bw != null)
+ {
+ bw.close();
+ }
+ }
+ catch (IOException ioe)
+ {
+ log.info("Can't close playlist", ioe);
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Adds item at a given position in the playlist.
+ */
+ public void addItemAt(PlaylistItem pli, int pos)
+ {
+ _playlist.insertElementAt(pli, pos);
+ setModified(true);
+ }
+
+ /**
+ * Searchs and removes item from the playlist.
+ */
+ public void removeItem(PlaylistItem pli)
+ {
+ _playlist.remove(pli);
+ setModified(true);
+ }
+
+ /**
+ * Removes item at a given position from the playlist.
+ */
+ public void removeItemAt(int pos)
+ {
+ _playlist.removeElementAt(pos);
+ setModified(true);
+ }
+
+ /**
+ * Removes all items from the playlist.
+ */
+ public void removeAllItems()
+ {
+ _playlist.removeAllElements();
+ _cursorPos = -1;
+ setModified(true);
+ }
+
+ /**
+ * Append item at the end of the playlist.
+ */
+ public void appendItem(PlaylistItem pli)
+ {
+ _playlist.addElement(pli);
+ setModified(true);
+ }
+
+ /**
+ * Sorts items of the playlist.
+ */
+ public void sortItems(int sortmode)
+ {
+ // TODO
+ }
+
+ /**
+ * Shuffles items in the playlist randomly
+ */
+ public void shuffle()
+ {
+ int size = _playlist.size();
+ if (size < 2) { return; }
+ Vector v = _playlist;
+ _playlist = new Vector(size);
+ while ((size = v.size()) > 0)
+ {
+ _playlist.addElement(v.remove((int) (Math.random() * size)));
+ }
+ begin();
+ }
+
+ /**
+ * Moves the cursor at the top of the playlist.
+ */
+ public void begin()
+ {
+ _cursorPos = -1;
+ if (getPlaylistSize() > 0)
+ {
+ _cursorPos = 0;
+ }
+ setModified(true);
+ }
+
+ /**
+ * Returns item at a given position from the playlist.
+ */
+ public PlaylistItem getItemAt(int pos)
+ {
+ PlaylistItem pli = null;
+ pli = (PlaylistItem) _playlist.elementAt(pos);
+ return pli;
+ }
+
+ /**
+ * Returns a collection of playlist items.
+ */
+ public Collection getAllItems()
+ {
+ // TODO
+ return null;
+ }
+
+ /**
+ * Returns then number of items in the playlist.
+ */
+ public int getPlaylistSize()
+ {
+ return _playlist.size();
+ }
+
+ // Next methods will be used by the Player
+ /**
+ * Returns item matching to the cursor.
+ */
+ public PlaylistItem getCursor()
+ {
+ if ((_cursorPos < 0) || (_cursorPos >= _playlist.size())) { return null; }
+ return getItemAt(_cursorPos);
+ }
+
+ /**
+ * Computes cursor position (next).
+ */
+ public void nextCursor()
+ {
+ _cursorPos++;
+ }
+
+ /**
+ * Computes cursor position (previous).
+ */
+ public void previousCursor()
+ {
+ _cursorPos--;
+ if (_cursorPos < 0)
+ {
+ _cursorPos = 0;
+ }
+ }
+
+ public boolean setModified(boolean set)
+ {
+ isModified = set;
+ return isModified;
+ }
+
+ public void setCursor(int index)
+ {
+ _cursorPos = index;
+ }
+
+ /**
+ * Returns selected index.
+ */
+ public int getSelectedIndex()
+ {
+ return _cursorPos;
+ }
+
+ /**
+ * Returns index of playlist item.
+ */
+ public int getIndex(PlaylistItem pli)
+ {
+ int pos = -1;
+ for (int i = 0; i < _playlist.size(); i++)
+ {
+ pos = i;
+ PlaylistItem p = (PlaylistItem) _playlist.elementAt(i);
+ if (p.equals(pli)) break;
+ }
+ return pos;
+ }
+
+ /**
+ * Get M3U home for relative playlist.
+ *
+ * @return
+ */
+ public String getM3UHome()
+ {
+ return M3UHome;
+ }
+
+ /**
+ * Set optional M3U home for relative playlist.
+ *
+ * @param string
+ */
+ public void setM3UHome(String string)
+ {
+ M3UHome = string;
+ }
+
+ /**
+ * Get PLS home for relative playlist.
+ *
+ * @return
+ */
+ public String getPLSHome()
+ {
+ return PLSHome;
+ }
+
+ /**
+ * Set optional PLS home for relative playlist.
+ *
+ * @param string
+ */
+ public void setPLSHome(String string)
+ {
+ PLSHome = string;
+ }
+}
\ No newline at end of file
diff --git a/java/src/javazoom/jlgui/player/amp/playlist/Playlist.java b/java/src/javazoom/jlgui/player/amp/playlist/Playlist.java
new file mode 100644
index 0000000..ade6beb
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/playlist/Playlist.java
@@ -0,0 +1,138 @@
+/*
+ * Playlist.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.playlist;
+
+import java.util.Collection;
+
+/**
+ * Playlist.
+ * This interface defines method that a playlist should implement.
+ * A playlist provides a collection of item to play and a cursor to know
+ * which item is playing.
+ */
+public interface Playlist
+{
+ // Next methods will be called by the Playlist UI.
+ /**
+ * Loads playlist.
+ */
+ public boolean load(String filename);
+
+ /**
+ * Saves playlist.
+ */
+ public boolean save(String filename);
+
+ /**
+ * Adds item at a given position in the playlist.
+ */
+ public void addItemAt(PlaylistItem pli, int pos);
+
+ /**
+ * Searchs and removes item from the playlist.
+ */
+ public void removeItem(PlaylistItem pli);
+
+ /**
+ * Removes item at a given position from the playlist.
+ */
+ public void removeItemAt(int pos);
+
+ /**
+ * Removes all items in the playlist.
+ */
+ public void removeAllItems();
+
+ /**
+ * Append item at the end of the playlist.
+ */
+ public void appendItem(PlaylistItem pli);
+
+ /**
+ * Sorts items of the playlist.
+ */
+ public void sortItems(int sortmode);
+
+ /**
+ * Returns item at a given position from the playlist.
+ */
+ public PlaylistItem getItemAt(int pos);
+
+ /**
+ * Returns a collection of playlist items.
+ */
+ public Collection getAllItems();
+
+ /**
+ * Returns then number of items in the playlist.
+ */
+ public int getPlaylistSize();
+
+ // Next methods will be used by the Player
+ /**
+ * Randomly re-arranges the playlist.
+ */
+ public void shuffle();
+
+ /**
+ * Returns item matching to the cursor.
+ */
+ public PlaylistItem getCursor();
+
+ /**
+ * Moves the cursor at the begining of the Playlist.
+ */
+ public void begin();
+
+ /**
+ * Returns item matching to the cursor.
+ */
+ public int getSelectedIndex();
+
+ /**
+ * Returns index of playlist item.
+ */
+ public int getIndex(PlaylistItem pli);
+
+ /**
+ * Computes cursor position (next).
+ */
+ public void nextCursor();
+
+ /**
+ * Computes cursor position (previous).
+ */
+ public void previousCursor();
+
+ /**
+ * Set the modification flag for the playlist
+ */
+ boolean setModified(boolean set);
+
+ /**
+ * Checks the modification flag
+ */
+ public boolean isModified();
+
+ void setCursor(int index);
+}
diff --git a/java/src/javazoom/jlgui/player/amp/playlist/PlaylistFactory.java b/java/src/javazoom/jlgui/player/amp/playlist/PlaylistFactory.java
new file mode 100644
index 0000000..c9c38d1
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/playlist/PlaylistFactory.java
@@ -0,0 +1,107 @@
+/*
+ * PlaylistFactory.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.playlist;
+
+import java.lang.reflect.Constructor;
+import javazoom.jlgui.player.amp.util.Config;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * PlaylistFactory.
+ */
+public class PlaylistFactory
+{
+ private static PlaylistFactory _instance = null;
+ private Playlist _playlistInstance = null;
+ private Config _config = null;
+ private static Log log = LogFactory.getLog(PlaylistFactory.class);
+
+ /**
+ * Constructor.
+ */
+ private PlaylistFactory()
+ {
+ _config = Config.getInstance();
+ }
+
+ /**
+ * Returns instance of PlaylistFactory.
+ */
+ public synchronized static PlaylistFactory getInstance()
+ {
+ if (_instance == null)
+ {
+ _instance = new PlaylistFactory();
+ }
+ return _instance;
+ }
+
+ /**
+ * Returns Playlist instantied from full qualified class name.
+ */
+ public Playlist getPlaylist()
+ {
+ if (_playlistInstance == null)
+ {
+ String classname = _config.getPlaylistClassName();
+ boolean interfaceFound = false;
+ try
+ {
+ Class aClass = Class.forName(classname);
+ Class superClass = aClass;
+ // Looking for Playlist interface implementation.
+ while (superClass != null)
+ {
+ Class[] interfaces = superClass.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++)
+ {
+ if ((interfaces[i].getName()).equals("javazoom.jlgui.player.amp.playlist.Playlist"))
+ {
+ interfaceFound = true;
+ break;
+ }
+ }
+ if (interfaceFound == true) break;
+ superClass = superClass.getSuperclass();
+ }
+ if (interfaceFound == false)
+ {
+ log.error("Error : Playlist implementation not found in " + classname + " hierarchy");
+ }
+ else
+ {
+ Class[] argsClass = new Class[] {};
+ Constructor c = aClass.getConstructor(argsClass);
+ _playlistInstance = (Playlist) (c.newInstance(null));
+ log.info(classname + " loaded");
+ }
+ }
+ catch (Exception e)
+ {
+ log.error("Error : " + classname + " : " + e.getMessage());
+ }
+ }
+ return _playlistInstance;
+ }
+}
\ No newline at end of file
diff --git a/java/src/javazoom/jlgui/player/amp/playlist/PlaylistItem.java b/java/src/javazoom/jlgui/player/amp/playlist/PlaylistItem.java
new file mode 100644
index 0000000..df2440c
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/playlist/PlaylistItem.java
@@ -0,0 +1,302 @@
+/*
+ * PlaylistItem.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ *
+ */
+package javazoom.jlgui.player.amp.playlist;
+
+import javazoom.jlgui.player.amp.tag.TagInfo;
+import javazoom.jlgui.player.amp.tag.TagInfoFactory;
+import javazoom.jlgui.player.amp.util.Config;
+import javazoom.jlgui.player.amp.util.FileUtil;
+
+/**
+ * This class implements item for playlist.
+ */
+public class PlaylistItem
+{
+ protected String _name = null;
+ protected String _displayName = null;
+ protected String _location = null;
+ protected boolean _isFile = true;
+ protected long _seconds = -1;
+ protected boolean _isSelected = false; // add by JOHN YANG
+ protected TagInfo _taginfo = null;
+
+ protected PlaylistItem()
+ {
+ }
+
+ /**
+ * Contructor for playlist item.
+ *
+ * @param name Song name to be displayed
+ * @param location File or URL
+ * @param seconds Time length
+ * @param isFile true for File instance
+ */
+ public PlaylistItem(String name, String location, long seconds, boolean isFile)
+ {
+ _name = name;
+ _seconds = seconds;
+ _isFile = isFile;
+ Config config = Config.getInstance();
+ if (config.getTaginfoPolicy().equals(Config.TAGINFO_POLICY_ALL))
+ {
+ // Read tag info for any File or URL. It could take time.
+ setLocation(location, true);
+ }
+ else if (config.getTaginfoPolicy().equals(Config.TAGINFO_POLICY_FILE))
+ {
+ // Read tag info for any File only not for URL.
+ if (_isFile) setLocation(location, true);
+ else setLocation(location, false);
+ }
+ else
+ {
+ // Do not read tag info.
+ setLocation(location, false);
+ }
+ }
+
+ /**
+ * Returns item name such as (hh:mm:ss) Title - Artist if available.
+ *
+ * @return
+ */
+ public String getFormattedName()
+ {
+ if (_displayName == null)
+ {
+ if (_seconds > 0)
+ {
+ String length = getFormattedLength();
+ return "(" + length + ") " + _name;
+ }
+ else return _name;
+ }
+ // Name extracted from TagInfo or stream title.
+ else return _displayName;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public String getLocation()
+ {
+ return _location;
+ }
+
+ /**
+ * Returns true if item to play is coming for a file.
+ *
+ * @return
+ */
+ public boolean isFile()
+ {
+ return _isFile;
+ }
+
+ /**
+ * Set File flag for playslit item.
+ *
+ * @param b
+ */
+ public void setFile(boolean b)
+ {
+ _isFile = b;
+ }
+
+ /**
+ * Returns playtime in seconds. If tag info is available then its playtime will be returned.
+ *
+ * @return playtime
+ */
+ public long getLength()
+ {
+ if ((_taginfo != null) && (_taginfo.getPlayTime() > 0)) return _taginfo.getPlayTime();
+ else return _seconds;
+ }
+
+ public int getBitrate()
+ {
+ if (_taginfo != null) return _taginfo.getBitRate();
+ else return -1;
+ }
+
+ public int getSamplerate()
+ {
+ if (_taginfo != null) return _taginfo.getSamplingRate();
+ else return -1;
+ }
+
+ public int getChannels()
+ {
+ if (_taginfo != null) return _taginfo.getChannels();
+ else return -1;
+ }
+
+ public void setSelected(boolean mode)
+ {
+ _isSelected = mode;
+ }
+
+ public boolean isSelected()
+ {
+ return _isSelected;
+ }
+
+ /**
+ * Reads file comments/tags.
+ *
+ * @param l
+ */
+ public void setLocation(String l)
+ {
+ setLocation(l, false);
+ }
+
+ /**
+ * Reads (or not) file comments/tags.
+ *
+ * @param l input location
+ * @param readInfo
+ */
+ public void setLocation(String l, boolean readInfo)
+ {
+ _location = l;
+ if (readInfo == true)
+ {
+ // Read Audio Format and read tags/comments.
+ if ((_location != null) && (!_location.equals("")))
+ {
+ TagInfoFactory factory = TagInfoFactory.getInstance();
+ _taginfo = factory.getTagInfo(l);
+ }
+ }
+ _displayName = getFormattedDisplayName();
+ }
+
+ /**
+ * Returns item lenght such as hh:mm:ss
+ *
+ * @return formatted String.
+ */
+ public String getFormattedLength()
+ {
+ long time = getLength();
+ String length = "";
+ if (time > -1)
+ {
+ int minutes = (int) Math.floor(time / 60);
+ int hours = (int) Math.floor(minutes / 60);
+ minutes = minutes - hours * 60;
+ int seconds = (int) (time - minutes * 60 - hours * 3600);
+ // Hours.
+ if (hours > 0)
+ {
+ length = length + FileUtil.rightPadString(hours + "", '0', 2) + ":";
+ }
+ length = length + FileUtil.rightPadString(minutes + "", '0', 2) + ":" + FileUtil.rightPadString(seconds + "", '0', 2);
+ }
+ else length = "" + time;
+ return length;
+ }
+
+ /**
+ * Returns item name such as (hh:mm:ss) Title - Artist
+ *
+ * @return formatted String.
+ */
+ public String getFormattedDisplayName()
+ {
+ if (_taginfo == null) return null;
+ else
+ {
+ String length = getFormattedLength();
+ if ((_taginfo.getTitle() != null) && (!_taginfo.getTitle().equals("")) && (_taginfo.getArtist() != null) && (!_taginfo.getArtist().equals("")))
+ {
+ if (getLength() > 0) return ("(" + length + ") " + _taginfo.getTitle() + " - " + _taginfo.getArtist());
+ else return (_taginfo.getTitle() + " - " + _taginfo.getArtist());
+ }
+ else if ((_taginfo.getTitle() != null) && (!_taginfo.getTitle().equals("")))
+ {
+ if (getLength() > 0) return ("(" + length + ") " + _taginfo.getTitle());
+ else return (_taginfo.getTitle());
+ }
+ else
+ {
+ if (getLength() > 0) return ("(" + length + ") " + _name);
+ else return (_name);
+ }
+ }
+ }
+
+ public void setFormattedDisplayName(String fname)
+ {
+ _displayName = fname;
+ }
+
+ /**
+ * Return item name such as hh:mm:ss,Title,Artist
+ *
+ * @return formatted String.
+ */
+ public String getM3UExtInf()
+ {
+ if (_taginfo == null)
+ {
+ return (_seconds + "," + _name);
+ }
+ else
+ {
+ if ((_taginfo.getTitle() != null) && (_taginfo.getArtist() != null))
+ {
+ return (getLength() + "," + _taginfo.getTitle() + " - " + _taginfo.getArtist());
+ }
+ else if (_taginfo.getTitle() != null)
+ {
+ return (getLength() + "," + _taginfo.getTitle());
+ }
+ else
+ {
+ return (_seconds + "," + _name);
+ }
+ }
+ }
+
+ /**
+ * Return TagInfo.
+ *
+ * @return
+ */
+ public TagInfo getTagInfo()
+ {
+ if (_taginfo == null)
+ {
+ // Inspect location
+ setLocation(_location, true);
+ }
+ return _taginfo;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/playlist/ui/PlaylistUI.java b/java/src/javazoom/jlgui/player/amp/playlist/ui/PlaylistUI.java
new file mode 100644
index 0000000..b7d0222
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/playlist/ui/PlaylistUI.java
@@ -0,0 +1,882 @@
+/*
+ * PlaylistUI.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.playlist.ui;
+
+import java.awt.Graphics;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTarget;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javazoom.jlgui.player.amp.PlayerActionEvent;
+import javazoom.jlgui.player.amp.PlayerUI;
+import javazoom.jlgui.player.amp.playlist.Playlist;
+import javazoom.jlgui.player.amp.playlist.PlaylistItem;
+import javazoom.jlgui.player.amp.skin.AbsoluteLayout;
+import javazoom.jlgui.player.amp.skin.ActiveJButton;
+import javazoom.jlgui.player.amp.skin.DropTargetAdapter;
+import javazoom.jlgui.player.amp.skin.Skin;
+import javazoom.jlgui.player.amp.skin.UrlDialog;
+import javazoom.jlgui.player.amp.tag.TagInfo;
+import javazoom.jlgui.player.amp.tag.TagInfoFactory;
+import javazoom.jlgui.player.amp.tag.ui.TagInfoDialog;
+import javazoom.jlgui.player.amp.util.Config;
+import javazoom.jlgui.player.amp.util.FileSelector;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class PlaylistUI extends JPanel implements ActionListener, ChangeListener
+{
+ private static Log log = LogFactory.getLog(PlaylistUI.class);
+ public static int MAXDEPTH = 4;
+ private Config config = null;
+ private Skin ui = null;
+ private Playlist playlist = null;
+ private PlayerUI player = null;
+ private int topIndex = 0;
+ private int currentSelection = -1;
+ private Vector exts = null;
+ private boolean isSearching = false;
+ private JPopupMenu fipopup = null;
+
+ public PlaylistUI()
+ {
+ super();
+ setDoubleBuffered(true);
+ setLayout(new AbsoluteLayout());
+ config = Config.getInstance();
+ addMouseListener(new MouseAdapter()
+ {
+ public void mousePressed(MouseEvent e)
+ {
+ handleMouseClick(e);
+ }
+ });
+ // DnD support.
+ DropTargetAdapter dnd = new DropTargetAdapter()
+ {
+ public void processDrop(Object data)
+ {
+ processDnD(data);
+ }
+ };
+ DropTarget dt = new DropTarget(this, DnDConstants.ACTION_COPY, dnd, true);
+ }
+
+ public void setPlayer(PlayerUI mp)
+ {
+ player = mp;
+ }
+
+ public void setSkin(Skin skin)
+ {
+ ui = skin;
+ }
+
+ public Skin getSkin()
+ {
+ return ui;
+ }
+
+ public Playlist getPlaylist()
+ {
+ return playlist;
+ }
+
+ public void setPlaylist(Playlist playlist)
+ {
+ this.playlist = playlist;
+ }
+
+ public int getTopIndex()
+ {
+ return topIndex;
+ }
+
+ public void loadUI()
+ {
+ removeAll();
+ ui.getPlaylistPanel().setParent(this);
+ add(ui.getAcPlSlider(), ui.getAcPlSlider().getConstraints());
+ ui.getAcPlSlider().setValue(100);
+ ui.getAcPlSlider().removeChangeListener(this);
+ ui.getAcPlSlider().addChangeListener(this);
+ add(ui.getAcPlUp(), ui.getAcPlUp().getConstraints());
+ ui.getAcPlUp().removeActionListener(this);
+ ui.getAcPlUp().addActionListener(this);
+ add(ui.getAcPlDown(), ui.getAcPlDown().getConstraints());
+ ui.getAcPlDown().removeActionListener(this);
+ ui.getAcPlDown().addActionListener(this);
+ // Add menu
+ add(ui.getAcPlAdd(), ui.getAcPlAdd().getConstraints());
+ ui.getAcPlAdd().removeActionListener(this);
+ ui.getAcPlAdd().addActionListener(this);
+ add(ui.getAcPlAddPopup(), ui.getAcPlAddPopup().getConstraints());
+ ui.getAcPlAddPopup().setVisible(false);
+ ActiveJButton[] items = ui.getAcPlAddPopup().getItems();
+ for (int i = 0; i < items.length; i++)
+ {
+ items[i].addActionListener(this);
+ }
+ // Remove menu
+ add(ui.getAcPlRemove(), ui.getAcPlRemove().getConstraints());
+ ui.getAcPlRemove().removeActionListener(this);
+ ui.getAcPlRemove().addActionListener(this);
+ add(ui.getAcPlRemovePopup(), ui.getAcPlRemovePopup().getConstraints());
+ ui.getAcPlRemovePopup().setVisible(false);
+ items = ui.getAcPlRemovePopup().getItems();
+ for (int i = 0; i < items.length; i++)
+ {
+ items[i].removeActionListener(this);
+ items[i].addActionListener(this);
+ }
+ // Select menu
+ add(ui.getAcPlSelect(), ui.getAcPlSelect().getConstraints());
+ ui.getAcPlSelect().removeActionListener(this);
+ ui.getAcPlSelect().addActionListener(this);
+ add(ui.getAcPlSelectPopup(), ui.getAcPlSelectPopup().getConstraints());
+ ui.getAcPlSelectPopup().setVisible(false);
+ items = ui.getAcPlSelectPopup().getItems();
+ for (int i = 0; i < items.length; i++)
+ {
+ items[i].removeActionListener(this);
+ items[i].addActionListener(this);
+ }
+ // Misc menu
+ add(ui.getAcPlMisc(), ui.getAcPlMisc().getConstraints());
+ ui.getAcPlMisc().removeActionListener(this);
+ ui.getAcPlMisc().addActionListener(this);
+ add(ui.getAcPlMiscPopup(), ui.getAcPlMiscPopup().getConstraints());
+ ui.getAcPlMiscPopup().setVisible(false);
+ items = ui.getAcPlMiscPopup().getItems();
+ for (int i = 0; i < items.length; i++)
+ {
+ items[i].removeActionListener(this);
+ items[i].addActionListener(this);
+ }
+ // List menu
+ add(ui.getAcPlList(), ui.getAcPlList().getConstraints());
+ ui.getAcPlList().removeActionListener(this);
+ ui.getAcPlList().addActionListener(this);
+ add(ui.getAcPlListPopup(), ui.getAcPlListPopup().getConstraints());
+ ui.getAcPlListPopup().setVisible(false);
+ items = ui.getAcPlListPopup().getItems();
+ for (int i = 0; i < items.length; i++)
+ {
+ items[i].removeActionListener(this);
+ items[i].addActionListener(this);
+ }
+ // Popup menu
+ fipopup = new JPopupMenu();
+ JMenuItem mi = new JMenuItem(ui.getResource("playlist.popup.info"));
+ mi.setActionCommand(PlayerActionEvent.ACPLINFO);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ fipopup.add(mi);
+ fipopup.addSeparator();
+ mi = new JMenuItem(ui.getResource("playlist.popup.play"));
+ mi.setActionCommand(PlayerActionEvent.ACPLPLAY);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ fipopup.add(mi);
+ fipopup.addSeparator();
+ mi = new JMenuItem(ui.getResource("playlist.popup.remove"));
+ mi.setActionCommand(PlayerActionEvent.ACPLREMOVE);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ fipopup.add(mi);
+ validate();
+ repaint();
+ }
+
+ /**
+ * Initialize playlist.
+ */
+ public void initPlayList()
+ {
+ topIndex = 0;
+ nextCursor();
+ }
+
+ /**
+ * Repaint the file list area and scroll it if necessary
+ */
+ public void nextCursor()
+ {
+ currentSelection = playlist.getSelectedIndex();
+ int n = playlist.getPlaylistSize();
+ int nlines = ui.getPlaylistPanel().getLines();
+ while (currentSelection - topIndex > nlines - 1)
+ topIndex += 2;
+ if (topIndex >= n) topIndex = n - 1;
+ while (currentSelection < topIndex)
+ topIndex -= 2;
+ if (topIndex < 0) topIndex = 0;
+ resetScrollBar();
+ repaint();
+ }
+
+ /**
+ * Get the item index according to the mouse y position
+ * @param y
+ * @return
+ */
+ protected int getIndex(int y)
+ {
+ int n0 = playlist.getPlaylistSize();
+ if (n0 == 0) return -1;
+ for (int n = 0; n < 100; n++)
+ {
+ if (ui.getPlaylistPanel().isIndexArea(y, n))
+ {
+ if (topIndex + n > n0 - 1) return -1;
+ return topIndex + n;
+ }
+ }
+ return -1;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
+ */
+ public void stateChanged(ChangeEvent e)
+ {
+ Object src = e.getSource();
+ //log.debug("State (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ if (src == ui.getAcPlSlider())
+ {
+ int n = playlist.getPlaylistSize();
+ float dx = (100 - ui.getAcPlSlider().getValue()) / 100.0f;
+ int index = (int) (dx * (n - 1));
+ if (index != topIndex)
+ {
+ topIndex = index;
+ paintList();
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ final ActionEvent evt = e;
+ new Thread("PlaylistUIActionEvent")
+ {
+ public void run()
+ {
+ processActionEvent(evt);
+ }
+ }.start();
+ }
+
+ /**
+ * Process action event.
+ * @param e
+ */
+ public void processActionEvent(ActionEvent e)
+ {
+ String cmd = e.getActionCommand();
+ log.debug("Action=" + cmd + " (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ int n = playlist.getPlaylistSize();
+ if (cmd.equals(PlayerActionEvent.ACPLUP))
+ {
+ topIndex--;
+ if (topIndex < 0) topIndex = 0;
+ resetScrollBar();
+ paintList();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLDOWN))
+ {
+ topIndex++;
+ if (topIndex > n - 1) topIndex = n - 1;
+ resetScrollBar();
+ paintList();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLADDPOPUP))
+ {
+ ui.getAcPlAdd().setVisible(false);
+ ui.getAcPlAddPopup().setVisible(true);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLREMOVEPOPUP))
+ {
+ ui.getAcPlRemove().setVisible(false);
+ ui.getAcPlRemovePopup().setVisible(true);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLSELPOPUP))
+ {
+ ui.getAcPlSelect().setVisible(false);
+ ui.getAcPlSelectPopup().setVisible(true);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLMISCPOPUP))
+ {
+ ui.getAcPlMisc().setVisible(false);
+ ui.getAcPlMiscPopup().setVisible(true);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLLISTPOPUP))
+ {
+ ui.getAcPlList().setVisible(false);
+ ui.getAcPlListPopup().setVisible(true);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLINFO))
+ {
+ popupFileInfo();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLPLAY))
+ {
+ int n0 = playlist.getPlaylistSize();
+ PlaylistItem pli = null;
+ for (int i = n0 - 1; i >= 0; i--)
+ {
+ pli = playlist.getItemAt(i);
+ if (pli.isSelected()) break;
+ }
+ // Play.
+ if ((pli != null) && (pli.getTagInfo() != null))
+ {
+ player.pressStop();
+ player.setCurrentSong(pli);
+ playlist.setCursor(playlist.getIndex(pli));
+ player.pressStart();
+ }
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLREMOVE))
+ {
+ delSelectedItems();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLADDFILE))
+ {
+ ui.getAcPlAddPopup().setVisible(false);
+ ui.getAcPlAdd().setVisible(true);
+ File[] file = FileSelector.selectFile(player.getLoader(), FileSelector.OPEN, true, config.getExtensions(), ui.getResource("playlist.popup.add.file"), new File(config.getLastDir()));
+ if (FileSelector.getInstance().getDirectory() != null) config.setLastDir(FileSelector.getInstance().getDirectory().getPath());
+ addFiles(file);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLADDURL))
+ {
+ ui.getAcPlAddPopup().setVisible(false);
+ ui.getAcPlAdd().setVisible(true);
+ UrlDialog UD = new UrlDialog(config.getTopParent(), ui.getResource("playlist.popup.add.url"), player.getLoader().getLocation().x, player.getLoader().getLocation().y + player.getHeight(), null);
+ UD.show();
+ if (UD.getFile() != null)
+ {
+ PlaylistItem pli = new PlaylistItem(UD.getFile(), UD.getURL(), -1, false);
+ playlist.appendItem(pli);
+ resetScrollBar();
+ repaint();
+ }
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLADDDIR))
+ {
+ ui.getAcPlAddPopup().setVisible(false);
+ ui.getAcPlAdd().setVisible(true);
+ File[] file = FileSelector.selectFile(player.getLoader(), FileSelector.DIRECTORY, false, "", ui.getResource("playlist.popup.add.dir"), new File(config.getLastDir()));
+ if (FileSelector.getInstance().getDirectory() != null) config.setLastDir(FileSelector.getInstance().getDirectory().getPath());
+ if (file == null || !file[0].isDirectory()) return;
+ // TODO - add message box for wrong filename
+ addDir(file[0]);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLREMOVEALL))
+ {
+ ui.getAcPlRemovePopup().setVisible(false);
+ ui.getAcPlRemove().setVisible(true);
+ delAllItems();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLREMOVESEL))
+ {
+ ui.getAcPlRemovePopup().setVisible(false);
+ ui.getAcPlRemove().setVisible(true);
+ delSelectedItems();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLREMOVEMISC))
+ {
+ ui.getAcPlRemovePopup().setVisible(false);
+ ui.getAcPlRemove().setVisible(true);
+ // TODO
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLREMOVECROP))
+ {
+ ui.getAcPlRemovePopup().setVisible(false);
+ ui.getAcPlRemove().setVisible(true);
+ // TODO
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLSELALL))
+ {
+ ui.getAcPlSelectPopup().setVisible(false);
+ ui.getAcPlSelect().setVisible(true);
+ selFunctions(1);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLSELINV))
+ {
+ ui.getAcPlSelectPopup().setVisible(false);
+ ui.getAcPlSelect().setVisible(true);
+ selFunctions(-1);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLSELZERO))
+ {
+ ui.getAcPlSelectPopup().setVisible(false);
+ ui.getAcPlSelect().setVisible(true);
+ selFunctions(0);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLMISCOPTS))
+ {
+ ui.getAcPlMiscPopup().setVisible(false);
+ ui.getAcPlMisc().setVisible(true);
+ // TODO
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLMISCFILE))
+ {
+ ui.getAcPlMiscPopup().setVisible(false);
+ ui.getAcPlMisc().setVisible(true);
+ popupFileInfo();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLMISCSORT))
+ {
+ ui.getAcPlMiscPopup().setVisible(false);
+ ui.getAcPlMisc().setVisible(true);
+ // TODO
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLLISTLOAD))
+ {
+ ui.getAcPlListPopup().setVisible(false);
+ ui.getAcPlList().setVisible(true);
+ File[] file = FileSelector.selectFile(player.getLoader(), FileSelector.OPEN, true, config.getExtensions(), ui.getResource("playlist.popup.list.load"), new File(config.getLastDir()));
+ if (FileSelector.getInstance().getDirectory() != null) config.setLastDir(FileSelector.getInstance().getDirectory().getPath());
+ if ((file != null) && (file[0] != null))
+ {
+ String fsFile = file[0].getName();
+ if ((fsFile.toLowerCase().endsWith(ui.getResource("playlist.extension.m3u"))) || (fsFile.toLowerCase().endsWith(ui.getResource("playlist.extension.pls"))))
+ {
+ if (player.loadPlaylist(config.getLastDir() + fsFile))
+ {
+ config.setPlaylistFilename(config.getLastDir() + fsFile);
+ playlist.begin();
+ playlist.setCursor(-1);
+ // TODO
+ topIndex = 0;
+ }
+ resetScrollBar();
+ repaint();
+ }
+ }
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLLISTSAVE))
+ {
+ ui.getAcPlListPopup().setVisible(false);
+ ui.getAcPlList().setVisible(true);
+ // TODO
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLLISTNEW))
+ {
+ ui.getAcPlListPopup().setVisible(false);
+ ui.getAcPlList().setVisible(true);
+ // TODO
+ }
+ }
+
+ /**
+ * Display file info.
+ */
+ public void popupFileInfo()
+ {
+ int n0 = playlist.getPlaylistSize();
+ PlaylistItem pli = null;
+ for (int i = n0 - 1; i >= 0; i--)
+ {
+ pli = playlist.getItemAt(i);
+ if (pli.isSelected()) break;
+ }
+ // Display Tag Info.
+ if (pli != null)
+ {
+ TagInfo taginfo = pli.getTagInfo();
+ TagInfoFactory factory = TagInfoFactory.getInstance();
+ TagInfoDialog dialog = factory.getTagInfoDialog(taginfo);
+ dialog.setLocation(player.getLoader().getLocation().x, player.getLoader().getLocation().y + player.getHeight());
+ dialog.show();
+ }
+ }
+
+ /**
+ * Selection operation in pledit window
+ * @param mode -1 : inverse selected items, 0 : select none, 1 : select all
+ */
+ private void selFunctions(int mode)
+ {
+ int n0 = playlist.getPlaylistSize();
+ if (n0 == 0) return;
+ for (int i = 0; i < n0; i++)
+ {
+ PlaylistItem pli = playlist.getItemAt(i);
+ if (pli == null) break;
+ if (mode == -1)
+ { // inverse selection
+ pli.setSelected(!pli.isSelected());
+ }
+ else if (mode == 0)
+ { // select none
+ pli.setSelected(false);
+ }
+ else if (mode == 1)
+ { // select all
+ pli.setSelected(true);
+ }
+ }
+ repaint();
+ }
+
+ /**
+ * Remove all items in playlist.
+ */
+ private void delAllItems()
+ {
+ int n0 = playlist.getPlaylistSize();
+ if (n0 == 0) return;
+ playlist.removeAllItems();
+ topIndex = 0;
+ ui.getAcPlSlider().setValue(100);
+ repaint();
+ }
+
+ /**
+ * Remove selected items in playlist.
+ */
+ private void delSelectedItems()
+ {
+ int n0 = playlist.getPlaylistSize();
+ boolean brepaint = false;
+ for (int i = n0 - 1; i >= 0; i--)
+ {
+ if (playlist.getItemAt(i).isSelected())
+ {
+ playlist.removeItemAt(i);
+ brepaint = true;
+ }
+ }
+ if (brepaint)
+ {
+ int n = playlist.getPlaylistSize();
+ if (topIndex >= n) topIndex = n - 1;
+ if (topIndex < 0) topIndex = 0;
+ resetScrollBar();
+ repaint();
+ }
+ }
+
+ /**
+ * Add file(s) to playlist.
+ * @param file
+ */
+ public void addFiles(File[] file)
+ {
+ if (file != null)
+ {
+ for (int i = 0; i < file.length; i++)
+ {
+ String fsFile = file[i].getName();
+ if ((!fsFile.toLowerCase().endsWith(ui.getResource("skin.extension"))) && (!fsFile.toLowerCase().endsWith(ui.getResource("playlist.extension.m3u"))) && (!fsFile.toLowerCase().endsWith(ui.getResource("playlist.extension.pls"))))
+ {
+ PlaylistItem pli = new PlaylistItem(fsFile, file[i].getAbsolutePath(), -1, true);
+ playlist.appendItem(pli);
+ resetScrollBar();
+ repaint();
+ }
+ }
+ }
+ }
+
+ /**
+ * Handle mouse clicks on playlist.
+ * @param evt
+ */
+ protected void handleMouseClick(MouseEvent evt)
+ {
+ int x = evt.getX();
+ int y = evt.getY();
+ ui.getAcPlAddPopup().setVisible(false);
+ ui.getAcPlAdd().setVisible(true);
+ ui.getAcPlRemovePopup().setVisible(false);
+ ui.getAcPlRemove().setVisible(true);
+ ui.getAcPlSelectPopup().setVisible(false);
+ ui.getAcPlSelect().setVisible(true);
+ ui.getAcPlMiscPopup().setVisible(false);
+ ui.getAcPlMisc().setVisible(true);
+ ui.getAcPlListPopup().setVisible(false);
+ ui.getAcPlList().setVisible(true);
+ // Check select action
+ if (ui.getPlaylistPanel().isInSelectArea(x, y))
+ {
+ int index = getIndex(y);
+ if (index != -1)
+ {
+ // PopUp
+ if (javax.swing.SwingUtilities.isRightMouseButton(evt))
+ {
+ if (fipopup != null) fipopup.show(this, x, y);
+ }
+ else
+ {
+ PlaylistItem pli = playlist.getItemAt(index);
+ if (pli != null)
+ {
+ pli.setSelected(!pli.isSelected());
+ if ((evt.getClickCount() == 2) && (evt.getModifiers() == MouseEvent.BUTTON1_MASK))
+ {
+ player.pressStop();
+ player.setCurrentSong(pli);
+ playlist.setCursor(index);
+ player.pressStart();
+ }
+ }
+ }
+ repaint();
+ }
+ }
+ }
+
+ /**
+ * Process Drag&Drop
+ * @param data
+ */
+ public void processDnD(Object data)
+ {
+ log.debug("Playlist DnD");
+ // Looking for files to drop.
+ if (data instanceof List)
+ {
+ List al = (List) data;
+ if ((al != null) && (al.size() > 0))
+ {
+ ArrayList fileList = new ArrayList();
+ ArrayList folderList = new ArrayList();
+ ListIterator li = al.listIterator();
+ while (li.hasNext())
+ {
+ File f = (File) li.next();
+ if ((f.exists()) && (f.canRead()))
+ {
+ if (f.isFile()) fileList.add(f);
+ else if (f.isDirectory()) folderList.add(f);
+ }
+ }
+ addFiles(fileList);
+ addDirs(folderList);
+ }
+ }
+ else if (data instanceof String)
+ {
+ String files = (String) data;
+ if ((files.length() > 0))
+ {
+ ArrayList fileList = new ArrayList();
+ ArrayList folderList = new ArrayList();
+ StringTokenizer st = new StringTokenizer(files, System.getProperty("line.separator"));
+ // Transfer files dropped.
+ while (st.hasMoreTokens())
+ {
+ String path = st.nextToken();
+ if (path.startsWith("file://"))
+ {
+ path = path.substring(7, path.length());
+ if (path.endsWith("\r")) path = path.substring(0, (path.length() - 1));
+ }
+ File f = new File(path);
+ if ((f.exists()) && (f.canRead()))
+ {
+ if (f.isFile()) fileList.add(f);
+ else if (f.isDirectory()) folderList.add(f);
+ }
+ }
+ addFiles(fileList);
+ addDirs(folderList);
+ }
+ }
+ else
+ {
+ log.info("Unknown dropped objects");
+ }
+ }
+
+ /**
+ * Add files to playlistUI.
+ * @param fileList
+ */
+ public void addFiles(List fileList)
+ {
+ if (fileList.size() > 0)
+ {
+ File[] file = (File[]) fileList.toArray(new File[fileList.size()]);
+ addFiles(file);
+ }
+ }
+
+ /**
+ * Add directories to playlistUI.
+ * @param folderList
+ */
+ public void addDirs(List folderList)
+ {
+ if (folderList.size() > 0)
+ {
+ ListIterator it = folderList.listIterator();
+ while (it.hasNext())
+ {
+ addDir((File) it.next());
+ }
+ }
+ }
+
+ /**
+ * Compute slider value.
+ */
+ private void resetScrollBar()
+ {
+ int n = playlist.getPlaylistSize();
+ float dx = (n < 1) ? 0 : ((float) topIndex / (n - 1)) * (100);
+ ui.getAcPlSlider().setValue(100 - (int) dx);
+ }
+
+ public void paintList()
+ {
+ if (!isVisible()) return;
+ else repaint();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
+ */
+ public void paintComponent(Graphics g)
+ {
+ ui.getPlaylistPanel().paintBackground(g);
+ ui.getPlaylistPanel().paintList(g);
+ }
+
+ /**
+ * Add all files under this directory to play list.
+ * @param fsFile
+ */
+ private void addDir(File fsFile)
+ {
+ // Put all music file extension in a Vector
+ String ext = config.getExtensions();
+ StringTokenizer st = new StringTokenizer(ext, ", ");
+ if (exts == null)
+ {
+ exts = new Vector();
+ while (st.hasMoreTokens())
+ {
+ exts.add("." + st.nextElement());
+ }
+ }
+ // recursive
+ Thread addThread = new AddThread(fsFile);
+ addThread.start();
+ // Refresh thread
+ Thread refresh = new Thread("Refresh")
+ {
+ public void run()
+ {
+ while (isSearching)
+ {
+ resetScrollBar();
+ repaint();
+ try
+ {
+ Thread.sleep(4000);
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+ }
+ };
+ refresh.start();
+ }
+ class AddThread extends Thread
+ {
+ private File fsFile;
+
+ public AddThread(File fsFile)
+ {
+ super("Add");
+ this.fsFile = fsFile;
+ }
+
+ public void run()
+ {
+ isSearching = true;
+ addMusicRecursive(fsFile, 0);
+ isSearching = false;
+ resetScrollBar();
+ repaint();
+ }
+ }
+
+ private void addMusicRecursive(File rootDir, int depth)
+ {
+ // We do not want waste time
+ if (rootDir == null || depth > MAXDEPTH) return;
+ String[] list = rootDir.list();
+ if (list == null) return;
+ for (int i = 0; i < list.length; i++)
+ {
+ File ff = new File(rootDir, list[i]);
+ if (ff.isDirectory()) addMusicRecursive(ff, depth + 1);
+ else
+ {
+ if (isMusicFile(list[i]))
+ {
+ PlaylistItem pli = new PlaylistItem(list[i], rootDir + File.separator + list[i], -1, true);
+ playlist.appendItem(pli);
+ }
+ }
+ }
+ }
+
+ private boolean isMusicFile(String ff)
+ {
+ int sz = exts.size();
+ for (int i = 0; i < sz; i++)
+ {
+ String ext = exts.elementAt(i).toString().toLowerCase();
+ // TODO : Improve
+ if (ext.equalsIgnoreCase(".wsz") || ext.equalsIgnoreCase(".m3u") || ext.equalsIgnoreCase(".pls")) continue;
+ if (ff.toLowerCase().endsWith(exts.elementAt(i).toString().toLowerCase())) return true;
+ }
+ return false;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/AbsoluteConstraints.java b/java/src/javazoom/jlgui/player/amp/skin/AbsoluteConstraints.java
new file mode 100644
index 0000000..d0961ed
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/AbsoluteConstraints.java
@@ -0,0 +1,151 @@
+/*
+ * AbsoluteConstraints.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.Dimension;
+import java.awt.Point;
+
+/**
+ * An object that encapsulates position and (optionally) size for
+ * Absolute positioning of components.
+ */
+public class AbsoluteConstraints implements java.io.Serializable
+{
+ /**
+ * generated Serialized Version UID
+ */
+ static final long serialVersionUID = 5261460716622152494L;
+ /**
+ * The X position of the component
+ */
+ public int x;
+ /**
+ * The Y position of the component
+ */
+ public int y;
+ /**
+ * The width of the component or -1 if the component's preferred width should be used
+ */
+ public int width = -1;
+ /**
+ * The height of the component or -1 if the component's preferred height should be used
+ */
+ public int height = -1;
+
+ /**
+ * Creates a new AbsoluteConstraints for specified position.
+ *
+ * @param pos The position to be represented by this AbsoluteConstraints
+ */
+ public AbsoluteConstraints(Point pos)
+ {
+ this(pos.x, pos.y);
+ }
+
+ /**
+ * Creates a new AbsoluteConstraints for specified position.
+ *
+ * @param x The X position to be represented by this AbsoluteConstraints
+ * @param y The Y position to be represented by this AbsoluteConstraints
+ */
+ public AbsoluteConstraints(int x, int y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Creates a new AbsoluteConstraints for specified position and size.
+ *
+ * @param pos The position to be represented by this AbsoluteConstraints
+ * @param size The size to be represented by this AbsoluteConstraints or null
+ * if the component's preferred size should be used
+ */
+ public AbsoluteConstraints(Point pos, Dimension size)
+ {
+ this.x = pos.x;
+ this.y = pos.y;
+ if (size != null)
+ {
+ this.width = size.width;
+ this.height = size.height;
+ }
+ }
+
+ /**
+ * Creates a new AbsoluteConstraints for specified position and size.
+ *
+ * @param x The X position to be represented by this AbsoluteConstraints
+ * @param y The Y position to be represented by this AbsoluteConstraints
+ * @param width The width to be represented by this AbsoluteConstraints or -1 if the
+ * component's preferred width should be used
+ * @param height The height to be represented by this AbsoluteConstraints or -1 if the
+ * component's preferred height should be used
+ */
+ public AbsoluteConstraints(int x, int y, int width, int height)
+ {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * @return The X position represented by this AbsoluteConstraints
+ */
+ public int getX()
+ {
+ return x;
+ }
+
+ /**
+ * @return The Y position represented by this AbsoluteConstraints
+ */
+ public int getY()
+ {
+ return y;
+ }
+
+ /**
+ * @return The width represented by this AbsoluteConstraints or -1 if the
+ * component's preferred width should be used
+ */
+ public int getWidth()
+ {
+ return width;
+ }
+
+ /**
+ * @return The height represented by this AbsoluteConstraints or -1 if the
+ * component's preferred height should be used
+ */
+ public int getHeight()
+ {
+ return height;
+ }
+
+ public String toString()
+ {
+ return super.toString() + " [x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + "]";
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/AbsoluteLayout.java b/java/src/javazoom/jlgui/player/amp/skin/AbsoluteLayout.java
new file mode 100644
index 0000000..4f9ead0
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/AbsoluteLayout.java
@@ -0,0 +1,196 @@
+/*
+ * AbsoluteLayout.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.LayoutManager;
+import java.awt.LayoutManager2;
+
+/**
+ * AbsoluteLayout is a LayoutManager that works as a replacement for "null" layout to
+ * allow placement of components in absolute positions.
+ */
+public class AbsoluteLayout implements LayoutManager2, java.io.Serializable
+{
+ /**
+ * generated Serialized Version UID
+ */
+ static final long serialVersionUID = -1919857869177070440L;
+
+ /**
+ * Adds the specified component with the specified name to
+ * the layout.
+ *
+ * @param name the component name
+ * @param comp the component to be added
+ */
+ public void addLayoutComponent(String name, Component comp)
+ {
+ throw new IllegalArgumentException();
+ }
+
+ /**
+ * Removes the specified component from the layout.
+ *
+ * @param comp the component to be removed
+ */
+ public void removeLayoutComponent(Component comp)
+ {
+ constraints.remove(comp);
+ }
+
+ /**
+ * Calculates the preferred dimension for the specified
+ * panel given the components in the specified parent container.
+ *
+ * @param parent the component to be laid out
+ * @see #minimumLayoutSize
+ */
+ public Dimension preferredLayoutSize(Container parent)
+ {
+ int maxWidth = 0;
+ int maxHeight = 0;
+ for (java.util.Enumeration e = constraints.keys(); e.hasMoreElements();)
+ {
+ Component comp = (Component) e.nextElement();
+ AbsoluteConstraints ac = (AbsoluteConstraints) constraints.get(comp);
+ Dimension size = comp.getPreferredSize();
+ int width = ac.getWidth();
+ if (width == -1) width = size.width;
+ int height = ac.getHeight();
+ if (height == -1) height = size.height;
+ if (ac.x + width > maxWidth) maxWidth = ac.x + width;
+ if (ac.y + height > maxHeight) maxHeight = ac.y + height;
+ }
+ return new Dimension(maxWidth, maxHeight);
+ }
+
+ /**
+ * Calculates the minimum dimension for the specified
+ * panel given the components in the specified parent container.
+ *
+ * @param parent the component to be laid out
+ * @see #preferredLayoutSize
+ */
+ public Dimension minimumLayoutSize(Container parent)
+ {
+ int maxWidth = 0;
+ int maxHeight = 0;
+ for (java.util.Enumeration e = constraints.keys(); e.hasMoreElements();)
+ {
+ Component comp = (Component) e.nextElement();
+ AbsoluteConstraints ac = (AbsoluteConstraints) constraints.get(comp);
+ Dimension size = comp.getMinimumSize();
+ int width = ac.getWidth();
+ if (width == -1) width = size.width;
+ int height = ac.getHeight();
+ if (height == -1) height = size.height;
+ if (ac.x + width > maxWidth) maxWidth = ac.x + width;
+ if (ac.y + height > maxHeight) maxHeight = ac.y + height;
+ }
+ return new Dimension(maxWidth, maxHeight);
+ }
+
+ /**
+ * Lays out the container in the specified panel.
+ *
+ * @param parent the component which needs to be laid out
+ */
+ public void layoutContainer(Container parent)
+ {
+ for (java.util.Enumeration e = constraints.keys(); e.hasMoreElements();)
+ {
+ Component comp = (Component) e.nextElement();
+ AbsoluteConstraints ac = (AbsoluteConstraints) constraints.get(comp);
+ Dimension size = comp.getPreferredSize();
+ int width = ac.getWidth();
+ if (width == -1) width = size.width;
+ int height = ac.getHeight();
+ if (height == -1) height = size.height;
+ comp.setBounds(ac.x, ac.y, width, height);
+ }
+ }
+
+ /**
+ * Adds the specified component to the layout, using the specified
+ * constraint object.
+ *
+ * @param comp the component to be added
+ * @param constr where/how the component is added to the layout.
+ */
+ public void addLayoutComponent(Component comp, Object constr)
+ {
+ if (!(constr instanceof AbsoluteConstraints)) throw new IllegalArgumentException();
+ constraints.put(comp, constr);
+ }
+
+ /**
+ * Returns the maximum size of this component.
+ *
+ * @see java.awt.Component#getMinimumSize()
+ * @see java.awt.Component#getPreferredSize()
+ * @see LayoutManager
+ */
+ public Dimension maximumLayoutSize(Container target)
+ {
+ return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Returns the alignment along the x axis. This specifies how
+ * the component would like to be aligned relative to other
+ * components. The value should be a number between 0 and 1
+ * where 0 represents alignment along the origin, 1 is aligned
+ * the furthest away from the origin, 0.5 is centered, etc.
+ */
+ public float getLayoutAlignmentX(Container target)
+ {
+ return 0;
+ }
+
+ /**
+ * Returns the alignment along the y axis. This specifies how
+ * the component would like to be aligned relative to other
+ * components. The value should be a number between 0 and 1
+ * where 0 represents alignment along the origin, 1 is aligned
+ * the furthest away from the origin, 0.5 is centered, etc.
+ */
+ public float getLayoutAlignmentY(Container target)
+ {
+ return 0;
+ }
+
+ /**
+ * Invalidates the layout, indicating that if the layout manager
+ * has cached information it should be discarded.
+ */
+ public void invalidateLayout(Container target)
+ {
+ }
+ /**
+ * A mapping
+ */
+ protected java.util.Hashtable constraints = new java.util.Hashtable();
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/ActiveFont.java b/java/src/javazoom/jlgui/player/amp/skin/ActiveFont.java
new file mode 100644
index 0000000..a0eba43
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/ActiveFont.java
@@ -0,0 +1,88 @@
+/*
+ * ActiveFont.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.Image;
+
+public class ActiveFont
+{
+ private Image image = null;
+ private String index = null;
+ private int width = -1;
+ private int height = -1;
+
+ public ActiveFont()
+ {
+ super();
+ }
+
+ public ActiveFont(Image image, String index, int width, int height)
+ {
+ super();
+ this.image=image;
+ this.index=index;
+ this.width=width;
+ this.height=height;
+ }
+
+ public int getHeight()
+ {
+ return height;
+ }
+
+ public void setHeight(int height)
+ {
+ this.height = height;
+ }
+
+ public Image getImage()
+ {
+ return image;
+ }
+
+ public void setImage(Image image)
+ {
+ this.image = image;
+ }
+
+ public String getIndex()
+ {
+ return index;
+ }
+
+ public void setIndex(String index)
+ {
+ this.index = index;
+ }
+
+ public int getWidth()
+ {
+ return width;
+ }
+
+ public void setWidth(int width)
+ {
+ this.width = width;
+ }
+
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/ActiveJBar.java b/java/src/javazoom/jlgui/player/amp/skin/ActiveJBar.java
new file mode 100644
index 0000000..d45c40d
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/ActiveJBar.java
@@ -0,0 +1,45 @@
+/*
+ * ActiveJBar.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import javax.swing.JPanel;
+
+public class ActiveJBar extends JPanel
+{
+ private AbsoluteConstraints constraints = null;
+
+ public ActiveJBar()
+ {
+ super();
+ }
+
+ public void setConstraints(AbsoluteConstraints cnts)
+ {
+ constraints = cnts;
+ }
+
+ public AbsoluteConstraints getConstraints()
+ {
+ return constraints;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/ActiveJButton.java b/java/src/javazoom/jlgui/player/amp/skin/ActiveJButton.java
new file mode 100644
index 0000000..f6cde82
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/ActiveJButton.java
@@ -0,0 +1,48 @@
+/*
+ * ActiveJButton.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import javax.swing.JButton;
+
+public class ActiveJButton extends JButton
+{
+ private AbsoluteConstraints constraints = null;
+
+ public ActiveJButton()
+ {
+ super();
+ setBorder(null);
+ setDoubleBuffered(true);
+ setFocusPainted(false);
+ }
+
+ public void setConstraints(AbsoluteConstraints cnts)
+ {
+ constraints = cnts;
+ }
+
+ public AbsoluteConstraints getConstraints()
+ {
+ return constraints;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/ActiveJIcon.java b/java/src/javazoom/jlgui/player/amp/skin/ActiveJIcon.java
new file mode 100644
index 0000000..c6d4bc1
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/ActiveJIcon.java
@@ -0,0 +1,62 @@
+/*
+ * ActiveJIcon.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+
+public class ActiveJIcon extends JLabel
+{
+ private AbsoluteConstraints constraints = null;
+ private ImageIcon[] icons = null;
+
+ public ActiveJIcon()
+ {
+ super();
+ this.setBorder(null);
+ this.setDoubleBuffered(true);
+ }
+
+ public void setIcons(ImageIcon[] icons)
+ {
+ this.icons = icons;
+ }
+
+ public void setIcon(int id)
+ {
+ if ((id >= 0) && (id < icons.length))
+ {
+ setIcon(icons[id]);
+ }
+ }
+
+ public void setConstraints(AbsoluteConstraints cnts)
+ {
+ constraints = cnts;
+ }
+
+ public AbsoluteConstraints getConstraints()
+ {
+ return constraints;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/ActiveJLabel.java b/java/src/javazoom/jlgui/player/amp/skin/ActiveJLabel.java
new file mode 100644
index 0000000..6e1aa71
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/ActiveJLabel.java
@@ -0,0 +1,104 @@
+/*
+ * ActiveJLabel.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.Rectangle;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+
+public class ActiveJLabel extends JLabel
+{
+ private AbsoluteConstraints constraints = null;
+ private ActiveFont acFont = null;
+ private Rectangle cropRectangle = null;
+ private String acText = null;
+
+ public ActiveJLabel()
+ {
+ super();
+ setBorder(null);
+ setDoubleBuffered(true);
+ }
+
+ public void setConstraints(AbsoluteConstraints cnts)
+ {
+ constraints = cnts;
+ }
+
+ public AbsoluteConstraints getConstraints()
+ {
+ return constraints;
+ }
+
+ public ActiveFont getAcFont()
+ {
+ return acFont;
+ }
+
+ public void setAcFont(ActiveFont acFont)
+ {
+ this.acFont = acFont;
+ }
+
+ public Rectangle getCropRectangle()
+ {
+ return cropRectangle;
+ }
+
+ public void setCropRectangle(Rectangle cropRectangle)
+ {
+ this.cropRectangle = cropRectangle;
+ }
+
+ public String getAcText()
+ {
+ return acText;
+ }
+
+ public void setAcText(String txt)
+ {
+ acText = txt;
+
+ acText = acText.replace('È','E');
+ acText = acText.replace('É','E');
+ acText = acText.replace('Ê','E');
+ acText = acText.replace('À','A');
+ acText = acText.replace('Ä','A');
+ acText = acText.replace('Ç','C');
+ acText = acText.replace('Ù','U');
+ acText = acText.replace('Ü','U');
+ acText = acText.replace('Ï','I');
+ if (acFont != null)
+ {
+ Taftb parser = new Taftb(acFont.getIndex(), acFont.getImage(), acFont.getWidth(), acFont.getHeight(), 0, acText);
+ if (cropRectangle != null)
+ {
+ setIcon(new ImageIcon(parser.getBanner(cropRectangle.x, cropRectangle.y, cropRectangle.width, cropRectangle.height)));
+ }
+ else
+ {
+ setIcon(new ImageIcon(parser.getBanner()));
+ }
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/ActiveJNumberLabel.java b/java/src/javazoom/jlgui/player/amp/skin/ActiveJNumberLabel.java
new file mode 100644
index 0000000..0505543
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/ActiveJNumberLabel.java
@@ -0,0 +1,61 @@
+/*
+ * ActiveJNumberLabel.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import javax.swing.ImageIcon;
+
+public class ActiveJNumberLabel extends ActiveJLabel
+{
+ private ImageIcon[] numbers = null;
+
+ public ActiveJNumberLabel()
+ {
+ super();
+ }
+
+ public ImageIcon[] getNumbers()
+ {
+ return numbers;
+ }
+
+ public void setNumbers(ImageIcon[] numbers)
+ {
+ this.numbers = numbers;
+ }
+
+ public void setAcText(String numberStr)
+ {
+ int number = 10;
+ try
+ {
+ number = Integer.parseInt(numberStr);
+ }
+ catch (NumberFormatException e)
+ {
+ }
+ if ((number >= 0) && (number < numbers.length))
+ {
+ setIcon(numbers[number]);
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/ActiveJPopup.java b/java/src/javazoom/jlgui/player/amp/skin/ActiveJPopup.java
new file mode 100644
index 0000000..191aa84
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/ActiveJPopup.java
@@ -0,0 +1,70 @@
+/*
+ * ActiveJPopup.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.GridLayout;
+import javax.swing.JPanel;
+
+public class ActiveJPopup extends JPanel
+{
+ private AbsoluteConstraints constraints = null;
+ private ActiveJButton[] items = null;
+
+ public ActiveJPopup()
+ {
+ super();
+ setBorder(null);
+ setDoubleBuffered(true);
+ }
+
+ public void setConstraints(AbsoluteConstraints cnts)
+ {
+ constraints = cnts;
+ }
+
+ public AbsoluteConstraints getConstraints()
+ {
+ return constraints;
+ }
+
+ public ActiveJButton[] getItems()
+ {
+ return items;
+ }
+
+ public void setItems(ActiveJButton[] items)
+ {
+ this.items = items;
+ if (items != null)
+ {
+ setLayout(new GridLayout(items.length, 1, 0, 0));
+ for (int i=0;i= 0)
+ {
+ if (parentSlider.getOrientation() == JSlider.HORIZONTAL)
+ {
+ g.drawImage(img, thumbRect.x + thumbXOffset, thumbYOffset, img.getWidth(null), newThumbHeight, null);
+ }
+ else
+ {
+ g.drawImage(img, thumbXOffset, thumbRect.y + thumbYOffset, img.getWidth(null), newThumbHeight, null);
+ }
+ }
+ else
+ {
+ if (parentSlider.getOrientation() == JSlider.HORIZONTAL)
+ {
+ g.drawImage(img, thumbRect.x + thumbXOffset, thumbYOffset, img.getWidth(null), img.getHeight(null), null);
+ }
+ else
+ {
+ g.drawImage(img, thumbXOffset, thumbRect.y + thumbYOffset, img.getWidth(null), img.getHeight(null), null);
+ }
+ }
+ }
+ }
+
+ public void paintTrack(Graphics g)
+ {
+ if (backgroundImages != null)
+ {
+ int id = (int) Math.round(((double) Math.abs(parentSlider.getValue()) / (double) parentSlider.getMaximum()) * (backgroundImages.length - 1));
+ g.drawImage(backgroundImages[id], 0, 0, backgroundImages[id].getWidth(null), backgroundImages[id].getHeight(null), null);
+ }
+ }
+
+ public void setThumbLocation(int x, int y)
+ {
+ super.setThumbLocation(x, y);
+ parentSlider.repaint();
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/DragAdapter.java b/java/src/javazoom/jlgui/player/amp/skin/DragAdapter.java
new file mode 100644
index 0000000..75a10bc
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/DragAdapter.java
@@ -0,0 +1,68 @@
+/*
+ * DragAdapter.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.Component;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+
+public class DragAdapter extends MouseAdapter implements MouseMotionListener
+{
+ private int mousePrevX = 0;
+ private int mousePrevY = 0;
+ private Component component = null;
+
+ public DragAdapter(Component component)
+ {
+ super();
+ this.component = component;
+ }
+
+ public void mousePressed(MouseEvent me)
+ {
+ super.mousePressed(me);
+ mousePrevX = me.getX();
+ mousePrevY = me.getY();
+ }
+
+ public void mouseDragged(MouseEvent me)
+ {
+ int mX = me.getX();
+ int mY = me.getY();
+ int cX = component.getX();
+ int cY = component.getY();
+ int moveX = mX - mousePrevX; // Negative if move left
+ int moveY = mY - mousePrevY; // Negative if move down
+ if (moveX == 0 && moveY == 0) return;
+ mousePrevX = mX - moveX;
+ mousePrevY = mY - moveY;
+ int newX = cX + moveX;
+ int newY = cY + moveY;
+ component.setLocation(newX, newY);
+ }
+
+ public void mouseMoved(MouseEvent e)
+ {
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/DropTargetAdapter.java b/java/src/javazoom/jlgui/player/amp/skin/DropTargetAdapter.java
new file mode 100644
index 0000000..46b6a98
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/DropTargetAdapter.java
@@ -0,0 +1,163 @@
+/*
+ * DropTargetAdapter.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+import java.io.IOException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class DropTargetAdapter implements DropTargetListener
+{
+ private static Log log = LogFactory.getLog(DropTargetAdapter.class);
+
+ public DropTargetAdapter()
+ {
+ super();
+ }
+
+ public void dragEnter(DropTargetDragEvent e)
+ {
+ if (isDragOk(e) == false)
+ {
+ e.rejectDrag();
+ }
+ }
+
+ public void dragOver(DropTargetDragEvent e)
+ {
+ if (isDragOk(e) == false)
+ {
+ e.rejectDrag();
+ }
+ }
+
+ public void dropActionChanged(DropTargetDragEvent e)
+ {
+ if (isDragOk(e) == false)
+ {
+ e.rejectDrag();
+ }
+ }
+
+ public void dragExit(DropTargetEvent dte)
+ {
+ }
+
+ protected boolean isDragOk(DropTargetDragEvent e)
+ {
+ // Check DataFlavor
+ DataFlavor[] dfs = e.getCurrentDataFlavors();
+ DataFlavor tdf = null;
+ for (int i = 0; i < dfs.length; i++)
+ {
+ if (DataFlavor.javaFileListFlavor.equals(dfs[i]))
+ {
+ tdf = dfs[i];
+ break;
+ }
+ else if (DataFlavor.stringFlavor.equals(dfs[i]))
+ {
+ tdf = dfs[i];
+ break;
+ }
+ }
+ // Only file list allowed.
+ if (tdf != null)
+ {
+ // Only DnD COPY allowed.
+ if ((e.getSourceActions() & DnDConstants.ACTION_COPY) != 0)
+ {
+ return true;
+ }
+ else return false;
+ }
+ else return false;
+ }
+
+ public void drop(DropTargetDropEvent e)
+ {
+ // Check DataFlavor
+ DataFlavor[] dfs = e.getCurrentDataFlavors();
+ DataFlavor tdf = null;
+ for (int i = 0; i < dfs.length; i++)
+ {
+ if (DataFlavor.javaFileListFlavor.equals(dfs[i]))
+ {
+ tdf = dfs[i];
+ break;
+ }
+ else if (DataFlavor.stringFlavor.equals(dfs[i]))
+ {
+ tdf = dfs[i];
+ break;
+ }
+ }
+ // Data Flavor available ?
+ if (tdf != null)
+ {
+ // Accept COPY DnD only.
+ if ((e.getSourceActions() & DnDConstants.ACTION_COPY) != 0)
+ {
+ e.acceptDrop(DnDConstants.ACTION_COPY);
+ }
+ else return;
+ try
+ {
+ Transferable t = e.getTransferable();
+ Object data = t.getTransferData(tdf);
+ processDrop(data);
+ }
+ catch (IOException ioe)
+ {
+ log.info("Drop error", ioe);
+ e.dropComplete(false);
+ return;
+ }
+ catch (UnsupportedFlavorException ufe)
+ {
+ log.info("Drop error", ufe);
+ e.dropComplete(false);
+ return;
+ }
+ catch (Exception ex)
+ {
+ log.info("Drop error", ex);
+ e.dropComplete(false);
+ return;
+ }
+ e.dropComplete(true);
+ }
+ }
+
+ public void processDrop(Object data)
+ {
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/ImageBorder.java b/java/src/javazoom/jlgui/player/amp/skin/ImageBorder.java
new file mode 100644
index 0000000..50fa8a1
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/ImageBorder.java
@@ -0,0 +1,65 @@
+/*
+ * ImageBorder.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Insets;
+import javax.swing.border.Border;
+
+public class ImageBorder implements Border
+{
+ private Insets insets = new Insets(0, 0, 0, 0);
+ private Image image = null;
+
+ public ImageBorder()
+ {
+ super();
+ }
+
+ public void setImage(Image image)
+ {
+ this.image = image;
+ }
+
+ public boolean isBorderOpaque()
+ {
+ return true;
+ }
+
+ public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
+ {
+ if (image != null)
+ {
+ int x0 = x + (width - image.getWidth(null)) / 2;
+ int y0 = y + (height - image.getHeight(null)) / 2;
+ g.drawImage(image, x0, y0, null);
+ }
+ }
+
+ public Insets getBorderInsets(Component c)
+ {
+ return insets;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/PlaylistUIDelegate.java b/java/src/javazoom/jlgui/player/amp/skin/PlaylistUIDelegate.java
new file mode 100644
index 0000000..1671688
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/PlaylistUIDelegate.java
@@ -0,0 +1,276 @@
+/*
+ * PlaylistUIDelegate.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Image;
+import javazoom.jlgui.player.amp.playlist.PlaylistItem;
+import javazoom.jlgui.player.amp.playlist.ui.PlaylistUI;
+
+public class PlaylistUIDelegate
+{
+ private AbsoluteConstraints constraints = null;
+ private Image titleLeftImage = null;
+ private Image titleRightImage = null;
+ private Image titleCenterImage = null;
+ private Image titleStretchImage = null;
+ private Image leftImage = null;
+ private Image rightImage = null;
+ private Image bottomLeftImage = null;
+ private Image bottomRightImage = null;
+ private Image bottomStretchImage = null;
+ private Color backgroundColor = null;
+ private Color selectedBackgroundColor = null;
+ private Color normalColor = null;
+ private Color currentColor = null;
+ private Font font = null;
+ private int listarea[] = { 12, 24 - 4, 256, 78 };
+ private PlaylistUI parent = null;
+
+ public PlaylistUIDelegate()
+ {
+ super();
+ currentColor = new Color(102, 204, 255);
+ normalColor = new Color(0xb2, 0xe4, 0xf6);
+ selectedBackgroundColor = Color.black;
+ backgroundColor = Color.black;
+ font = new Font("Dialog", Font.PLAIN, 10);
+ }
+
+ public void setParent(PlaylistUI playlist)
+ {
+ parent = playlist;
+ }
+
+ public Color getBackgroundColor()
+ {
+ return backgroundColor;
+ }
+
+ public void setBackgroundColor(Color backgroundColor)
+ {
+ this.backgroundColor = backgroundColor;
+ }
+
+ public Color getSelectedBackgroundColor()
+ {
+ return selectedBackgroundColor;
+ }
+
+ public Color getCurrentColor()
+ {
+ return currentColor;
+ }
+
+ public void setCurrentColor(Color currentColor)
+ {
+ this.currentColor = currentColor;
+ }
+
+ public Color getNormalColor()
+ {
+ return normalColor;
+ }
+
+ public void setNormalColor(Color normalColor)
+ {
+ this.normalColor = normalColor;
+ }
+
+ public void setSelectedBackgroundColor(Color selectedColor)
+ {
+ this.selectedBackgroundColor = selectedColor;
+ }
+
+ public Image getBottomLeftImage()
+ {
+ return bottomLeftImage;
+ }
+
+ public void setBottomLeftImage(Image bottomLeftImage)
+ {
+ this.bottomLeftImage = bottomLeftImage;
+ }
+
+ public Image getBottomRightImage()
+ {
+ return bottomRightImage;
+ }
+
+ public void setBottomRightImage(Image bottomRightImage)
+ {
+ this.bottomRightImage = bottomRightImage;
+ }
+
+ public Image getBottomStretchImage()
+ {
+ return bottomStretchImage;
+ }
+
+ public void setBottomStretchImage(Image bottomStretchImage)
+ {
+ this.bottomStretchImage = bottomStretchImage;
+ }
+
+ public Image getLeftImage()
+ {
+ return leftImage;
+ }
+
+ public void setLeftImage(Image leftImage)
+ {
+ this.leftImage = leftImage;
+ }
+
+ public Image getRightImage()
+ {
+ return rightImage;
+ }
+
+ public void setRightImage(Image rightImage)
+ {
+ this.rightImage = rightImage;
+ }
+
+ public Image getTitleCenterImage()
+ {
+ return titleCenterImage;
+ }
+
+ public void setTitleCenterImage(Image titleCenterImage)
+ {
+ this.titleCenterImage = titleCenterImage;
+ }
+
+ public Image getTitleLeftImage()
+ {
+ return titleLeftImage;
+ }
+
+ public void setTitleLeftImage(Image titleLeftImage)
+ {
+ this.titleLeftImage = titleLeftImage;
+ }
+
+ public Image getTitleRightImage()
+ {
+ return titleRightImage;
+ }
+
+ public void setTitleRightImage(Image titleRightImage)
+ {
+ this.titleRightImage = titleRightImage;
+ }
+
+ public Image getTitleStretchImage()
+ {
+ return titleStretchImage;
+ }
+
+ public void setTitleStretchImage(Image titleStretchImage)
+ {
+ this.titleStretchImage = titleStretchImage;
+ }
+
+ public void setConstraints(AbsoluteConstraints cnts)
+ {
+ constraints = cnts;
+ }
+
+ public AbsoluteConstraints getConstraints()
+ {
+ return constraints;
+ }
+
+ public int getLines()
+ {
+ return ((listarea[3] - listarea[1]) / 12);
+ }
+
+ public boolean isInSelectArea(int x, int y)
+ {
+ return (x >= listarea[0] && x <= listarea[2] && y >= listarea[1] && y <= listarea[3]);
+ }
+
+ public boolean isIndexArea(int y, int n)
+ {
+ return (y >= listarea[1] + 12 - 10 + n * 12 && y < listarea[1] + 12 - 10 + n * 12 + 14);
+ }
+
+ public void paintBackground(Graphics g)
+ {
+ g.drawImage(titleLeftImage, 0, 0, null);
+ g.drawImage(titleStretchImage, 25, 0, null);
+ g.drawImage(titleStretchImage, 50, 0, null);
+ g.drawImage(titleStretchImage, 62, 0, null);
+ g.drawImage(titleCenterImage, 87, 0, null);
+ g.drawImage(titleStretchImage, 187, 0, null);
+ g.drawImage(titleStretchImage, 200, 0, null);
+ g.drawImage(titleStretchImage, 225, 0, null);
+ g.drawImage(titleRightImage, 250, 0, null);
+ g.drawImage(leftImage, 0, 20, null);
+ g.drawImage(leftImage, 0, 48, null);
+ g.drawImage(leftImage, 0, 50, null);
+ //g.drawImage(rightImage, parent.getWidth() - 20, 20, null);
+ //g.drawImage(rightImage, parent.getWidth() - 20, 48, null);
+ //g.drawImage(rightImage, parent.getWidth() - 20, 50, null);
+ g.drawImage(bottomLeftImage, 0, parent.getHeight() - 38, null);
+ g.drawImage(bottomRightImage, 125, parent.getHeight() - 38, null);
+ }
+
+ public void paintList(Graphics g)
+ {
+ g.setColor(backgroundColor);
+ g.fillRect(listarea[0], listarea[1], listarea[2] - listarea[0], listarea[3] - listarea[1]);
+ if (font != null) g.setFont(font);
+ if (parent.getPlaylist() != null)
+ {
+ int currentSelection = parent.getPlaylist().getSelectedIndex();
+ g.setColor(normalColor);
+ int n = parent.getPlaylist().getPlaylistSize();
+ for (int i = 0; i < n; i++)
+ {
+ if (i < parent.getTopIndex()) continue;
+ int k = i - parent.getTopIndex();
+ if (listarea[1] + 12 + k * 12 > listarea[3]) break;
+ PlaylistItem pli = parent.getPlaylist().getItemAt(i);
+ String name = pli.getFormattedName();
+ if (pli.isSelected())
+ {
+ g.setColor(selectedBackgroundColor);
+ g.fillRect(listarea[0] + 4, listarea[1] + 12 - 10 + k * 12, listarea[2] - listarea[0] - 4, 14);
+ }
+ if (i == currentSelection) g.setColor(currentColor);
+ else g.setColor(normalColor);
+ if (i + 1 >= 10) g.drawString((i + 1) + ". " + name, listarea[0] + 12, listarea[1] + 12 + k * 12);
+ else g.drawString("0" + (i + 1) + ". " + name, listarea[0] + 12, listarea[1] + 12 + k * 12);
+ if (i == currentSelection) g.setColor(normalColor);
+ }
+ //g.drawImage(rightImage, parent.getWidth() - 20, 20, null);
+ //g.drawImage(rightImage, parent.getWidth() - 20, 48, null);
+ //g.drawImage(rightImage, parent.getWidth() - 20, 50, null);
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/PopupAdapter.java b/java/src/javazoom/jlgui/player/amp/skin/PopupAdapter.java
new file mode 100644
index 0000000..3616a74
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/PopupAdapter.java
@@ -0,0 +1,61 @@
+/*
+ * PopupAdapter.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import javax.swing.JPopupMenu;
+
+public class PopupAdapter extends MouseAdapter
+{
+ private JPopupMenu popup = null;
+
+ public PopupAdapter(JPopupMenu popup)
+ {
+ super();
+ this.popup=popup;
+ }
+
+ public void mousePressed(MouseEvent e)
+ {
+ checkPopup(e);
+ }
+
+ public void mouseClicked(MouseEvent e)
+ {
+ checkPopup(e);
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ checkPopup(e);
+ }
+
+ private void checkPopup(MouseEvent e)
+ {
+ if (e.isPopupTrigger())
+ {
+ popup.show(e.getComponent(), e.getX(), e.getY());
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/Skin.java b/java/src/javazoom/jlgui/player/amp/skin/Skin.java
new file mode 100644
index 0000000..5575699
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/Skin.java
@@ -0,0 +1,1493 @@
+/*
+ * Skin.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.awt.image.PixelGrabber;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import javax.swing.ImageIcon;
+import javax.swing.JSlider;
+import javazoom.jlgui.player.amp.PlayerActionEvent;
+import javazoom.jlgui.player.amp.equalizer.ui.SplinePanel;
+import javazoom.jlgui.player.amp.util.Config;
+import javazoom.jlgui.player.amp.visual.ui.SpectrumTimeAnalyzer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class allows to load all skin (2.0 compliant) features.
+ */
+public class Skin
+{
+ private static Log log = LogFactory.getLog(Skin.class);
+ public static final String TITLETEXT = "jlGui 3.0 ";
+ private Config config = null;
+ private String skinVersion = "1"; // 1, 2, for different Volume.bmp
+ private String path = null;
+ private boolean dspEnabled = true;
+ /*-- Window Parameters --*/
+ private int WinWidth, WinHeight;
+ private String theMain = "main.bmp";
+ private Image imMain = null;
+ /*-- Text Members --*/
+ private int fontWidth = 5;
+ private int fontHeight = 6;
+ private String theText = "text.bmp";
+ private Image imText;
+ private String fontIndex = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\"@a " + "0123456789 :()-'!_+ /[]^&%.=$#" + " ?*";
+ private ActiveFont acFont = null;
+ private ActiveJLabel acTitleLabel = null;
+ private ActiveJLabel acSampleRateLabel = null;
+ private ActiveJLabel acBitRateLabel = null;
+ private String sampleRateClearText = " ";
+ private int[] sampleRateLocation = { 156, 43 };
+ private String bitsRateClearText = " ";
+ private int[] bitsRateLocation = { 110, 43 };
+ private int[] titleLocation = { 111, 27 };
+ /*-- Numbers Members --*/
+ private int numberWidth = 9;
+ private int numberHeight = 13;
+ private String theNumbers = "numbers.bmp";
+ private String theNumEx = "nums_ex.bmp";
+ private Image imNumbers;
+ private String numberIndex = "0123456789 ";
+ private int[] minuteHLocation = { 48, 26 };
+ private int[] minuteLLocation = { 60, 26 };
+ private int[] secondHLocation = { 78, 26 };
+ private int[] secondLLocation = { 90, 26 };
+ private ActiveJNumberLabel acMinuteH = null;
+ private ActiveJNumberLabel acMinuteL = null;
+ private ActiveJNumberLabel acSecondH = null;
+ private ActiveJNumberLabel acSecondL = null;
+ /*-- Buttons Panel members --*/
+ private String theButtons = "cbuttons.bmp";
+ private Image imButtons;
+ private ActiveJButton acPrevious, acPlay, acPause, acStop, acNext, acEject;
+ private Image imPrevious, imPlay, imPause, imStop, imNext, imEject;
+ private Image[] releasedImage = { imPrevious, imPlay, imPause, imStop, imNext, imEject };
+ private Image[] pressedImage = { imPrevious, imPlay, imPause, imStop, imNext, imEject };
+ private int[] releasedPanel = { 0, 0, 23, 18, 23, 0, 23, 18, 46, 0, 23, 18, 69, 0, 23, 18, 92, 0, 22, 18, 114, 0, 22, 16 };
+ private int[] pressedPanel = { 0, 18, 23, 18, 23, 18, 23, 18, 46, 18, 23, 18, 69, 18, 23, 18, 92, 18, 22, 18, 114, 16, 22, 16 };
+ private int[] panelLocation = { 16, 88, 39, 88, 62, 88, 85, 88, 108, 88, 136, 89 };
+ /*-- EqualizerUI/Playlist/Shuffle/Repeat --*/
+ private String theEPSRButtons = "shufrep.bmp";
+ private Image imEPSRButtons;
+ private ActiveJToggleButton acEqualizer, acPlaylist, acShuffle, acRepeat;
+ private Image[] releasedEPSRImage = { null, null, null, null };
+ private Image[] pressedEPSRImage = { null, null, null, null };
+ private int[] releasedEPSRPanel = { 0, 61, 23, 12, 23, 61, 23, 12, 28, 0, 47, 15, 0, 0, 28, 15 };
+ private int[] pressedEPSRPanel = { 0, 73, 23, 12, 23, 73, 23, 12, 28, 30, 47, 15, 0, 30, 28, 15 };
+ private int[] panelEPSRLocation = { 219, 58, 242, 58, 164, 89, 212, 89 };
+ /*-- Volume Panel members --*/
+ public static final int VOLUMEMAX = 100;
+ private String theVolume = "volume.bmp";
+ private Image imVolume;
+ private ActiveJSlider acVolume = null;;
+ private Image[] volumeImage = { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null };
+ private String fakeIndex = "abcdefghijklmnopqrstuvwxyz01";
+ private int[] volumeBarLocation = { 107, 57 };
+ private Image[] releasedVolumeImage = { null };
+ private Image[] pressedVolumeImage = { null };
+ private int[] releasedVolumePanel0 = { 15, 422, 14, 11 };
+ private int[] pressedVolumePanel0 = { 0, 422, 14, 11 };
+ private int[] releasedVolumePanel1 = { 75, 376, 14, 11 };
+ private int[] pressedVolumePanel1 = { 90, 376, 14, 11 };
+ /*-- Balance Panel members --*/
+ public static final int BALANCEMAX = 5;
+ private String theBalance = "balance.bmp";
+ private ActiveJSlider acBalance = null;
+ private Image imBalance;
+ private Image[] balanceImage = { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null };
+ private Image[] releasedBalanceImage = { null };
+ private Image[] pressedBalanceImage = { null };
+ private int[] releasedBalancePanel0 = { 15, 422, 14, 11 };
+ private int[] pressedBalancePanel0 = { 0, 422, 14, 11 };
+ private int[] releasedBalancePanel1 = { 75, 376, 14, 11 };
+ private int[] pressedBalancePanel1 = { 90, 376, 14, 11 };
+ private int[] balanceBarLocation = { 177, 57 };
+ /*-- Title members --*/
+ private String theTitleBar = "titlebar.bmp";
+ private Image imTitleBar;
+ private ActiveJBar acTitleBar = null;
+ private Image imTitleB;
+ private Image[] releasedTitleIm = { imTitleB };
+ private Image[] pressedTitleIm = { imTitleB };
+ private int[] releasedTitlePanel = { 27, 0, 264 - 20, 14 }; // -20 for the two button add by me
+ private int[] pressedTitlePanel = { 27, 15, 264 - 20, 14 };// -20 for the two button add by me
+ private int[] titleBarLocation = { 0, 0 };
+ /*-- Exit member --*/
+ private ActiveJButton acExit = null;
+ private int[] releasedExitPanel = { 18, 0, 9, 9 };
+ private int[] pressedExitPanel = { 18, 9, 9, 9 };
+ private Image[] releasedExitIm = { null };
+ private Image[] pressedExitIm = { null };
+ private int[] exitLocation = { 264, 3 };
+ /*-- Minimize member --*/
+ private ActiveJButton acMinimize = null;
+ private int[] releasedMinimizePanel = { 9, 0, 9, 9 };
+ private int[] pressedMinimizePanel = { 9, 9, 9, 9 };
+ private Image[] releasedMinimizeIm = { null };
+ private Image[] pressedMinimizeIm = { null };
+ private int[] minimizeLocation = { 244, 3 };
+ /*-- Mono/Stereo Members --*/
+ private String theMode = "monoster.bmp";
+ private Image imMode;
+ private int[] activeModePanel = { 0, 0, 28, 12, 29, 0, 27, 12 };
+ private int[] passiveModePanel = { 0, 12, 28, 12, 29, 12, 27, 12 };
+ private Image[] activeModeImage = { null, null };
+ private Image[] passiveModeImage = { null, null };
+ private int[] monoLocation = { 212, 41 };
+ private int[] stereoLocation = { 239, 41 };
+ private ActiveJIcon acMonoIcon = null;
+ private ActiveJIcon acStereoIcon = null;
+ /*-- PosBar members --*/
+ public static final int POSBARMAX = 1000;
+ private String thePosBar = "posbar.bmp";
+ private Image imPosBar;
+ private ActiveJSlider acPosBar = null;
+ private Image[] releasedPosIm = { null };
+ private Image[] pressedPosIm = { null };
+ private int[] releasedPosPanel = { 248, 0, 28, 10 };
+ private int[] pressedPosPanel = { 278, 0, 28, 10 };
+ private int[] posBarLocation = { 16, 72 };
+ /*-- Play/Pause Icons --*/
+ private String theIcons = "playpaus.bmp";
+ private Image imIcons;
+ private Image[] iconsImage = { null, null, null, null, null };
+ private int[] iconsPanel = { 0, 0, 9, 9, 9, 0, 9, 9, 18, 0, 9, 9, 36, 0, 3, 9, 27, 0, 2, 9 };
+ private int[] iconsLocation = { 26, 28, 24, 28 };
+ private ActiveJIcon acPlayIcon = null;
+ private ActiveJIcon acTimeIcon = null;
+ /*-- Readme --*/
+ private String theReadme = "readme.txt";
+ private String readme = null;
+ /*-- DSP and viscolor --*/
+ private String theViscolor = "viscolor.txt";
+ private String viscolor = null;
+ private int[] visualLocation = { 24, 44 };
+ private int[] visualSize = { 76, 15 };
+ private SpectrumTimeAnalyzer analyzer = null;
+ /*-- EqualizerUI --*/
+ private Image imFullEqualizer = null;
+ private Image imEqualizer = null;
+ private Image imSliders = null;
+ private ActiveJSlider[] acSlider = { null, null, null, null, null, null, null, null, null, null, null };
+ private Image[] sliderImage = { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null };
+ private int[][] sliderBarLocation = { { 21, 38 }, { 78, 38 }, { 96, 38 }, { 114, 38 }, { 132, 38 }, { 150, 38 }, { 168, 38 }, { 186, 38 }, { 204, 38 }, { 222, 38 }, { 240, 38 } };
+ private Image[] releasedSliderImage = { null };
+ private Image[] pressedSliderImage = { null };
+ private int[][] sliderLocation = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
+ private Image[] releasedPresetsImage = { null };
+ private Image[] pressedPresetsImage = { null };
+ private int[] panelPresetsLocation = { 217, 18 };
+ private ActiveJButton acPresets = null;
+ private ActiveJToggleButton acOnOff, acAuto;
+ private Image[] releasedOAImage = { null, null };
+ private Image[] pressedOAImage = { null, null };
+ private int[] panelOALocation = { 15, 18, 39, 18 };
+ private SplinePanel spline = null;
+ private int[] panelSplineLocation = { 88, 17, 113, 19 };
+ private Image splineImage = null;
+ private Image splineBarImage = null;
+ private ResourceBundle bundle = null;
+ /*-- Playlist --*/
+ private PlaylistUIDelegate playlist = null;
+ private Image imPlaylist = null;
+ private String plEdit = null;
+ private ActiveJSlider acPlSlider = null;
+ private int[] plSliderLocation = { 255, 20 };
+ private ActiveJButton acPlUp, acPlDown;
+ private ActiveJButton acPlAdd, acPlRemove, acPlSelect, acPlMisc, acPlList;
+ private int[] plAddLocation = { 14, 86 };
+ private int[] plRemoveLocation = { 14 + 30, 86 };
+ private int[] plSelectLocation = { 14 + 60, 86 };
+ private int[] plMiscLocation = { 14 + 89, 86 };
+ private int[] plListLocation = { 14 + 214, 86 };
+ private ActiveJPopup acPlAddPopup, acPlRemovePopup, acPlSelectPopup, acPlMiscPopup, acPlListPopup;
+ private int[] plAddPopupArea = { 14, 50, 22, 18 * 3 };
+ private int[] plRemovePopupArea = { 14 + 29, 32, 22, 18 * 4 };
+ private int[] plSelectPopupArea = { 14 + 58, 50, 22, 18 * 3 };
+ private int[] plMiscPopupArea = { 14 + 87, 50, 22, 18 * 3 };
+ private int[] plListPopupArea = { 14 + 217, 50, 22, 18 * 3 };
+
+ public Skin()
+ {
+ super();
+ String i18n = "javazoom/jlgui/player/amp/skin/skin";
+ bundle = ResourceBundle.getBundle(i18n);
+ }
+
+ /**
+ * Return I18N value of a given key.
+ * @param key
+ * @return
+ */
+ public String getResource(String key)
+ {
+ String value = null;
+ try
+ {
+ value = bundle.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ log.debug(e);
+ }
+ return value;
+ }
+
+ /**
+ * Return skin path.
+ * @return
+ */
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public boolean isDspEnabled()
+ {
+ return dspEnabled;
+ }
+
+ public void setDspEnabled(boolean dspEnabled)
+ {
+ this.dspEnabled = dspEnabled;
+ }
+
+ /**
+ * Loads a new skin from local file system.
+ * @param skinName
+ */
+ public void loadSkin(String skinName)
+ {
+ SkinLoader skl = new SkinLoader(skinName);
+ try
+ {
+ loadSkin(skl);
+ path = skinName;
+ }
+ catch (Exception e)
+ {
+ log.info("Can't load skin : ", e);
+ InputStream sis = this.getClass().getClassLoader().getResourceAsStream("javazoom/jlgui/player/amp/metrix.wsz");
+ log.info("Load default skin for JAR");
+ loadSkin(sis);
+ }
+ }
+
+ /**
+ * Loads a new skin from any input stream.
+ * @param skinStream
+ */
+ public void loadSkin(InputStream skinStream)
+ {
+ SkinLoader skl = new SkinLoader(skinStream);
+ try
+ {
+ loadSkin(skl);
+ }
+ catch (Exception e)
+ {
+ log.info("Can't load skin : ", e);
+ InputStream sis = this.getClass().getClassLoader().getResourceAsStream("javazoom/jlgui/player/amp/metrix.wsz");
+ log.info("Load default skin for JAR");
+ loadSkin(sis);
+ }
+ }
+
+ /**
+ * Loads a skin from a SkinLoader.
+ * @param skl
+ * @throws Exception
+ */
+ public void loadSkin(SkinLoader skl) throws Exception
+ {
+ skl.loadImages();
+ imMain = skl.getImage(theMain);
+ imButtons = skl.getImage(theButtons);
+ imTitleBar = skl.getImage(theTitleBar);
+ imText = skl.getImage(theText);
+ imMode = skl.getImage(theMode);
+ imNumbers = skl.getImage(theNumbers);
+ // add by John Yang
+ if (imNumbers == null)
+ {
+ log.debug("Try load nums_ex.bmp !");
+ imNumbers = skl.getImage(theNumEx);
+ }
+ imVolume = skl.getImage(theVolume);
+ imBalance = skl.getImage(theBalance);
+ imIcons = skl.getImage(theIcons);
+ imPosBar = skl.getImage(thePosBar);
+ imEPSRButtons = skl.getImage(theEPSRButtons);
+ viscolor = (String) skl.getContent(theViscolor);
+ String readmeStr = theReadme;
+ readme = (String) skl.getContent(readmeStr);
+ if (readme == null)
+ {
+ readmeStr = readmeStr.toUpperCase();
+ readme = (String) skl.getContent(readmeStr);
+ }
+ if (readme == null)
+ {
+ readmeStr = readmeStr.substring(0, 1) + theReadme.substring(1, theReadme.length());
+ readme = (String) skl.getContent(readmeStr);
+ }
+ // Computes volume slider height :
+ int vh = (imVolume.getHeight(null) - 422);
+ if (vh > 0)
+ {
+ releasedVolumePanel0[3] = vh;
+ pressedVolumePanel0[3] = vh;
+ releasedVolumePanel1[3] = vh;
+ pressedVolumePanel1[3] = vh;
+ }
+ // Computes balance slider height :
+ if (imBalance == null) imBalance = imVolume;
+ int bh = (imBalance.getHeight(null) - 422);
+ if (bh > 0)
+ {
+ releasedBalancePanel0[3] = bh;
+ pressedBalancePanel0[3] = bh;
+ releasedBalancePanel1[3] = bh;
+ pressedBalancePanel1[3] = bh;
+ }
+ // Compute posbar height.
+ int ph = imPosBar.getHeight(null);
+ if (ph > 0)
+ {
+ releasedPosPanel[3] = ph;
+ pressedPosPanel[3] = ph;
+ }
+ WinHeight = imMain.getHeight(null); // 116
+ WinWidth = imMain.getWidth(null); // 275
+ /*-- Text --*/
+ acFont = new ActiveFont(imText, fontIndex, fontWidth, fontHeight);
+ acTitleLabel = new ActiveJLabel();
+ acTitleLabel.setAcFont(acFont);
+ acTitleLabel.setCropRectangle(new Rectangle(0, 0, 155, 6));
+ acTitleLabel.setConstraints(new AbsoluteConstraints(titleLocation[0], titleLocation[1], 155, 6));
+ acTitleLabel.setAcText(TITLETEXT.toUpperCase());
+ acSampleRateLabel = new ActiveJLabel();
+ acSampleRateLabel.setAcFont(acFont);
+ acSampleRateLabel.setConstraints(new AbsoluteConstraints(sampleRateLocation[0], sampleRateLocation[1]));
+ acSampleRateLabel.setAcText(sampleRateClearText);
+ acBitRateLabel = new ActiveJLabel();
+ acBitRateLabel.setAcFont(acFont);
+ acBitRateLabel.setConstraints(new AbsoluteConstraints(bitsRateLocation[0], bitsRateLocation[1]));
+ acBitRateLabel.setAcText(bitsRateClearText);
+ /*-- Buttons --*/
+ readPanel(releasedImage, releasedPanel, pressedImage, pressedPanel, imButtons);
+ setButtonsPanel();
+ /*-- Volume/Balance --*/
+ if (skinVersion.equals("1"))
+ {
+ readPanel(releasedVolumeImage, releasedVolumePanel0, pressedVolumeImage, pressedVolumePanel0, imVolume);
+ readPanel(releasedBalanceImage, releasedBalancePanel0, pressedBalanceImage, pressedBalancePanel0, imBalance);
+ }
+ else
+ {
+ readPanel(releasedVolumeImage, releasedVolumePanel1, pressedVolumeImage, pressedVolumePanel1, imVolume);
+ readPanel(releasedBalanceImage, releasedBalancePanel1, pressedBalanceImage, pressedBalancePanel1, imBalance);
+ }
+ setVolumeBalancePanel(vh, bh);
+ /*-- Title Bar --*/
+ readPanel(releasedTitleIm, releasedTitlePanel, pressedTitleIm, pressedTitlePanel, imTitleBar);
+ setTitleBarPanel();
+ /*-- Exit --*/
+ readPanel(releasedExitIm, releasedExitPanel, pressedExitIm, pressedExitPanel, imTitleBar);
+ setExitPanel();
+ /*-- Minimize --*/
+ readPanel(releasedMinimizeIm, releasedMinimizePanel, pressedMinimizeIm, pressedMinimizePanel, imTitleBar);
+ setMinimizePanel();
+ /*-- Mode --*/
+ readPanel(activeModeImage, activeModePanel, passiveModeImage, passiveModePanel, imMode);
+ setMonoStereoPanel();
+ /*-- Numbers --*/
+ ImageIcon[] numbers = new ImageIcon[numberIndex.length()];
+ for (int h = 0; h < numberIndex.length(); h++)
+ {
+ numbers[h] = new ImageIcon((new Taftb(numberIndex, imNumbers, numberWidth, numberHeight, 0, "" + numberIndex.charAt(h))).getBanner());
+ }
+ acMinuteH = new ActiveJNumberLabel();
+ acMinuteH.setNumbers(numbers);
+ acMinuteH.setConstraints(new AbsoluteConstraints(minuteHLocation[0], minuteHLocation[1]));
+ acMinuteH.setAcText(" ");
+ acMinuteL = new ActiveJNumberLabel();
+ acMinuteL.setNumbers(numbers);
+ acMinuteL.setConstraints(new AbsoluteConstraints(minuteLLocation[0], minuteLLocation[1]));
+ acMinuteL.setAcText(" ");
+ acSecondH = new ActiveJNumberLabel();
+ acSecondH.setNumbers(numbers);
+ acSecondH.setConstraints(new AbsoluteConstraints(secondHLocation[0], secondHLocation[1]));
+ acSecondH.setAcText(" ");
+ acSecondL = new ActiveJNumberLabel();
+ acSecondL.setNumbers(numbers);
+ acSecondL.setConstraints(new AbsoluteConstraints(secondLLocation[0], secondLLocation[1]));
+ acSecondL.setAcText(" ");
+ /*-- Icons --*/
+ readPanel(iconsImage, iconsPanel, null, null, imIcons);
+ acPlayIcon = new ActiveJIcon();
+ ImageIcon[] playIcons = { new ImageIcon(iconsImage[0]), new ImageIcon(iconsImage[1]), new ImageIcon(iconsImage[2]) };
+ acPlayIcon.setIcons(playIcons);
+ acPlayIcon.setConstraints(new AbsoluteConstraints(iconsLocation[0], iconsLocation[1]));
+ acPlayIcon.setIcon(2);
+ acTimeIcon = new ActiveJIcon();
+ ImageIcon[] timeIcons = { new ImageIcon(iconsImage[3]), new ImageIcon(iconsImage[4]) };
+ acTimeIcon.setIcons(timeIcons);
+ acTimeIcon.setConstraints(new AbsoluteConstraints(iconsLocation[2], iconsLocation[3]));
+ /*-- DSP --*/
+ setAnalyzerPanel();
+ /*-- Pos Bar --*/
+ readPanel(releasedPosIm, releasedPosPanel, pressedPosIm, pressedPosPanel, imPosBar);
+ setPosBarPanel();
+ /*-- EqualizerUI/Playlist/Shuffle/Repeat --*/
+ readPanel(releasedEPSRImage, releasedEPSRPanel, pressedEPSRImage, pressedEPSRPanel, imEPSRButtons);
+ setEPSRButtonsPanel();
+ /*-- EqualizerUI --*/
+ imFullEqualizer = skl.getImage("eqmain.bmp");
+ imEqualizer = new BufferedImage(WinWidth, WinHeight, BufferedImage.TYPE_INT_RGB);
+ imEqualizer.getGraphics().drawImage(imFullEqualizer, 0, 0, null);
+ imSliders = new BufferedImage(208, 128, BufferedImage.TYPE_INT_RGB);
+ imSliders.getGraphics().drawImage(imFullEqualizer, 0, 0, 208, 128, 13, 164, 13 + 208, 164 + 128, null);
+ setSliderPanel();
+ setOnOffAutoPanel();
+ setPresetsPanel();
+ setSplinePanel();
+ /*-- Playlist --*/
+ imPlaylist = skl.getImage("pledit.bmp");
+ plEdit = (String) skl.getContent("pledit.txt");
+ setPlaylistPanel();
+ }
+
+ /**
+ * Instantiate Buttons Panel with ActiveComponent.
+ */
+ private void setButtonsPanel()
+ {
+ int l = 0;
+ acPrevious = new ActiveJButton();
+ acPrevious.setIcon(new ImageIcon(releasedImage[0]));
+ acPrevious.setPressedIcon(new ImageIcon(pressedImage[0]));
+ acPrevious.setConstraints(new AbsoluteConstraints(panelLocation[l++], panelLocation[l++], releasedImage[0].getWidth(null), releasedImage[0].getHeight(null)));
+ acPrevious.setToolTipText(getResource("button.previous"));
+ acPrevious.setActionCommand(PlayerActionEvent.ACPREVIOUS);
+ acPlay = new ActiveJButton();
+ acPlay.setIcon(new ImageIcon(releasedImage[1]));
+ acPlay.setPressedIcon(new ImageIcon(pressedImage[1]));
+ acPlay.setConstraints(new AbsoluteConstraints(panelLocation[l++], panelLocation[l++], releasedImage[1].getWidth(null), releasedImage[1].getHeight(null)));
+ acPlay.setToolTipText(getResource("button.play"));
+ acPlay.setActionCommand(PlayerActionEvent.ACPLAY);
+ acPause = new ActiveJButton();
+ acPause.setIcon(new ImageIcon(releasedImage[2]));
+ acPause.setPressedIcon(new ImageIcon(pressedImage[2]));
+ acPause.setConstraints(new AbsoluteConstraints(panelLocation[l++], panelLocation[l++], releasedImage[2].getWidth(null), releasedImage[2].getHeight(null)));
+ acPause.setToolTipText(getResource("button.pause"));
+ acPause.setActionCommand(PlayerActionEvent.ACPAUSE);
+ acStop = new ActiveJButton();
+ acStop.setIcon(new ImageIcon(releasedImage[3]));
+ acStop.setPressedIcon(new ImageIcon(pressedImage[3]));
+ acStop.setConstraints(new AbsoluteConstraints(panelLocation[l++], panelLocation[l++], releasedImage[3].getWidth(null), releasedImage[3].getHeight(null)));
+ acStop.setToolTipText(getResource("button.stop"));
+ acStop.setActionCommand(PlayerActionEvent.ACSTOP);
+ acNext = new ActiveJButton();
+ acNext.setIcon(new ImageIcon(releasedImage[4]));
+ acNext.setPressedIcon(new ImageIcon(pressedImage[4]));
+ acNext.setConstraints(new AbsoluteConstraints(panelLocation[l++], panelLocation[l++], releasedImage[4].getWidth(null), releasedImage[4].getHeight(null)));
+ acNext.setToolTipText(getResource("button.next"));
+ acNext.setActionCommand(PlayerActionEvent.ACNEXT);
+ acEject = new ActiveJButton();
+ acEject.setIcon(new ImageIcon(releasedImage[5]));
+ acEject.setPressedIcon(new ImageIcon(pressedImage[5]));
+ acEject.setConstraints(new AbsoluteConstraints(panelLocation[l++], panelLocation[l++], releasedImage[5].getWidth(null), releasedImage[5].getHeight(null)));
+ acEject.setToolTipText(getResource("button.eject"));
+ acEject.setActionCommand(PlayerActionEvent.ACEJECT);
+ }
+
+ /**
+ * Instantiate EPSR Buttons Panel with ActiveComponent.
+ * imEqualizer, imPlaylist, imShuffle, imRepeat
+ */
+ private void setEPSRButtonsPanel()
+ {
+ int l = 0;
+ acEqualizer = new ActiveJToggleButton();
+ acEqualizer.setIcon(new ImageIcon(releasedEPSRImage[0]));
+ acEqualizer.setSelectedIcon(new ImageIcon(pressedEPSRImage[0]));
+ acEqualizer.setPressedIcon(new ImageIcon(pressedEPSRImage[0]));
+ acEqualizer.setConstraints(new AbsoluteConstraints(panelEPSRLocation[l++], panelEPSRLocation[l++], releasedEPSRImage[0].getWidth(null), releasedEPSRImage[0].getHeight(null)));
+ acEqualizer.setToolTipText(getResource("toggle.equalizer"));
+ acEqualizer.setActionCommand(PlayerActionEvent.ACEQUALIZER);
+ acEqualizer.setSelected(config.isEqualizerEnabled());
+ acPlaylist = new ActiveJToggleButton();
+ acPlaylist.setIcon(new ImageIcon(releasedEPSRImage[1]));
+ acPlaylist.setSelectedIcon(new ImageIcon(pressedEPSRImage[1]));
+ acPlaylist.setPressedIcon(new ImageIcon(pressedEPSRImage[1]));
+ acPlaylist.setConstraints(new AbsoluteConstraints(panelEPSRLocation[l++], panelEPSRLocation[l++], releasedEPSRImage[1].getWidth(null), releasedEPSRImage[1].getHeight(null)));
+ acPlaylist.setToolTipText(getResource("toggle.playlist"));
+ acPlaylist.setActionCommand(PlayerActionEvent.ACPLAYLIST);
+ acPlaylist.setSelected(config.isPlaylistEnabled());
+ acShuffle = new ActiveJToggleButton();
+ acShuffle.setIcon(new ImageIcon(releasedEPSRImage[2]));
+ acShuffle.setSelectedIcon(new ImageIcon(pressedEPSRImage[2]));
+ acShuffle.setPressedIcon(new ImageIcon(pressedEPSRImage[2]));
+ acShuffle.setConstraints(new AbsoluteConstraints(panelEPSRLocation[l++], panelEPSRLocation[l++], releasedEPSRImage[2].getWidth(null), releasedEPSRImage[2].getHeight(null)));
+ acShuffle.setToolTipText(getResource("toggle.shuffle"));
+ acShuffle.setActionCommand(PlayerActionEvent.ACSHUFFLE);
+ acShuffle.setSelected(config.isShuffleEnabled());
+ acRepeat = new ActiveJToggleButton();
+ acRepeat.setIcon(new ImageIcon(releasedEPSRImage[3]));
+ acRepeat.setSelectedIcon(new ImageIcon(pressedEPSRImage[3]));
+ acRepeat.setPressedIcon(new ImageIcon(pressedEPSRImage[3]));
+ acRepeat.setConstraints(new AbsoluteConstraints(panelEPSRLocation[l++], panelEPSRLocation[l++], releasedEPSRImage[3].getWidth(null), releasedEPSRImage[3].getHeight(null)));
+ acRepeat.setToolTipText(getResource("toggle.repeat"));
+ acRepeat.setActionCommand(PlayerActionEvent.ACREPEAT);
+ acRepeat.setSelected(config.isRepeatEnabled());
+ }
+
+ /**
+ * Instantiate Volume/Balance Panel with ActiveComponent.
+ * @param vheight
+ * @param bheight
+ */
+ private void setVolumeBalancePanel(int vheight, int bheight)
+ {
+ // Volume.
+ acVolume = new ActiveJSlider();
+ acVolume.setMinimum(0);
+ acVolume.setMaximum(VOLUMEMAX);
+ int volumeValue = config.getVolume();
+ if (volumeValue < 0) volumeValue = (int) VOLUMEMAX / 2;
+ acVolume.setValue(volumeValue);
+ acVolume.setToolTipText(getResource("slider.volume"));
+ int l = 0;
+ for (int k = 0; k < volumeImage.length; k++)
+ {
+ //volumeImage[k] = (new Taftb(fakeIndex, imVolume, 68, 13, 2, "" + fakeIndex.charAt(k))).getBanner();
+ volumeImage[k] = (new Taftb(fakeIndex, imVolume, imVolume.getWidth(null), 13, 2, "" + fakeIndex.charAt(k))).getBanner();
+ }
+ if (volumeImage[0].getHeight(null) > releasedVolumeImage[0].getHeight(null))
+ {
+ acVolume.setConstraints(new AbsoluteConstraints(volumeBarLocation[l++], volumeBarLocation[l++], volumeImage[0].getWidth(null), volumeImage[0].getHeight(null)));
+ }
+ else
+ {
+ acVolume.setConstraints(new AbsoluteConstraints(volumeBarLocation[l++], volumeBarLocation[l++], volumeImage[0].getWidth(null), releasedVolumeImage[0].getHeight(null)));
+ }
+ ActiveSliderUI sUI = new ActiveSliderUI(acVolume);
+ sUI.setThumbImage(releasedVolumeImage[0]);
+ sUI.setThumbPressedImage(pressedVolumeImage[0]);
+ sUI.setBackgroundImages(volumeImage);
+ if (vheight < 0) vheight = 0;
+ sUI.forceThumbHeight(vheight);
+ sUI.setThumbXOffset(0);
+ sUI.setThumbYOffset(1);
+ acVolume.setUI(sUI);
+ // Balance
+ acBalance = new ActiveJSlider();
+ acBalance.setMinimum(-BALANCEMAX);
+ acBalance.setMaximum(BALANCEMAX);
+ acBalance.setValue(0);
+ acBalance.setToolTipText(getResource("slider.balance"));
+ Image cropBalance = new BufferedImage(38, 418, BufferedImage.TYPE_INT_RGB);
+ Graphics g = cropBalance.getGraphics();
+ g.drawImage(imBalance, 0, 0, 38, 418, 9, 0, 9 + 38, 0 + 418, null);
+ for (int k = 0; k < balanceImage.length; k++)
+ {
+ balanceImage[k] = (new Taftb(fakeIndex, cropBalance, 38, 13, 2, "" + fakeIndex.charAt(k))).getBanner();
+ }
+ l = 0;
+ if (balanceImage[0].getHeight(null) > releasedBalanceImage[0].getHeight(null))
+ {
+ acBalance.setConstraints(new AbsoluteConstraints(balanceBarLocation[l++], balanceBarLocation[l++], balanceImage[0].getWidth(null), balanceImage[0].getHeight(null)));
+ }
+ else
+ {
+ acBalance.setConstraints(new AbsoluteConstraints(balanceBarLocation[l++], balanceBarLocation[l++], balanceImage[0].getWidth(null), releasedBalanceImage[0].getHeight(null)));
+ }
+ sUI = new ActiveSliderUI(acBalance);
+ sUI.setThumbImage(releasedBalanceImage[0]);
+ sUI.setThumbPressedImage(pressedBalanceImage[0]);
+ sUI.setBackgroundImages(balanceImage);
+ if (bheight < 0) bheight = 0;
+ sUI.forceThumbHeight(bheight);
+ sUI.setThumbXOffset(1);
+ sUI.setThumbYOffset(1);
+ acBalance.setUI(sUI);
+ }
+
+ /**
+ * Instantiate Title Panel with ActiveComponent.
+ */
+ protected void setTitleBarPanel()
+ {
+ int l = 0;
+ acTitleBar = new ActiveJBar();
+ ImageBorder border = new ImageBorder();
+ border.setImage(releasedTitleIm[0]);
+ acTitleBar.setBorder(border);
+ acTitleBar.setConstraints(new AbsoluteConstraints(titleBarLocation[l++], titleBarLocation[l++], releasedTitleIm[0].getWidth(null), releasedTitleIm[0].getHeight(null)));
+ }
+
+ /**
+ * Instantiate Exit Panel with ActiveComponent.
+ */
+ protected void setExitPanel()
+ {
+ int l = 0;
+ acExit = new ActiveJButton();
+ acExit.setIcon(new ImageIcon(releasedExitIm[0]));
+ acExit.setPressedIcon(new ImageIcon(pressedExitIm[0]));
+ acExit.setConstraints(new AbsoluteConstraints(exitLocation[l++], exitLocation[l++], releasedExitIm[0].getWidth(null), releasedExitIm[0].getHeight(null)));
+ acExit.setToolTipText(getResource("button.exit"));
+ acExit.setActionCommand(PlayerActionEvent.ACEXIT);
+ }
+
+ /**
+ * Instantiate Minimize Panel with ActiveComponent.
+ */
+ protected void setMinimizePanel()
+ {
+ int l = 0;
+ acMinimize = new ActiveJButton();
+ acMinimize.setIcon(new ImageIcon(releasedMinimizeIm[0]));
+ acMinimize.setPressedIcon(new ImageIcon(pressedMinimizeIm[0]));
+ acMinimize.setConstraints(new AbsoluteConstraints(minimizeLocation[l++], minimizeLocation[l++], releasedMinimizeIm[0].getWidth(null), releasedMinimizeIm[0].getHeight(null)));
+ acMinimize.setToolTipText(getResource("button.minimize"));
+ acMinimize.setActionCommand(PlayerActionEvent.ACMINIMIZE);
+ }
+
+ /**
+ * Instantiate Mono/Stereo panel.
+ */
+ private void setMonoStereoPanel()
+ {
+ acMonoIcon = new ActiveJIcon();
+ ImageIcon[] mono = { new ImageIcon(passiveModeImage[1]), new ImageIcon(activeModeImage[1]) };
+ acMonoIcon.setIcons(mono);
+ acMonoIcon.setIcon(0);
+ acMonoIcon.setConstraints(new AbsoluteConstraints(monoLocation[0], monoLocation[1], passiveModeImage[1].getWidth(null), passiveModeImage[1].getHeight(null)));
+ acStereoIcon = new ActiveJIcon();
+ ImageIcon[] stereo = { new ImageIcon(passiveModeImage[0]), new ImageIcon(activeModeImage[0]) };
+ acStereoIcon.setIcons(stereo);
+ acStereoIcon.setIcon(0);
+ acStereoIcon.setConstraints(new AbsoluteConstraints(stereoLocation[0], stereoLocation[1], passiveModeImage[0].getWidth(null), passiveModeImage[0].getHeight(null)));
+ }
+
+ /**
+ * Initialize Spectrum/Time analyzer.
+ */
+ private void setAnalyzerPanel()
+ {
+ String javaVersion = System.getProperty("java.version");
+ if ((javaVersion != null) && ((javaVersion.startsWith("1.3"))) || (javaVersion.startsWith("1.4")))
+ {
+ log.info("DSP disabled for JRE " + javaVersion);
+ }
+ else if (!dspEnabled)
+ {
+ log.info("DSP disabled");
+ }
+ else
+ {
+ if (analyzer == null) analyzer = new SpectrumTimeAnalyzer();
+ String visualMode = config.getVisualMode();
+ if ((visualMode != null) && (visualMode.length() > 0))
+ {
+ if (visualMode.equalsIgnoreCase("off")) analyzer.setDisplayMode(SpectrumTimeAnalyzer.DISPLAY_MODE_OFF);
+ else if (visualMode.equalsIgnoreCase("oscillo")) analyzer.setDisplayMode(SpectrumTimeAnalyzer.DISPLAY_MODE_SCOPE);
+ else analyzer.setDisplayMode(SpectrumTimeAnalyzer.DISPLAY_MODE_SPECTRUM_ANALYSER);
+ }
+ else analyzer.setDisplayMode(SpectrumTimeAnalyzer.DISPLAY_MODE_SPECTRUM_ANALYSER);
+ analyzer.setSpectrumAnalyserBandCount(19);
+ analyzer.setVisColor(viscolor);
+ analyzer.setLocation(visualLocation[0], visualLocation[1]);
+ analyzer.setSize(visualSize[0], visualSize[1]);
+ analyzer.setSpectrumAnalyserDecay(0.05f);
+ int fps = SpectrumTimeAnalyzer.DEFAULT_FPS;
+ analyzer.setFps(fps);
+ analyzer.setPeakDelay((int) (fps * SpectrumTimeAnalyzer.DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO));
+ analyzer.setConstraints(new AbsoluteConstraints(visualLocation[0], visualLocation[1], visualSize[0], visualSize[1]));
+ analyzer.setToolTipText(getResource("panel.analyzer"));
+ }
+ }
+
+ /**
+ * Instantiate PosBar Panel with ActiveComponent.
+ */
+ protected void setPosBarPanel()
+ {
+ int l = 0;
+ Image posBackground = new BufferedImage(248, 10, BufferedImage.TYPE_INT_RGB);
+ posBackground.getGraphics().drawImage(imPosBar, 0, 0, 248, 10, 0, 0, 248, 10, null);
+ acPosBar = new ActiveJSlider();
+ acPosBar.setMinimum(0);
+ acPosBar.setMaximum(POSBARMAX);
+ acPosBar.setValue(0);
+ acPosBar.setOrientation(JSlider.HORIZONTAL);
+ acPosBar.setConstraints(new AbsoluteConstraints(posBarLocation[l++], posBarLocation[l++], 248, releasedPosIm[0].getHeight(null)));
+ ActiveSliderUI sUI = new ActiveSliderUI(acPosBar);
+ Image[] back = { posBackground };
+ sUI.setBackgroundImages(back);
+ sUI.setThumbXOffset(0);
+ sUI.setThumbYOffset(0);
+ sUI.setThumbImage(releasedPosIm[0]);
+ sUI.setThumbPressedImage(pressedPosIm[0]);
+ acPosBar.setUI(sUI);
+ acPosBar.setToolTipText(getResource("slider.seek"));
+ }
+
+ /**
+ * Set sliders for equalizer.
+ */
+ private void setSliderPanel()
+ {
+ releasedSliderImage[0] = new BufferedImage(12, 11, BufferedImage.TYPE_INT_RGB);
+ Graphics g = releasedSliderImage[0].getGraphics();
+ g.drawImage(imFullEqualizer, 0, 0, 12, 11, 0, 164, 0 + 12, 164 + 11, null);
+ pressedSliderImage[0] = new BufferedImage(10, 11, BufferedImage.TYPE_INT_RGB);
+ g = pressedSliderImage[0].getGraphics();
+ g.drawImage(imFullEqualizer, 0, 0, 11, 11, 0, 176, 0 + 11, 176 + 11, null);
+ for (int k = 0; k < sliderImage.length / 2; k++)
+ {
+ sliderImage[k] = new BufferedImage(13, 63, BufferedImage.TYPE_INT_RGB);
+ g = sliderImage[k].getGraphics();
+ g.drawImage(imSliders, 0, 0, 13, 63, k * 15, 0, k * 15 + 13, 0 + 63, null);
+ }
+ for (int k = 0; k < sliderImage.length / 2; k++)
+ {
+ sliderImage[k + (sliderImage.length / 2)] = new BufferedImage(13, 63, BufferedImage.TYPE_INT_RGB);
+ g = sliderImage[k + (sliderImage.length / 2)].getGraphics();
+ g.drawImage(imSliders, 0, 0, 13, 63, k * 15, 65, k * 15 + 13, 65 + 63, null);
+ }
+ // Setup sliders
+ for (int i = 0; i < acSlider.length; i++)
+ {
+ sliderLocation[i][0] = sliderBarLocation[i][0] + 1;
+ sliderLocation[i][1] = sliderBarLocation[i][1] + 1;// + deltaSlider * gainEqValue[i] / maxEqGain;
+ acSlider[i] = new ActiveJSlider();
+ acSlider[i].setMinimum(0);
+ acSlider[i].setMaximum(100);
+ acSlider[i].setValue(50);
+ acSlider[i].setOrientation(JSlider.VERTICAL);
+ ActiveSliderUI sUI = new ActiveSliderUI(acSlider[i]);
+ sUI.setThumbImage(releasedSliderImage[0]);
+ sUI.setThumbPressedImage(pressedSliderImage[0]);
+ sUI.setBackgroundImages(sliderImage);
+ sUI.setThumbXOffset(1);
+ sUI.setThumbYOffset(-1);
+ acSlider[i].setUI(sUI);
+ acSlider[i].setConstraints(new AbsoluteConstraints(sliderLocation[i][0], sliderLocation[i][1], releasedSliderImage[0].getWidth(null), sliderImage[0].getHeight(null)));
+ }
+ acSlider[0].setEnabled(false);
+ }
+
+ /**
+ * Set On/Off and Auto checkbox.
+ */
+ public void setOnOffAutoPanel()
+ {
+ // On/Off
+ int w = 24, h = 12;
+ releasedOAImage[0] = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ Graphics g = releasedOAImage[0].getGraphics();
+ g.drawImage(imFullEqualizer, 0, 0, w, h, 10, 119, 10 + w, 119 + h, null);
+ pressedOAImage[0] = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ g = pressedOAImage[0].getGraphics();
+ g.drawImage(imFullEqualizer, 0, 0, w, h, 69, 119, 69 + w, 119 + h, null);
+ acOnOff = new ActiveJToggleButton();
+ acOnOff.setIcon(new ImageIcon(releasedOAImage[0]));
+ acOnOff.setSelectedIcon(new ImageIcon(pressedOAImage[0]));
+ acOnOff.setPressedIcon(new ImageIcon(pressedOAImage[0]));
+ acOnOff.setSelected(config.isEqualizerOn());
+ acOnOff.setConstraints(new AbsoluteConstraints(panelOALocation[0], panelOALocation[1], releasedOAImage[0].getWidth(null), releasedOAImage[0].getHeight(null)));
+ acOnOff.setToolTipText(getResource("equalizer.toggle.onoff"));
+ acOnOff.setActionCommand(PlayerActionEvent.ACEQONOFF);
+ // Auto
+ w = 34;
+ h = 12;
+ releasedOAImage[1] = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ g = releasedOAImage[1].getGraphics();
+ g.drawImage(imFullEqualizer, 0, 0, w, h, 34, 119, 34 + w, 119 + h, null);
+ pressedOAImage[1] = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ g = pressedOAImage[1].getGraphics();
+ g.drawImage(imFullEqualizer, 0, 0, w, h, 93, 119, 93 + w, 119 + h, null);
+ acAuto = new ActiveJToggleButton();
+ acAuto.setIcon(new ImageIcon(releasedOAImage[1]));
+ acAuto.setPressedIcon(new ImageIcon(pressedOAImage[1]));
+ acAuto.setSelectedIcon(new ImageIcon(pressedOAImage[1]));
+ acAuto.setConstraints(new AbsoluteConstraints(panelOALocation[2], panelOALocation[3], releasedOAImage[1].getWidth(null), releasedOAImage[1].getHeight(null)));
+ acAuto.setToolTipText(getResource("equalizer.toggle.auto"));
+ acAuto.setActionCommand(PlayerActionEvent.ACEQAUTO);
+ }
+
+ /**
+ * Set presets button.
+ */
+ public void setPresetsPanel()
+ {
+ int w = 44, h = 12;
+ releasedPresetsImage[0] = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ Graphics g = releasedPresetsImage[0].getGraphics();
+ g.drawImage(imFullEqualizer, 0, 0, w, h, 224, 164, 224 + w, 164 + h, null);
+ pressedPresetsImage[0] = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ g = pressedPresetsImage[0].getGraphics();
+ g.drawImage(imFullEqualizer, 0, 0, w, h, 224, 176, 224 + w, 176 + h, null);
+ acPresets = new ActiveJButton();
+ acPresets.setIcon(new ImageIcon(releasedPresetsImage[0]));
+ acPresets.setPressedIcon(new ImageIcon(pressedPresetsImage[0]));
+ acPresets.setConstraints(new AbsoluteConstraints(panelPresetsLocation[0], panelPresetsLocation[1], releasedPresetsImage[0].getWidth(null), releasedPresetsImage[0].getHeight(null)));
+ acPresets.setToolTipText(getResource("equalizer.button.presets"));
+ acPresets.setActionCommand(PlayerActionEvent.ACEQPRESETS);
+ }
+
+ /**
+ * Instantiate equalizer spline panel.
+ */
+ public void setSplinePanel()
+ {
+ int w = panelSplineLocation[2];
+ int h = panelSplineLocation[3];
+ splineImage = null;
+ splineBarImage = null;
+ spline = null;
+ if (imFullEqualizer.getHeight(null) > 294)
+ {
+ splineImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ splineBarImage = new BufferedImage(w, 1, BufferedImage.TYPE_INT_RGB);
+ splineImage.getGraphics().drawImage(imFullEqualizer, 0, 0, w, h, 0, 294, 0 + w, 294 + h, null);
+ splineBarImage.getGraphics().drawImage(imFullEqualizer, 0, 0, w, 1, 0, 294 + h + 1, 0 + w, 294 + h + 1 + 1, null);
+ spline = new SplinePanel();
+ spline.setBackgroundImage(splineImage);
+ spline.setBarImage(splineBarImage);
+ int[] pixels = new int[1 * h];
+ PixelGrabber pg = new PixelGrabber(imFullEqualizer, 115, 294, 1, h, pixels, 0, 1);
+ try
+ {
+ pg.grabPixels();
+ }
+ catch (InterruptedException e)
+ {
+ log.debug(e);
+ }
+ Color[] colors = new Color[h];
+ for (int i = 0; i < h; i++)
+ {
+ int c = pixels[i];
+ int red = (c & 0x00ff0000) >> 16;
+ int green = (c & 0x0000ff00) >> 8;
+ int blue = c & 0x000000ff;
+ colors[i] = new Color(red, green, blue);
+ }
+ spline.setGradient(colors);
+ spline.setConstraints(new AbsoluteConstraints(panelSplineLocation[0], panelSplineLocation[1], panelSplineLocation[2], panelSplineLocation[3]));
+ }
+ }
+
+ /**
+ * Instantiate playlist panel.
+ */
+ public void setPlaylistPanel()
+ {
+ playlist = new PlaylistUIDelegate();
+ Image titleCenter = new BufferedImage(100, 20, BufferedImage.TYPE_INT_RGB);
+ titleCenter.getGraphics().drawImage(imPlaylist, 0, 0, 100, 20, 26, 0, 126, 20, null);
+ playlist.setTitleCenterImage(titleCenter);
+ Image titleLeft = new BufferedImage(25, 20, BufferedImage.TYPE_INT_RGB);
+ titleLeft.getGraphics().drawImage(imPlaylist, 0, 0, 25, 20, 0, 0, 25, 20, null);
+ playlist.setTitleLeftImage(titleLeft);
+ Image titleStretch = new BufferedImage(25, 20, BufferedImage.TYPE_INT_RGB);
+ titleStretch.getGraphics().drawImage(imPlaylist, 0, 0, 25, 20, 127, 0, 152, 20, null);
+ playlist.setTitleStretchImage(titleStretch);
+ Image titleRight = new BufferedImage(25, 20, BufferedImage.TYPE_INT_RGB);
+ titleRight.getGraphics().drawImage(imPlaylist, 0, 0, 25, 20, 153, 0, 178, 20, null);
+ playlist.setTitleRightImage(titleRight);
+ Image btmLeft = new BufferedImage(125, 38, BufferedImage.TYPE_INT_RGB);
+ btmLeft.getGraphics().drawImage(imPlaylist, 0, 0, 125, 38, 0, 72, 125, 110, null);
+ playlist.setBottomLeftImage(btmLeft);
+ Image btmRight = new BufferedImage(150, 38, BufferedImage.TYPE_INT_RGB);
+ btmRight.getGraphics().drawImage(imPlaylist, 0, 0, 150, 38, 126, 72, 276, 110, null);
+ playlist.setBottomRightImage(btmRight);
+ Image bodyLeft = new BufferedImage(12, 28, BufferedImage.TYPE_INT_RGB);
+ bodyLeft.getGraphics().drawImage(imPlaylist, 0, 0, 12, 28, 0, 42, 12, 70, null);
+ playlist.setLeftImage(bodyLeft);
+ Image bodyRight = new BufferedImage(20, 28, BufferedImage.TYPE_INT_RGB);
+ bodyRight.getGraphics().drawImage(imPlaylist, 0, 0, 20, 28, 31, 42, 51, 70, null);
+ playlist.setRightImage(bodyRight);
+ // Parse color
+ plEdit = plEdit.toLowerCase();
+ ByteArrayInputStream in = new ByteArrayInputStream(plEdit.getBytes());
+ BufferedReader lin = new BufferedReader(new InputStreamReader(in));
+ try
+ {
+ for (;;)
+ {
+ String line = lin.readLine();
+ if (line == null) break;
+ if ((line.toLowerCase()).startsWith("normalbg")) playlist.setBackgroundColor(parsePlEditColor(line));
+ else if ((line.toLowerCase()).startsWith("normal")) playlist.setNormalColor(parsePlEditColor(line));
+ else if ((line.toLowerCase()).startsWith("current")) playlist.setCurrentColor(parsePlEditColor(line));
+ else if ((line.toLowerCase()).startsWith("selectedbg")) playlist.setSelectedBackgroundColor(parsePlEditColor(line));
+ }
+ }
+ catch (Exception e)
+ {
+ log.debug(e);
+ }
+ finally
+ {
+ try
+ {
+ if (in != null) in.close();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ // Playlist slider.
+ acPlSlider = new ActiveJSlider();
+ acPlSlider.setOrientation(JSlider.VERTICAL);
+ acPlSlider.setMinimum(0);
+ acPlSlider.setMaximum(100);
+ acPlSlider.setValue(100);
+ ActiveSliderUI sUI = new ActiveSliderUI(acPlSlider);
+ Image scrollBarReleased = new BufferedImage(8, 18, BufferedImage.TYPE_INT_RGB);
+ scrollBarReleased.getGraphics().drawImage(imPlaylist, 0, 0, 8, 18, 52, 53, 52 + 8, 53 + 18, null);
+ sUI.setThumbImage(scrollBarReleased);
+ Image scrollBarClicked = new BufferedImage(8, 18, BufferedImage.TYPE_INT_RGB);
+ scrollBarClicked.getGraphics().drawImage(imPlaylist, 0, 0, 8, 18, 61, 53, 61 + 8, 53 + 18, null);
+ sUI.setThumbPressedImage(scrollBarClicked);
+ Image sliderBackground = new BufferedImage(20, 58, BufferedImage.TYPE_INT_RGB);
+ sliderBackground.getGraphics().drawImage(bodyRight, 0, 0, null);
+ sliderBackground.getGraphics().drawImage(bodyRight, 0, 28, null);
+ sliderBackground.getGraphics().drawImage(bodyRight, 0, 30, null);
+ Image[] background = { sliderBackground };
+ sUI.setBackgroundImages(background);
+ sUI.setThumbXOffset(5);
+ acPlSlider.setUI(sUI);
+ acPlSlider.setConstraints(new AbsoluteConstraints(plSliderLocation[0], plSliderLocation[1], 20, 58));
+ // Up/Down scroll buttons
+ acPlUp = new ActiveJButton();
+ Image upScrollButton = new BufferedImage(8, 4, BufferedImage.TYPE_INT_RGB);
+ upScrollButton.getGraphics().drawImage(imPlaylist, 0, 0, 8, 4, 261, 75, 269, 79, null);
+ acPlUp.setIcon(new ImageIcon(upScrollButton));
+ acPlUp.setPressedIcon(new ImageIcon(upScrollButton));
+ acPlUp.setConstraints(new AbsoluteConstraints(WinWidth - 15, WinHeight - 35, 8, 4));
+ acPlUp.setActionCommand(PlayerActionEvent.ACPLUP);
+ acPlDown = new ActiveJButton();
+ Image downScrollButton = new BufferedImage(8, 4, BufferedImage.TYPE_INT_RGB);
+ downScrollButton.getGraphics().drawImage(imPlaylist, 0, 0, 8, 4, 261, 80, 269, 84, null);
+ acPlDown.setIcon(new ImageIcon(downScrollButton));
+ acPlDown.setPressedIcon(new ImageIcon(downScrollButton));
+ acPlDown.setConstraints(new AbsoluteConstraints(WinWidth - 15, WinHeight - 30, 8, 4));
+ acPlDown.setActionCommand(PlayerActionEvent.ACPLDOWN);
+ // Playlist AddFile/AddDir/AddURL buttons
+ int w = 22;
+ int h = 18;
+ Image addButtonImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ addButtonImage.getGraphics().drawImage(imPlaylist, 0, 0, w, h, 14, 80, 14 + w, 80 + h, null);
+ acPlAdd = new ActiveJButton();
+ acPlAdd.setIcon(new ImageIcon(addButtonImage));
+ acPlAdd.setPressedIcon(new ImageIcon(addButtonImage));
+ acPlAdd.setActionCommand(PlayerActionEvent.ACPLADDPOPUP);
+ acPlAdd.setConstraints(new AbsoluteConstraints(plAddLocation[0], plAddLocation[1], w, h));
+ ActiveJButton acPlAddFile = createPLButton(0, 149);
+ acPlAddFile.setActionCommand(PlayerActionEvent.ACPLADDFILE);
+ ActiveJButton acPlAddDir = createPLButton(0, 130);
+ acPlAddDir.setActionCommand(PlayerActionEvent.ACPLADDDIR);
+ ActiveJButton acPlAddURL = createPLButton(0, 111);
+ acPlAddURL.setActionCommand(PlayerActionEvent.ACPLADDURL);
+ acPlAddPopup = new ActiveJPopup();
+ ActiveJButton[] addbuttons = { acPlAddURL, acPlAddDir, acPlAddFile };
+ acPlAddPopup.setItems(addbuttons);
+ acPlAddPopup.setConstraints(new AbsoluteConstraints(plAddPopupArea[0], plAddPopupArea[1], plAddPopupArea[2], plAddPopupArea[3]));
+ // Playlist RemoveMisc/RemoveSelection/Crop/RemoveAll buttons
+ Image removeButtonImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ removeButtonImage.getGraphics().drawImage(imPlaylist, 0, 0, w, h, 14 + 30, 80, 14 + 30 + w, 80 + h, null);
+ acPlRemove = new ActiveJButton();
+ acPlRemove.setIcon(new ImageIcon(removeButtonImage));
+ acPlRemove.setPressedIcon(new ImageIcon(removeButtonImage));
+ acPlRemove.setActionCommand(PlayerActionEvent.ACPLREMOVEPOPUP);
+ acPlRemove.setConstraints(new AbsoluteConstraints(plRemoveLocation[0], plRemoveLocation[1], w, h));
+ ActiveJButton acPlRemoveMisc = createPLButton(54, 168);
+ acPlRemoveMisc.setActionCommand(PlayerActionEvent.ACPLREMOVEMISC);
+ ActiveJButton acPlRemoveSel = createPLButton(54, 149);
+ acPlRemoveSel.setActionCommand(PlayerActionEvent.ACPLREMOVESEL);
+ ActiveJButton acPlRemoveCrop = createPLButton(54, 130);
+ acPlRemoveCrop.setActionCommand(PlayerActionEvent.ACPLREMOVECROP);
+ ActiveJButton acPlRemoveAll = createPLButton(54, 111);
+ acPlRemoveAll.setActionCommand(PlayerActionEvent.ACPLREMOVEALL);
+ acPlRemovePopup = new ActiveJPopup();
+ ActiveJButton[] rembuttons = { acPlRemoveMisc, acPlRemoveAll, acPlRemoveCrop, acPlRemoveSel };
+ acPlRemovePopup.setItems(rembuttons);
+ acPlRemovePopup.setConstraints(new AbsoluteConstraints(plRemovePopupArea[0], plRemovePopupArea[1], plRemovePopupArea[2], plRemovePopupArea[3]));
+ // Playlist SelAll/SelZero/SelInv buttons
+ Image selButtonImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ selButtonImage.getGraphics().drawImage(imPlaylist, 0, 0, w, h, 14 + 60, 80, 14 + 60 + w, 80 + h, null);
+ acPlSelect = new ActiveJButton();
+ acPlSelect.setIcon(new ImageIcon(selButtonImage));
+ acPlSelect.setPressedIcon(new ImageIcon(selButtonImage));
+ acPlSelect.setActionCommand(PlayerActionEvent.ACPLSELPOPUP);
+ acPlSelect.setConstraints(new AbsoluteConstraints(plSelectLocation[0], plSelectLocation[1], w, h));
+ ActiveJButton acPlSelectAll = createPLButton(104, 149);
+ acPlSelectAll.setActionCommand(PlayerActionEvent.ACPLSELALL);
+ ActiveJButton acPlSelectZero = createPLButton(104, 130);
+ acPlSelectZero.setActionCommand(PlayerActionEvent.ACPLSELZERO);
+ ActiveJButton acPlSelectInv = createPLButton(104, 111);
+ acPlSelectInv.setActionCommand(PlayerActionEvent.ACPLSELINV);
+ acPlSelectPopup = new ActiveJPopup();
+ ActiveJButton[] selbuttons = { acPlSelectInv, acPlSelectZero, acPlSelectAll };
+ acPlSelectPopup.setItems(selbuttons);
+ acPlSelectPopup.setConstraints(new AbsoluteConstraints(plSelectPopupArea[0], plSelectPopupArea[1], plSelectPopupArea[2], plSelectPopupArea[3]));
+ // Playlist MiscOpts/MiscFile/MiscSort buttons
+ Image miscButtonImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ miscButtonImage.getGraphics().drawImage(imPlaylist, 0, 0, w, h, 14 + 89, 80, 14 + 89 + w, 80 + h, null);
+ acPlMisc = new ActiveJButton();
+ acPlMisc.setIcon(new ImageIcon(miscButtonImage));
+ acPlMisc.setPressedIcon(new ImageIcon(miscButtonImage));
+ acPlMisc.setActionCommand(PlayerActionEvent.ACPLMISCPOPUP);
+ acPlMisc.setConstraints(new AbsoluteConstraints(plMiscLocation[0], plMiscLocation[1], w, h));
+ ActiveJButton acPlMiscOpts = createPLButton(154, 149);
+ acPlMiscOpts.setActionCommand(PlayerActionEvent.ACPLMISCOPTS);
+ ActiveJButton acPlMiscFile = createPLButton(154, 130);
+ acPlMiscFile.setActionCommand(PlayerActionEvent.ACPLMISCFILE);
+ ActiveJButton acPlMiscSort = createPLButton(154, 111);
+ acPlMiscSort.setActionCommand(PlayerActionEvent.ACPLMISCSORT);
+ acPlMiscPopup = new ActiveJPopup();
+ ActiveJButton[] miscbuttons = { acPlMiscSort, acPlMiscFile, acPlMiscOpts };
+ acPlMiscPopup.setItems(miscbuttons);
+ acPlMiscPopup.setConstraints(new AbsoluteConstraints(plMiscPopupArea[0], plMiscPopupArea[1], plMiscPopupArea[2], plMiscPopupArea[3]));
+ // Playlist ListLoad/ListSave/ListNew buttons
+ Image listButtonImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ listButtonImage.getGraphics().drawImage(imPlaylist, 0, 0, w, h, 14 + 215, 80, 14 + 215 + w, 80 + h, null);
+ acPlList = new ActiveJButton();
+ acPlList.setIcon(new ImageIcon(listButtonImage));
+ acPlList.setPressedIcon(new ImageIcon(listButtonImage));
+ acPlList.setActionCommand(PlayerActionEvent.ACPLLISTPOPUP);
+ acPlList.setConstraints(new AbsoluteConstraints(plListLocation[0], plListLocation[1], w, h));
+ ActiveJButton acPlListLoad = createPLButton(204, 149);
+ acPlListLoad.setActionCommand(PlayerActionEvent.ACPLLISTLOAD);
+ ActiveJButton acPlListSave = createPLButton(204, 130);
+ acPlListSave.setActionCommand(PlayerActionEvent.ACPLLISTSAVE);
+ ActiveJButton acPlListNew = createPLButton(204, 111);
+ acPlListNew.setActionCommand(PlayerActionEvent.ACPLLISTNEW);
+ acPlListPopup = new ActiveJPopup();
+ ActiveJButton[] listbuttons = { acPlListNew, acPlListSave, acPlListLoad };
+ acPlListPopup.setItems(listbuttons);
+ acPlListPopup.setConstraints(new AbsoluteConstraints(plListPopupArea[0], plListPopupArea[1], plListPopupArea[2], plListPopupArea[3]));
+ }
+
+ /**
+ * Create Playlist buttons.
+ * @param sx
+ * @param sy
+ * @return
+ */
+ private ActiveJButton createPLButton(int sx, int sy)
+ {
+ Image normal = new BufferedImage(22, 18, BufferedImage.TYPE_INT_RGB);
+ Image clicked = new BufferedImage(22, 18, BufferedImage.TYPE_INT_RGB);
+ Graphics g = normal.getGraphics();
+ g.drawImage(imPlaylist, 0, 0, 22, 18, sx, sy, sx + 22, sy + 18, null);
+ sx += 23;
+ g = clicked.getGraphics();
+ g.drawImage(imPlaylist, 0, 0, 22, 18, sx, sy, sx + 22, sy + 18, null);
+ ActiveJButton comp = new ActiveJButton();
+ comp.setIcon(new ImageIcon(normal));
+ comp.setPressedIcon(new ImageIcon(clicked));
+ comp.setRolloverIcon(new ImageIcon(clicked));
+ comp.setRolloverEnabled(true);
+ return comp;
+ }
+
+ /**
+ * Parse playlist colors.
+ * @param line
+ * @return
+ * @throws Exception
+ */
+ private Color parsePlEditColor(String line) throws Exception
+ {
+ int pos = line.indexOf("#");
+ if (pos == -1)
+ {
+ pos = line.indexOf("=");
+ if (pos == -1) throw new Exception("Can not parse color!");
+ }
+ line = line.substring(pos + 1);
+ int r = Integer.parseInt(line.substring(0, 2), 16);
+ int g = Integer.parseInt(line.substring(2, 4), 16);
+ int b = Integer.parseInt(line.substring(4), 16);
+ return new Color(r, g, b);
+ }
+
+ /**
+ * Crop Panel Features from image file.
+ * @param releasedImage
+ * @param releasedPanel
+ * @param pressedImage
+ * @param pressedPanel
+ * @param imPanel
+ */
+ public void readPanel(Image[] releasedImage, int[] releasedPanel, Image[] pressedImage, int[] pressedPanel, Image imPanel)
+ {
+ int xul, yul, xld, yld;
+ int j = 0;
+ if (releasedImage != null)
+ {
+ for (int i = 0; i < releasedImage.length; i++)
+ {
+ releasedImage[i] = new BufferedImage(releasedPanel[j + 2], releasedPanel[j + 3], BufferedImage.TYPE_INT_RGB);
+ xul = releasedPanel[j];
+ yul = releasedPanel[j + 1];
+ xld = releasedPanel[j] + releasedPanel[j + 2];
+ yld = releasedPanel[j + 1] + releasedPanel[j + 3];
+ (releasedImage[i].getGraphics()).drawImage(imPanel, 0, 0, releasedPanel[j + 2], releasedPanel[j + 3], xul, yul, xld, yld, null);
+ j = j + 4;
+ }
+ }
+ j = 0;
+ if (pressedImage != null)
+ {
+ for (int i = 0; i < pressedImage.length; i++)
+ {
+ pressedImage[i] = new BufferedImage(pressedPanel[j + 2], pressedPanel[j + 3], BufferedImage.TYPE_INT_RGB);
+ xul = pressedPanel[j];
+ yul = pressedPanel[j + 1];
+ xld = pressedPanel[j] + pressedPanel[j + 2];
+ yld = pressedPanel[j + 1] + pressedPanel[j + 3];
+ (pressedImage[i].getGraphics()).drawImage(imPanel, 0, 0, pressedPanel[j + 2], pressedPanel[j + 3], xul, yul, xld, yld, null);
+ j = j + 4;
+ }
+ }
+ }
+
+ public ActiveJButton getAcEject()
+ {
+ return acEject;
+ }
+
+ public ActiveJButton getAcNext()
+ {
+ return acNext;
+ }
+
+ public ActiveJButton getAcPause()
+ {
+ return acPause;
+ }
+
+ public ActiveJButton getAcPlay()
+ {
+ return acPlay;
+ }
+
+ public ActiveJButton getAcPrevious()
+ {
+ return acPrevious;
+ }
+
+ public ActiveJButton getAcStop()
+ {
+ return acStop;
+ }
+
+ public ActiveJButton getAcExit()
+ {
+ return acExit;
+ }
+
+ public ActiveJButton getAcMinimize()
+ {
+ return acMinimize;
+ }
+
+ public ActiveJBar getAcTitleBar()
+ {
+ return acTitleBar;
+ }
+
+ public ActiveJLabel getAcTitleLabel()
+ {
+ return acTitleLabel;
+ }
+
+ public ActiveJLabel getAcSampleRateLabel()
+ {
+ return acSampleRateLabel;
+ }
+
+ public ActiveJLabel getAcBitRateLabel()
+ {
+ return acBitRateLabel;
+ }
+
+ public String getSkinVersion()
+ {
+ return skinVersion;
+ }
+
+ public void setSkinVersion(String skinVersion)
+ {
+ this.skinVersion = skinVersion;
+ }
+
+ public ActiveJToggleButton getAcEqualizer()
+ {
+ return acEqualizer;
+ }
+
+ public ActiveJToggleButton getAcPlaylist()
+ {
+ return acPlaylist;
+ }
+
+ public ActiveJToggleButton getAcRepeat()
+ {
+ return acRepeat;
+ }
+
+ public ActiveJToggleButton getAcShuffle()
+ {
+ return acShuffle;
+ }
+
+ public ActiveJSlider getAcVolume()
+ {
+ return acVolume;
+ }
+
+ public ActiveJSlider getAcBalance()
+ {
+ return acBalance;
+ }
+
+ public ActiveJIcon getAcMonoIcon()
+ {
+ return acMonoIcon;
+ }
+
+ public ActiveJIcon getAcStereoIcon()
+ {
+ return acStereoIcon;
+ }
+
+ public ActiveJSlider getAcPosBar()
+ {
+ return acPosBar;
+ }
+
+ public ActiveJIcon getAcPlayIcon()
+ {
+ return acPlayIcon;
+ }
+
+ public ActiveJIcon getAcTimeIcon()
+ {
+ return acTimeIcon;
+ }
+
+ public ActiveJNumberLabel getAcMinuteH()
+ {
+ return acMinuteH;
+ }
+
+ public ActiveJNumberLabel getAcMinuteL()
+ {
+ return acMinuteL;
+ }
+
+ public ActiveJNumberLabel getAcSecondH()
+ {
+ return acSecondH;
+ }
+
+ public ActiveJNumberLabel getAcSecondL()
+ {
+ return acSecondL;
+ }
+
+ public SpectrumTimeAnalyzer getAcAnalyzer()
+ {
+ return analyzer;
+ }
+
+ public ActiveJButton getAcEqPresets()
+ {
+ return acPresets;
+ }
+
+ public ActiveJToggleButton getAcEqOnOff()
+ {
+ return acOnOff;
+ }
+
+ public ActiveJToggleButton getAcEqAuto()
+ {
+ return acAuto;
+ }
+
+ public ActiveJSlider[] getAcEqSliders()
+ {
+ return acSlider;
+ }
+
+ public ActiveJSlider getAcPlSlider()
+ {
+ return acPlSlider;
+ }
+
+ public ActiveJButton getAcPlUp()
+ {
+ return acPlUp;
+ }
+
+ public ActiveJButton getAcPlDown()
+ {
+ return acPlDown;
+ }
+
+ public ActiveJButton getAcPlAdd()
+ {
+ return acPlAdd;
+ }
+
+ public ActiveJPopup getAcPlAddPopup()
+ {
+ return acPlAddPopup;
+ }
+
+ public ActiveJButton getAcPlRemove()
+ {
+ return acPlRemove;
+ }
+
+ public ActiveJPopup getAcPlRemovePopup()
+ {
+ return acPlRemovePopup;
+ }
+
+ public ActiveJButton getAcPlSelect()
+ {
+ return acPlSelect;
+ }
+
+ public ActiveJPopup getAcPlSelectPopup()
+ {
+ return acPlSelectPopup;
+ }
+
+ public ActiveJButton getAcPlMisc()
+ {
+ return acPlMisc;
+ }
+
+ public ActiveJPopup getAcPlMiscPopup()
+ {
+ return acPlMiscPopup;
+ }
+
+ public ActiveJButton getAcPlList()
+ {
+ return acPlList;
+ }
+
+ public ActiveJPopup getAcPlListPopup()
+ {
+ return acPlListPopup;
+ }
+
+ public SplinePanel getSpline()
+ {
+ return spline;
+ }
+
+ public PlaylistUIDelegate getPlaylistPanel()
+ {
+ return playlist;
+ }
+
+ /**
+ * Return readme content from skin.
+ * @return
+ */
+ public String getReadme()
+ {
+ return readme;
+ }
+
+ public int getMainWidth()
+ {
+ return WinWidth;
+ }
+
+ public int getMainHeight()
+ {
+ return WinHeight;
+ }
+
+ public Image getMainImage()
+ {
+ return imMain;
+ }
+
+ public Image getEqualizerImage()
+ {
+ return imEqualizer;
+ }
+
+ /**
+ * Return visual colors from skin.
+ * @return
+ */
+ public String getVisColors()
+ {
+ return viscolor;
+ }
+
+ public Config getConfig()
+ {
+ return config;
+ }
+
+ public void setConfig(Config config)
+ {
+ this.config = config;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/SkinLoader.java b/java/src/javazoom/jlgui/player/amp/skin/SkinLoader.java
new file mode 100644
index 0000000..6ccb3df
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/SkinLoader.java
@@ -0,0 +1,124 @@
+/*
+ * SkinLoader.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.Image;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.Hashtable;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import javazoom.jlgui.player.amp.util.BMPLoader;
+import javazoom.jlgui.player.amp.util.Config;
+
+/**
+ * This class implements a Skin Loader.
+ * WinAmp 2.x javazoom.jlgui.player.amp.skins compliant.
+ */
+public class SkinLoader
+{
+ private Hashtable _images = null;
+ private ZipInputStream _zis = null;
+
+ /**
+ * Contructs a SkinLoader from a skin file.
+ */
+ public SkinLoader(String filename)
+ {
+ _images = new Hashtable();
+ try
+ {
+ if (Config.startWithProtocol(filename)) _zis = new ZipInputStream((new URL(filename)).openStream());
+ else _zis = new ZipInputStream(new FileInputStream(filename));
+ }
+ catch (Exception e)
+ {
+ // Try to load included default skin.
+ ClassLoader cl = this.getClass().getClassLoader();
+ InputStream sis = cl.getResourceAsStream("javazoom/jlgui/player/amp/metrix.wsz");
+ if (sis != null) _zis = new ZipInputStream(sis);
+ }
+ }
+
+ /**
+ * Contructs a SkinLoader from any input stream.
+ */
+ public SkinLoader(InputStream inputstream)
+ {
+ _images = new Hashtable();
+ _zis = new ZipInputStream(inputstream);
+ }
+
+ /**
+ * Loads data (images + info) from skin.
+ */
+ public void loadImages() throws Exception
+ {
+ ZipEntry entry = _zis.getNextEntry();
+ String name;
+ BMPLoader bmp = new BMPLoader();
+ int pos;
+ while (entry != null)
+ {
+ name = entry.getName().toLowerCase();
+ pos = name.lastIndexOf("/");
+ if (pos != -1) name = name.substring(pos + 1);
+ if (name.endsWith("bmp"))
+ {
+ _images.put(name, bmp.getBMPImage(_zis));
+ }
+ else if (name.endsWith("txt"))
+ {
+ InputStreamReader reader = new InputStreamReader(_zis, "US-ASCII");
+ StringWriter writer = new StringWriter();
+ char buffer[] = new char[256];
+ int charsRead;
+ while ((charsRead = reader.read(buffer)) != -1)
+ writer.write(buffer, 0, charsRead);
+ _images.put(name, writer.toString());
+ }
+ entry = _zis.getNextEntry();
+ }
+ _zis.close();
+ }
+
+ /**
+ * Return Image from name.
+ */
+ public Image getImage(String name)
+ {
+ return (Image) _images.get(name);
+ }
+
+ // Added by John Yang - 02/05/2001
+ /**
+ * Return skin content (Image or String) from name.
+ */
+ public Object getContent(String name)
+ {
+ return _images.get(name);
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/Taftb.java b/java/src/javazoom/jlgui/player/amp/skin/Taftb.java
new file mode 100644
index 0000000..9343d27
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/Taftb.java
@@ -0,0 +1,153 @@
+/*
+ * Taftb.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.Image;
+import java.awt.image.CropImageFilter;
+import java.awt.image.FilteredImageSource;
+import java.awt.image.MemoryImageSource;
+import java.awt.image.PixelGrabber;
+import javax.swing.JComponent;
+
+/**
+ * Taftb is used to build gif image from graphical fonts.
+ */
+public class Taftb extends JComponent
+{
+ public Image theFonts;
+ private int imageW;
+ private int fontWidth;
+ private int fontHeight;
+ private int Yspacing;
+ protected Image theBanner;
+ protected int pixels[];
+ private PixelGrabber pg;
+ private String theText;
+
+ /**
+ * Text banner building according to the alphabet index, font size and Y spacing.
+ */
+ public Taftb(String alphaIndex, Image fontFile, int fontW, int fontH, int Yspc, String theTxt/*, Color BgValue*/)
+ {
+ fontWidth = fontW;
+ fontHeight = fontH;
+ Yspacing = Yspc;
+ theText = theTxt;
+ theFonts = fontFile;
+ imageW = theFonts.getWidth(this);
+ /*-- We create the TextBanner by grabbing font letters in the image fonts --*/
+ pixels = new int[theText.length() * fontW * fontH];
+ int SpacePosition = 0;
+ int offsetSp = 0;
+ /*-- We search the space position in the Alphabet index --*/
+ while ((offsetSp < alphaIndex.length()) && (alphaIndex.charAt(offsetSp) != ' '))
+ {
+ offsetSp++;
+ }
+ if (offsetSp < alphaIndex.length()) SpacePosition = offsetSp;
+ for (int offsetT = 0; offsetT < theText.length(); offsetT++)
+ {
+ int xPos = 0;
+ int yPos = 0;
+ int reste = 0;
+ int entie = 0;
+ int offsetA = 0;
+ int FontPerLine = (int) Math.rint((imageW / fontW));
+ /*-- We search the letter's position in the Alphabet index --*/
+ while ((offsetA < alphaIndex.length()) && (theText.charAt(offsetT) != alphaIndex.charAt(offsetA)))
+ {
+ offsetA++;
+ }
+ /*-- We deduce its image's position (Int forced) --*/
+ if (offsetA < alphaIndex.length())
+ {
+ reste = offsetA % FontPerLine;
+ entie = (offsetA - reste);
+ xPos = reste * fontW;
+ yPos = ((entie / FontPerLine) * fontH) + ((entie / FontPerLine) * Yspacing);
+ }
+ else
+ /*-- If the letter is not indexed the space (if available) is selected --*/
+ {
+ reste = SpacePosition % FontPerLine;
+ entie = (SpacePosition - reste);
+ xPos = reste * fontW;
+ yPos = ((entie / FontPerLine) * fontH) + ((entie / FontPerLine) * Yspacing);
+ }
+ /*-- We grab the letter in the font image and put it in a pixel array --*/
+ pg = new PixelGrabber(theFonts, xPos, yPos, fontW, fontH, pixels, offsetT * fontW, theText.length() * fontW);
+ try
+ {
+ pg.grabPixels();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+ /*-- We create the final Image Banner throught an Image --*/
+ theBanner = createImage(new MemoryImageSource(theText.length() * fontW, fontH, pixels, 0, theText.length() * fontW));
+ }
+
+ /**
+ * Returns final banner as an image.
+ */
+ public Image getBanner()
+ {
+ return theBanner;
+ }
+
+ /**
+ * Returns final banner as cropped image.
+ */
+ public Image getBanner(int x, int y, int sx, int sy)
+ {
+ Image cropBanner = null;
+ CropImageFilter cif = new CropImageFilter(x, y, sx, sy);
+ cropBanner = createImage(new FilteredImageSource(theBanner.getSource(), cif));
+ return cropBanner;
+ }
+
+ /**
+ * Returns final banner as a pixels array.
+ */
+ public int[] getPixels()
+ {
+ return pixels;
+ }
+
+ /**
+ * Returns banner's length.
+ */
+ public int getPixelsW()
+ {
+ return theText.length() * fontWidth;
+ }
+
+ /**
+ * Returns banner's height.
+ */
+ public int getPixelsH()
+ {
+ return fontHeight;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/UrlDialog.java b/java/src/javazoom/jlgui/player/amp/skin/UrlDialog.java
new file mode 100644
index 0000000..e15005e
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/UrlDialog.java
@@ -0,0 +1,148 @@
+/*
+ * UrlDialog.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+
+/**
+ * UrlDialog class implements a DialogBox to get an URL.
+ */
+public class UrlDialog extends JDialog
+{
+ private String _url = null;
+
+ /**
+ * Creates new form ud
+ */
+ public UrlDialog(JFrame parent, String title, int x, int y, String url)
+ {
+ super(parent, title, true);
+ _url = url;
+ initComponents();
+ if (_url != null) textField.setText(_url);
+ this.setLocation(x, y);
+ }
+
+ /**
+ * Returns URL.
+ */
+ public String getURL()
+ {
+ return _url;
+ }
+
+ /**
+ * Returns filename.
+ */
+ public String getFile()
+ {
+ return _url;
+ }
+
+ /**
+ * This method is called from within the constructor to
+ * initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is
+ * always regenerated by the Form Editor.
+ */
+ private void initComponents()
+ {//GEN-BEGIN:initComponents
+ java.awt.GridBagConstraints gridBagConstraints;
+ jLabel1 = new javax.swing.JLabel();
+ jLabel2 = new javax.swing.JLabel();
+ textField = new javax.swing.JTextField();
+ jPanel1 = new javax.swing.JPanel();
+ openButton = new javax.swing.JButton();
+ cancelButton = new javax.swing.JButton();
+ getContentPane().setLayout(new java.awt.GridBagLayout());
+ jLabel1.setText("Enter an Internet location to open here :");
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ getContentPane().add(jLabel1, gridBagConstraints);
+ jLabel2.setText("\"For example : http://www.server.com:8000\"");
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ getContentPane().add(jLabel2, gridBagConstraints);
+ textField.setColumns(10);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ getContentPane().add(textField, gridBagConstraints);
+ openButton.setMnemonic('O');
+ openButton.setText("Open");
+ openButton.setToolTipText("Open");
+ openButton.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(java.awt.event.ActionEvent evt)
+ {
+ openHandler(evt);
+ }
+ });
+ jPanel1.add(openButton);
+ cancelButton.setMnemonic('C');
+ cancelButton.setText("Cancel");
+ cancelButton.setToolTipText("Cancel");
+ cancelButton.addActionListener(new java.awt.event.ActionListener()
+ {
+ public void actionPerformed(java.awt.event.ActionEvent evt)
+ {
+ cancelHandler(evt);
+ }
+ });
+ jPanel1.add(cancelButton);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 3;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ getContentPane().add(jPanel1, gridBagConstraints);
+ pack();
+ }//GEN-END:initComponents
+
+ private void cancelHandler(java.awt.event.ActionEvent evt)
+ {//GEN-FIRST:event_cancelHandler
+ _url = null;
+ this.dispose();
+ }//GEN-LAST:event_cancelHandler
+
+ private void openHandler(java.awt.event.ActionEvent evt)
+ {//GEN-FIRST:event_openHandler
+ _url = textField.getText();
+ this.dispose();
+ }//GEN-LAST:event_openHandler
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JButton cancelButton;
+ private javax.swing.JLabel jLabel1;
+ private javax.swing.JLabel jLabel2;
+ private javax.swing.JPanel jPanel1;
+ private javax.swing.JButton openButton;
+ private javax.swing.JTextField textField;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/java/src/javazoom/jlgui/player/amp/skin/skin.properties b/java/src/javazoom/jlgui/player/amp/skin/skin.properties
new file mode 100644
index 0000000..a7c9235
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/skin/skin.properties
@@ -0,0 +1,65 @@
+button.previous=Previous
+button.play=Play
+button.pause=Pause
+button.stop=Stop
+button.next=Next
+button.eject=Open file(s)
+button.eject.filedialog.filtername=File, playlist or skin
+button.eject.urldialog.title=Open location
+title.loading=PLEASE WAIT ... LOADING ...
+title.buffering=PLEASE WAIT ... BUFFERING ...
+title.invalidfile=INVALID FILE
+
+button.exit=Close
+button.minimize=Minimize
+
+toggle.equalizer=Toggle Graphical Equalizer
+toggle.playlist=Toggle Playlist Editor
+toggle.shuffle=Toggle Shuffle
+toggle.repeat=Toggle Repeat
+
+slider.volume=Volume Bar
+slider.volume.text=VOLUME: {0}%
+slider.balance=Panning Bar
+slider.balance.text.right=BALANCE: {0}% RIGHT
+slider.balance.text.left=BALANCE: {0}% LEFT
+slider.balance.text.center=BALANCE: CENTER
+slider.seek=Seeking Bar
+
+panel.analyzer=Spectrum/Time analyzer
+
+popup.title=Setup
+popup.play=Play
+popup.play.file=File...
+popup.play.location=Location...
+popup.playlist=Playlist Editor
+popup.equalizer=Equalizer
+popup.preferences=Preferences
+popup.skins=Skins
+popup.skins.browser=Skin Browser
+popup.skins.load=Load Skin
+popup.playback=Playback
+popup.playback.jump=Jump to file
+popup.playback.stop=Stop
+popup.exit=Exit
+
+popup.eject.openfile=Open file...
+popup.eject.openlocation=Open location...
+
+loadskin.dialog.filtername=Skin files
+
+skin.extension=wsz
+playlist.extension.m3u=m3u
+playlist.extension.pls=pls
+
+equalizer.toggle.onoff=On/Off
+equalizer.toggle.auto=Auto
+equalizer.button.presets=Presets
+
+playlist.popup.info=File Info
+playlist.popup.play=Play Item
+playlist.popup.remove=Remove Item(s)
+playlist.popup.add.file=Music files
+playlist.popup.add.url=Open location
+playlist.popup.add.dir=Directories
+playlist.popup.list.load=PLS or M3U Playlist
diff --git a/java/src/javazoom/jlgui/player/amp/tag/APEInfo.java b/java/src/javazoom/jlgui/player/amp/tag/APEInfo.java
new file mode 100644
index 0000000..838737f
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/APEInfo.java
@@ -0,0 +1,340 @@
+/*
+ * 21.04.2004 Original verion. davagin@udm.ru.
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag;
+
+import org.tritonus.share.sampled.TAudioFormat;
+import org.tritonus.share.sampled.file.TAudioFileFormat;
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * This class gives information (audio format and comments) about APE file or URL.
+ */
+public class APEInfo implements TagInfo
+{
+ protected int channels = -1;
+ protected int bitspersample = -1;
+ protected int samplerate = -1;
+ protected int bitrate = -1;
+ protected int version = -1;
+ protected String compressionlevel = null;
+ protected int totalframes = -1;
+ protected int blocksperframe = -1;
+ protected int finalframeblocks = -1;
+ protected int totalblocks = -1;
+ protected int peaklevel = -1;
+ protected long duration = -1;
+ protected String author = null;
+ protected String title = null;
+ protected String copyright = null;
+ protected Date date = null;
+ protected String comment = null;
+ protected String track = null;
+ protected String genre = null;
+ protected String album = null;
+ protected long size = 0;
+ protected String location = null;
+
+ /**
+ * Constructor.
+ */
+ public APEInfo()
+ {
+ super();
+ }
+
+ /**
+ * Load and parse APE info from File.
+ *
+ * @param input
+ * @throws IOException
+ */
+ public void load(File input) throws IOException, UnsupportedAudioFileException
+ {
+ size = input.length();
+ location = input.getPath();
+ loadInfo(input);
+ }
+
+ /**
+ * Load and parse APE info from URL.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void load(URL input) throws IOException, UnsupportedAudioFileException
+ {
+ location = input.toString();
+ loadInfo(input);
+ }
+
+ /**
+ * Load and parse APE info from InputStream.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void load(InputStream input) throws IOException, UnsupportedAudioFileException
+ {
+ loadInfo(input);
+ }
+
+ /**
+ * Load APE info from input stream.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(InputStream input) throws IOException, UnsupportedAudioFileException
+ {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
+ loadInfo(aff);
+ }
+
+ /**
+ * Load APE info from file.
+ *
+ * @param file
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(File file) throws IOException, UnsupportedAudioFileException
+ {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(file);
+ loadInfo(aff);
+ }
+
+ /**
+ * Load APE info from AudioFileFormat.
+ *
+ * @param aff
+ */
+ protected void loadInfo(AudioFileFormat aff) throws UnsupportedAudioFileException
+ {
+ String type = aff.getType().toString();
+ if (!type.equalsIgnoreCase("Monkey's Audio (ape)") && !type.equalsIgnoreCase("Monkey's Audio (mac)")) throw new UnsupportedAudioFileException("Not APE audio format");
+ if (aff instanceof TAudioFileFormat)
+ {
+ Map props = ((TAudioFileFormat) aff).properties();
+ if (props.containsKey("duration")) duration = ((Long) props.get("duration")).longValue();
+ if (props.containsKey("author")) author = (String) props.get("author");
+ if (props.containsKey("title")) title = (String) props.get("title");
+ if (props.containsKey("copyright")) copyright = (String) props.get("copyright");
+ if (props.containsKey("date")) date = (Date) props.get("date");
+ if (props.containsKey("comment")) comment = (String) props.get("comment");
+ if (props.containsKey("album")) album = (String) props.get("album");
+ if (props.containsKey("track")) track = (String) props.get("track");
+ if (props.containsKey("genre")) genre = (String) props.get("genre");
+ AudioFormat af = aff.getFormat();
+ channels = af.getChannels();
+ samplerate = (int) af.getSampleRate();
+ bitspersample = af.getSampleSizeInBits();
+ if (af instanceof TAudioFormat)
+ {
+ props = ((TAudioFormat) af).properties();
+ if (props.containsKey("bitrate")) bitrate = ((Integer) props.get("bitrate")).intValue();
+ if (props.containsKey("ape.version")) version = ((Integer) props.get("ape.version")).intValue();
+ if (props.containsKey("ape.compressionlevel"))
+ {
+ int cl = ((Integer) props.get("ape.compressionlevel")).intValue();
+ switch (cl)
+ {
+ case 1000:
+ compressionlevel = "Fast";
+ break;
+ case 2000:
+ compressionlevel = "Normal";
+ break;
+ case 3000:
+ compressionlevel = "High";
+ break;
+ case 4000:
+ compressionlevel = "Extra High";
+ break;
+ case 5000:
+ compressionlevel = "Insane";
+ break;
+ }
+ }
+ if (props.containsKey("ape.totalframes")) totalframes = ((Integer) props.get("ape.totalframes")).intValue();
+ if (props.containsKey("ape.blocksperframe")) totalframes = ((Integer) props.get("ape.blocksperframe")).intValue();
+ if (props.containsKey("ape.finalframeblocks")) finalframeblocks = ((Integer) props.get("ape.finalframeblocks")).intValue();
+ if (props.containsKey("ape.totalblocks")) totalblocks = ((Integer) props.get("ape.totalblocks")).intValue();
+ if (props.containsKey("ape.peaklevel")) peaklevel = ((Integer) props.get("ape.peaklevel")).intValue();
+ }
+ }
+ }
+
+ /**
+ * Load APE info from URL.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(URL input) throws IOException, UnsupportedAudioFileException
+ {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
+ loadInfo(aff);
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getLocation()
+ {
+ return location;
+ }
+
+ public int getVersion()
+ {
+ return version;
+ }
+
+ public String getCompressionlevel()
+ {
+ return compressionlevel;
+ }
+
+ public int getTotalframes()
+ {
+ return totalframes;
+ }
+
+ public int getBlocksperframe()
+ {
+ return blocksperframe;
+ }
+
+ public int getFinalframeblocks()
+ {
+ return finalframeblocks;
+ }
+
+ public int getChannels()
+ {
+ return channels;
+ }
+
+ public int getSamplingRate()
+ {
+ return samplerate;
+ }
+
+ public int getBitsPerSample()
+ {
+ return bitspersample;
+ }
+
+ public int getTotalblocks()
+ {
+ return totalblocks;
+ }
+
+ public long getPlayTime()
+ {
+ return duration / 1000;
+ }
+
+ public int getBitRate()
+ {
+ return bitrate * 1000;
+ }
+
+ public int getPeaklevel()
+ {
+ return peaklevel;
+ }
+
+ public int getTrack()
+ {
+ int t;
+ try
+ {
+ t = Integer.parseInt(track);
+ }
+ catch (Exception e)
+ {
+ t = -1;
+ }
+ return t;
+ }
+
+ public String getYear()
+ {
+ if (date != null)
+ {
+ Calendar c = Calendar.getInstance();
+ c.setTime(date);
+ return String.valueOf(c.get(Calendar.YEAR));
+ }
+ return null;
+ }
+
+ public String getGenre()
+ {
+ return genre;
+ }
+
+ public String getTitle()
+ {
+ return title;
+ }
+
+ public String getArtist()
+ {
+ return author;
+ }
+
+ public String getAlbum()
+ {
+ return album;
+ }
+
+ public Vector getComment()
+ {
+ if (comment != null)
+ {
+ Vector c = new Vector();
+ c.add(comment);
+ return c;
+ }
+ return null;
+ }
+
+ public String getCopyright()
+ {
+ return copyright;
+ }
+}
\ No newline at end of file
diff --git a/java/src/javazoom/jlgui/player/amp/tag/FlacInfo.java b/java/src/javazoom/jlgui/player/amp/tag/FlacInfo.java
new file mode 100644
index 0000000..70d1712
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/FlacInfo.java
@@ -0,0 +1,189 @@
+/*
+ * 21.04.2004 Original verion. davagin@udm.ru.
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Vector;
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+/**
+ * This class gives information (audio format and comments) about Flac file or URL.
+ */
+public class FlacInfo implements TagInfo {
+ protected int channels = -1;
+ protected int bitspersample = -1;
+ protected int samplerate = -1;
+ protected long size = 0;
+ protected String location = null;
+
+ /**
+ * Constructor.
+ */
+ public FlacInfo() {
+ super();
+ }
+
+ /**
+ * Load and parse Flac info from File.
+ *
+ * @param input
+ * @throws IOException
+ */
+ public void load(File input) throws IOException, UnsupportedAudioFileException {
+ size = input.length();
+ location = input.getPath();
+ loadInfo(input);
+ }
+
+ /**
+ * Load and parse Flac info from URL.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void load(URL input) throws IOException, UnsupportedAudioFileException {
+ location = input.toString();
+ loadInfo(input);
+ }
+
+ /**
+ * Load and parse Flac info from InputStream.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void load(InputStream input) throws IOException, UnsupportedAudioFileException {
+ loadInfo(input);
+ }
+
+ /**
+ * Load Flac info from input stream.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(InputStream input) throws IOException, UnsupportedAudioFileException {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
+ loadInfo(aff);
+ }
+
+ /**
+ * Load Flac info from file.
+ *
+ * @param file
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(File file) throws IOException, UnsupportedAudioFileException {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(file);
+ loadInfo(aff);
+ }
+
+ /**
+ * Load Flac info from AudioFileFormat.
+ *
+ * @param aff
+ */
+ protected void loadInfo(AudioFileFormat aff) throws UnsupportedAudioFileException {
+ String type = aff.getType().toString();
+ if (!type.equalsIgnoreCase("flac")) throw new UnsupportedAudioFileException("Not Flac audio format");
+ AudioFormat af = aff.getFormat();
+ channels = af.getChannels();
+ samplerate = (int) af.getSampleRate();
+ bitspersample = af.getSampleSizeInBits();
+ }
+
+ /**
+ * Load Flac info from URL.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(URL input) throws IOException, UnsupportedAudioFileException {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
+ loadInfo(aff);
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ public int getChannels() {
+ return channels;
+ }
+
+ public int getSamplingRate() {
+ return samplerate;
+ }
+
+ public int getBitsPerSample() {
+ return bitspersample;
+ }
+
+ public Vector getComment() {
+ return null;
+ }
+
+ public String getYear() {
+ return null;
+ }
+
+ public String getGenre() {
+ return null;
+ }
+
+ public int getTrack() {
+ return -1;
+ }
+
+ public String getAlbum() {
+ return null;
+ }
+
+ public String getArtist() {
+ return null;
+ }
+
+ public String getTitle() {
+ return null;
+ }
+
+ public long getPlayTime() {
+ return -1;
+ }
+
+ public int getBitRate() {
+ return -1;
+ }
+
+}
\ No newline at end of file
diff --git a/java/src/javazoom/jlgui/player/amp/tag/MpegInfo.java b/java/src/javazoom/jlgui/player/amp/tag/MpegInfo.java
new file mode 100644
index 0000000..18ee050
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/MpegInfo.java
@@ -0,0 +1,315 @@
+/*
+ * MpegInfo.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag;
+
+import org.tritonus.share.sampled.file.TAudioFileFormat;
+
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * This class gives information (audio format and comments) about MPEG file or URL.
+ */
+public class MpegInfo implements TagInfo {
+ protected int channels = -1;
+ protected String channelsMode = null;
+ protected String version = null;
+ protected int rate = 0;
+ protected String layer = null;
+ protected String emphasis = null;
+ protected int nominalbitrate = 0;
+ protected long total = 0;
+ protected String vendor = null;
+ protected String location = null;
+ protected long size = 0;
+ protected boolean copyright = false;
+ protected boolean crc = false;
+ protected boolean original = false;
+ protected boolean priv = false;
+ protected boolean vbr = false;
+ protected int track = -1;
+ protected String year = null;
+ protected String genre = null;
+ protected String title = null;
+ protected String artist = null;
+ protected String album = null;
+ protected Vector comments = null;
+
+ /**
+ * Constructor.
+ */
+ public MpegInfo() {
+ super();
+ }
+
+ /**
+ * Load and parse MPEG info from File.
+ *
+ * @param input
+ * @throws IOException
+ */
+ public void load(File input) throws IOException, UnsupportedAudioFileException {
+ size = input.length();
+ location = input.getPath();
+ loadInfo(input);
+ }
+
+ /**
+ * Load and parse MPEG info from URL.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void load(URL input) throws IOException, UnsupportedAudioFileException {
+ location = input.toString();
+ loadInfo(input);
+ }
+
+ /**
+ * Load and parse MPEG info from InputStream.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void load(InputStream input) throws IOException, UnsupportedAudioFileException {
+ loadInfo(input);
+ }
+
+ /**
+ * Load info from input stream.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(InputStream input) throws IOException, UnsupportedAudioFileException {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
+ loadInfo(aff);
+ }
+
+ /**
+ * Load MP3 info from file.
+ *
+ * @param file
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(File file) throws IOException, UnsupportedAudioFileException {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(file);
+ loadInfo(aff);
+ }
+
+ /**
+ * Load info from AudioFileFormat.
+ *
+ * @param aff
+ */
+ protected void loadInfo(AudioFileFormat aff) throws UnsupportedAudioFileException {
+ String type = aff.getType().toString();
+ if (!type.equalsIgnoreCase("mp3")) throw new UnsupportedAudioFileException("Not MP3 audio format");
+ if (aff instanceof TAudioFileFormat) {
+ Map props = ((TAudioFileFormat) aff).properties();
+ if (props.containsKey("mp3.channels")) channels = ((Integer) props.get("mp3.channels")).intValue();
+ if (props.containsKey("mp3.frequency.hz")) rate = ((Integer) props.get("mp3.frequency.hz")).intValue();
+ if (props.containsKey("mp3.bitrate.nominal.bps")) nominalbitrate = ((Integer) props.get("mp3.bitrate.nominal.bps")).intValue();
+ if (props.containsKey("mp3.version.layer")) layer = "Layer " + props.get("mp3.version.layer");
+ if (props.containsKey("mp3.version.mpeg")) {
+ version = (String) props.get("mp3.version.mpeg");
+ if (version.equals("1")) version = "MPEG1";
+ else if (version.equals("2")) version = "MPEG2-LSF";
+ else if (version.equals("2.5")) version = "MPEG2.5-LSF";
+ }
+ if (props.containsKey("mp3.mode")) {
+ int mode = ((Integer) props.get("mp3.mode")).intValue();
+ if (mode == 0) channelsMode = "Stereo";
+ else if (mode == 1) channelsMode = "Joint Stereo";
+ else if (mode == 2) channelsMode = "Dual Channel";
+ else if (mode == 3) channelsMode = "Single Channel";
+ }
+ if (props.containsKey("mp3.crc")) crc = ((Boolean) props.get("mp3.crc")).booleanValue();
+ if (props.containsKey("mp3.vbr")) vbr = ((Boolean) props.get("mp3.vbr")).booleanValue();
+ if (props.containsKey("mp3.copyright")) copyright = ((Boolean) props.get("mp3.copyright")).booleanValue();
+ if (props.containsKey("mp3.original")) original = ((Boolean) props.get("mp3.original")).booleanValue();
+ emphasis = "none";
+ if (props.containsKey("title")) title = (String) props.get("title");
+ if (props.containsKey("author")) artist = (String) props.get("author");
+ if (props.containsKey("album")) album = (String) props.get("album");
+ if (props.containsKey("date")) year = (String) props.get("date");
+ if (props.containsKey("duration")) total = (long) Math.round((((Long) props.get("duration")).longValue()) / 1000000);
+ if (props.containsKey("mp3.id3tag.genre")) genre = (String) props.get("mp3.id3tag.genre");
+ if (props.containsKey("mp3.id3tag.track")) {
+ try {
+ track = Integer.parseInt((String) props.get("mp3.id3tag.track"));
+ }
+ catch (NumberFormatException e1) {
+ // Not a number
+ }
+ }
+ }
+ }
+
+ /**
+ * Load MP3 info from URL.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(URL input) throws IOException, UnsupportedAudioFileException {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
+ loadInfo(aff);
+ loadShoutastInfo(aff);
+ }
+
+ /**
+ * Load Shoutcast info from AudioFileFormat.
+ *
+ * @param aff
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadShoutastInfo(AudioFileFormat aff) throws IOException, UnsupportedAudioFileException {
+ String type = aff.getType().toString();
+ if (!type.equalsIgnoreCase("mp3")) throw new UnsupportedAudioFileException("Not MP3 audio format");
+ if (aff instanceof TAudioFileFormat) {
+ Map props = ((TAudioFileFormat) aff).properties();
+ // Try shoutcast meta data (if any).
+ Iterator it = props.keySet().iterator();
+ comments = new Vector();
+ while (it.hasNext()) {
+ String key = (String) it.next();
+ if (key.startsWith("mp3.shoutcast.metadata.")) {
+ String value = (String) props.get(key);
+ key = key.substring(23, key.length());
+ if (key.equalsIgnoreCase("icy-name")) {
+ title = value;
+ } else if (key.equalsIgnoreCase("icy-genre")) {
+ genre = value;
+ } else {
+ comments.add(key + "=" + value);
+ }
+ }
+ }
+ }
+ }
+
+ public boolean getVBR() {
+ return vbr;
+ }
+
+ public int getChannels() {
+ return channels;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public String getEmphasis() {
+ return emphasis;
+ }
+
+ public boolean getCopyright() {
+ return copyright;
+ }
+
+ public boolean getCRC() {
+ return crc;
+ }
+
+ public boolean getOriginal() {
+ return original;
+ }
+
+ public String getLayer() {
+ return layer;
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ /*-- TagInfo Implementation --*/
+ public int getSamplingRate() {
+ return rate;
+ }
+
+ public int getBitRate() {
+ return nominalbitrate;
+ }
+
+ public long getPlayTime() {
+ return total;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getArtist() {
+ return artist;
+ }
+
+ public String getAlbum() {
+ return album;
+ }
+
+ public int getTrack() {
+ return track;
+ }
+
+ public String getGenre() {
+ return genre;
+ }
+
+ public Vector getComment() {
+ return comments;
+ }
+
+ public String getYear() {
+ return year;
+ }
+
+ /**
+ * Get channels mode.
+ *
+ * @return channels mode
+ */
+ public String getChannelsMode() {
+ return channelsMode;
+ }
+}
\ No newline at end of file
diff --git a/java/src/javazoom/jlgui/player/amp/tag/OggVorbisInfo.java b/java/src/javazoom/jlgui/player/amp/tag/OggVorbisInfo.java
new file mode 100644
index 0000000..8ea28cd
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/OggVorbisInfo.java
@@ -0,0 +1,307 @@
+/*
+ * OggVorbisInfo.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag;
+
+import org.tritonus.share.sampled.file.TAudioFileFormat;
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * This class gives information (audio format and comments) about Ogg Vorbis file or URL.
+ */
+public class OggVorbisInfo implements TagInfo
+{
+ protected int serial = 0;
+ protected int channels = 0;
+ protected int version = 0;
+ protected int rate = 0;
+ protected int minbitrate = 0;
+ protected int maxbitrate = 0;
+ protected int averagebitrate = 0;
+ protected int nominalbitrate = 0;
+ protected long totalms = 0;
+ protected String vendor = "";
+ protected String location = null;
+ protected long size = 0;
+ protected int track = -1;
+ protected String year = null;
+ protected String genre = null;
+ protected String title = null;
+ protected String artist = null;
+ protected String album = null;
+ protected Vector comments = new Vector();
+
+ /**
+ * Constructor.
+ */
+ public OggVorbisInfo()
+ {
+ super();
+ }
+
+ /**
+ * Load and parse Ogg Vorbis info from File.
+ *
+ * @param input
+ * @throws IOException
+ */
+ public void load(File input) throws IOException, UnsupportedAudioFileException
+ {
+ size = input.length();
+ location = input.getPath();
+ loadInfo(input);
+ }
+
+ /**
+ * Load and parse Ogg Vorbis info from URL.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void load(URL input) throws IOException, UnsupportedAudioFileException
+ {
+ location = input.toString();
+ loadInfo(input);
+ }
+
+ /**
+ * Load and parse Ogg Vorbis info from InputStream.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ public void load(InputStream input) throws IOException, UnsupportedAudioFileException
+ {
+ loadInfo(input);
+ }
+
+ /**
+ * Load info from input stream.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(InputStream input) throws IOException, UnsupportedAudioFileException
+ {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
+ loadInfo(aff);
+ }
+
+ /**
+ * Load Ogg Vorbis info from file.
+ *
+ * @param file
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(File file) throws IOException, UnsupportedAudioFileException
+ {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(file);
+ loadInfo(aff);
+ }
+
+ /**
+ * Load Ogg Vorbis info from URL.
+ *
+ * @param input
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(URL input) throws IOException, UnsupportedAudioFileException
+ {
+ AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
+ loadInfo(aff);
+ loadExtendedInfo(aff);
+ }
+
+ /**
+ * Load info from AudioFileFormat.
+ *
+ * @param aff
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadInfo(AudioFileFormat aff) throws UnsupportedAudioFileException
+ {
+ String type = aff.getType().toString();
+ if (!type.equalsIgnoreCase("ogg")) throw new UnsupportedAudioFileException("Not Ogg Vorbis audio format");
+ if (aff instanceof TAudioFileFormat)
+ {
+ Map props = ((TAudioFileFormat) aff).properties();
+ if (props.containsKey("ogg.channels")) channels = ((Integer) props.get("ogg.channels")).intValue();
+ if (props.containsKey("ogg.frequency.hz")) rate = ((Integer) props.get("ogg.frequency.hz")).intValue();
+ if (props.containsKey("ogg.bitrate.nominal.bps")) nominalbitrate = ((Integer) props.get("ogg.bitrate.nominal.bps")).intValue();
+ averagebitrate = nominalbitrate;
+ if (props.containsKey("ogg.bitrate.max.bps")) maxbitrate = ((Integer) props.get("ogg.bitrate.max.bps")).intValue();
+ if (props.containsKey("ogg.bitrate.min.bps")) minbitrate = ((Integer) props.get("ogg.bitrate.min.bps")).intValue();
+ if (props.containsKey("ogg.version")) version = ((Integer) props.get("ogg.version")).intValue();
+ if (props.containsKey("ogg.serial")) serial = ((Integer) props.get("ogg.serial")).intValue();
+ if (props.containsKey("ogg.comment.encodedby")) vendor = (String) props.get("ogg.comment.encodedby");
+ if (props.containsKey("copyright")) comments.add((String) props.get("copyright"));
+ if (props.containsKey("title")) title = (String) props.get("title");
+ if (props.containsKey("author")) artist = (String) props.get("author");
+ if (props.containsKey("album")) album = (String) props.get("album");
+ if (props.containsKey("date")) year = (String) props.get("date");
+ if (props.containsKey("comment")) comments.add((String) props.get("comment"));
+ if (props.containsKey("duration")) totalms = (long) Math.round((((Long) props.get("duration")).longValue()) / 1000000);
+ if (props.containsKey("ogg.comment.genre")) genre = (String) props.get("ogg.comment.genre");
+ if (props.containsKey("ogg.comment.track"))
+ {
+ try
+ {
+ track = Integer.parseInt((String) props.get("ogg.comment.track"));
+ }
+ catch (NumberFormatException e1)
+ {
+ // Not a number
+ }
+ }
+ if (props.containsKey("ogg.comment.ext.1")) comments.add((String) props.get("ogg.comment.ext.1"));
+ if (props.containsKey("ogg.comment.ext.2")) comments.add((String) props.get("ogg.comment.ext.2"));
+ if (props.containsKey("ogg.comment.ext.3")) comments.add((String) props.get("ogg.comment.ext.3"));
+ }
+ }
+
+ /**
+ * Load extended info from AudioFileFormat.
+ *
+ * @param aff
+ * @throws IOException
+ * @throws UnsupportedAudioFileException
+ */
+ protected void loadExtendedInfo(AudioFileFormat aff) throws IOException, UnsupportedAudioFileException
+ {
+ String type = aff.getType().toString();
+ if (!type.equalsIgnoreCase("ogg")) throw new UnsupportedAudioFileException("Not Ogg Vorbis audio format");
+ if (aff instanceof TAudioFileFormat)
+ {
+ //Map props = ((TAudioFileFormat) aff).properties();
+ // How to load icecast meta data (if any) ??
+ }
+ }
+
+ public int getSerial()
+ {
+ return serial;
+ }
+
+ public int getChannels()
+ {
+ return channels;
+ }
+
+ public int getVersion()
+ {
+ return version;
+ }
+
+ public int getMinBitrate()
+ {
+ return minbitrate;
+ }
+
+ public int getMaxBitrate()
+ {
+ return maxbitrate;
+ }
+
+ public int getAverageBitrate()
+ {
+ return averagebitrate;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getVendor()
+ {
+ return vendor;
+ }
+
+ public String getLocation()
+ {
+ return location;
+ }
+
+ /*-- TagInfo Implementation --*/
+ public int getSamplingRate()
+ {
+ return rate;
+ }
+
+ public int getBitRate()
+ {
+ return nominalbitrate;
+ }
+
+ public long getPlayTime()
+ {
+ return totalms;
+ }
+
+ public String getTitle()
+ {
+ return title;
+ }
+
+ public String getArtist()
+ {
+ return artist;
+ }
+
+ public String getAlbum()
+ {
+ return album;
+ }
+
+ public int getTrack()
+ {
+ return track;
+ }
+
+ public String getGenre()
+ {
+ return genre;
+ }
+
+ public Vector getComment()
+ {
+ return comments;
+ }
+
+ public String getYear()
+ {
+ return year;
+ }
+}
\ No newline at end of file
diff --git a/java/src/javazoom/jlgui/player/amp/tag/TagInfo.java b/java/src/javazoom/jlgui/player/amp/tag/TagInfo.java
new file mode 100644
index 0000000..86e05d5
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/TagInfo.java
@@ -0,0 +1,120 @@
+/*
+ * TagInfo.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Vector;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+/**
+ * This interface define needed features for song information.
+ * Adapted from Scott Pennell interface.
+ */
+public interface TagInfo
+{
+ public void load(InputStream input) throws IOException, UnsupportedAudioFileException;
+
+ public void load(URL input) throws IOException, UnsupportedAudioFileException;
+
+ public void load(File input) throws IOException, UnsupportedAudioFileException;
+
+ /**
+ * Get Sampling Rate
+ *
+ * @return sampling rate
+ */
+ public int getSamplingRate();
+
+ /**
+ * Get Nominal Bitrate
+ *
+ * @return bitrate in bps
+ */
+ public int getBitRate();
+
+ /**
+ * Get channels.
+ *
+ * @return channels
+ */
+ public int getChannels();
+
+ /**
+ * Get play time in seconds.
+ *
+ * @return play time in seconds
+ */
+ public long getPlayTime();
+
+ /**
+ * Get the title of the song.
+ *
+ * @return the title of the song
+ */
+ public String getTitle();
+
+ /**
+ * Get the artist that performed the song
+ *
+ * @return the artist that performed the song
+ */
+ public String getArtist();
+
+ /**
+ * Get the name of the album upon which the song resides
+ *
+ * @return the album name
+ */
+ public String getAlbum();
+
+ /**
+ * Get the track number of this track on the album
+ *
+ * @return the track number
+ */
+ public int getTrack();
+
+ /**
+ * Get the genre string of the music
+ *
+ * @return the genre string
+ */
+ public String getGenre();
+
+ /**
+ * Get the year the track was released
+ *
+ * @return the year the track was released
+ */
+ public String getYear();
+
+ /**
+ * Get any comments provided about the song
+ *
+ * @return the comments
+ */
+ public Vector getComment();
+}
\ No newline at end of file
diff --git a/java/src/javazoom/jlgui/player/amp/tag/TagInfoFactory.java b/java/src/javazoom/jlgui/player/amp/tag/TagInfoFactory.java
new file mode 100644
index 0000000..13281f1
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/TagInfoFactory.java
@@ -0,0 +1,399 @@
+/*
+ * TagInfoFactory.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import javazoom.jlgui.player.amp.tag.ui.APEDialog;
+import javazoom.jlgui.player.amp.tag.ui.EmptyDialog;
+import javazoom.jlgui.player.amp.tag.ui.FlacDialog;
+import javazoom.jlgui.player.amp.tag.ui.MpegDialog;
+import javazoom.jlgui.player.amp.tag.ui.OggVorbisDialog;
+import javazoom.jlgui.player.amp.tag.ui.TagInfoDialog;
+import javazoom.jlgui.player.amp.util.Config;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class is a factory for TagInfo and TagInfoDialog.
+ * It allows to any plug custom TagIngfo parser matching to TagInfo
+ * interface.
+ */
+public class TagInfoFactory
+{
+ private static Log log = LogFactory.getLog(TagInfoFactory.class);
+ private static TagInfoFactory instance = null;
+ private Class MpegTagInfoClass = null;
+ private Class VorbisTagInfoClass = null;
+ private Class APETagInfoClass = null;
+ private Class FlacTagInfoClass = null;
+ private Config conf = null;
+
+ private TagInfoFactory()
+ {
+ super();
+ conf = Config.getInstance();
+ String classname = conf.getMpegTagInfoClassName();
+ MpegTagInfoClass = getTagInfoImpl(classname);
+ if (MpegTagInfoClass == null)
+ {
+ log.error("Error : TagInfo implementation not found in " + classname + " hierarchy");
+ MpegTagInfoClass = getTagInfoImpl("javazoom.jlgui.player.amp.tag.MpegInfo");
+ }
+ classname = conf.getOggVorbisTagInfoClassName();
+ VorbisTagInfoClass = getTagInfoImpl(classname);
+ if (VorbisTagInfoClass == null)
+ {
+ log.error("Error : TagInfo implementation not found in " + classname + " hierarchy");
+ VorbisTagInfoClass = getTagInfoImpl("javazoom.jlgui.player.amp.tag.OggVorbisInfo");
+ }
+ classname = conf.getAPETagInfoClassName();
+ APETagInfoClass = getTagInfoImpl(classname);
+ if (APETagInfoClass == null)
+ {
+ log.error("Error : TagInfo implementation not found in " + classname + " hierarchy");
+ APETagInfoClass = getTagInfoImpl("javazoom.jlgui.player.amp.tag.APEInfo");
+ }
+ classname = conf.getFlacTagInfoClassName();
+ FlacTagInfoClass = getTagInfoImpl(classname);
+ if (FlacTagInfoClass == null)
+ {
+ log.error("Error : TagInfo implementation not found in " + classname + " hierarchy");
+ FlacTagInfoClass = getTagInfoImpl("javazoom.jlgui.player.amp.tag.FlacInfo");
+ }
+ }
+
+ public static synchronized TagInfoFactory getInstance()
+ {
+ if (instance == null)
+ {
+ instance = new TagInfoFactory();
+ }
+ return instance;
+ }
+
+ /**
+ * Return tag info from a given URL.
+ *
+ * @param location
+ * @return TagInfo structure for given URL
+ */
+ public TagInfo getTagInfo(URL location)
+ {
+ TagInfo taginfo;
+ try
+ {
+ taginfo = getTagInfoImplInstance(MpegTagInfoClass);
+ taginfo.load(location);
+ }
+ catch (IOException ex)
+ {
+ log.debug(ex);
+ taginfo = null;
+ }
+ catch (UnsupportedAudioFileException ex)
+ {
+ // Not Mpeg Format
+ taginfo = null;
+ }
+ if (taginfo == null)
+ {
+ // Check Ogg Vorbis format.
+ try
+ {
+ taginfo = getTagInfoImplInstance(VorbisTagInfoClass);
+ taginfo.load(location);
+ }
+ catch (UnsupportedAudioFileException ex)
+ {
+ // Not Ogg Vorbis Format
+ taginfo = null;
+ }
+ catch (IOException ex)
+ {
+ log.debug(ex);
+ taginfo = null;
+ }
+ }
+ if (taginfo == null)
+ {
+ // Check APE format.
+ try
+ {
+ taginfo = getTagInfoImplInstance(APETagInfoClass);
+ taginfo.load(location);
+ }
+ catch (UnsupportedAudioFileException ex)
+ {
+ // Not APE Format
+ taginfo = null;
+ }
+ catch (IOException ex)
+ {
+ log.debug(ex);
+ taginfo = null;
+ }
+ }
+ if (taginfo == null)
+ {
+ // Check Flac format.
+ try
+ {
+ taginfo = getTagInfoImplInstance(FlacTagInfoClass);
+ taginfo.load(location);
+ }
+ catch (UnsupportedAudioFileException ex)
+ {
+ // Not Flac Format
+ taginfo = null;
+ }
+ catch (IOException ex)
+ {
+ log.debug(ex);
+ taginfo = null;
+ }
+ }
+ return taginfo;
+ }
+
+ /**
+ * Return tag info from a given String.
+ *
+ * @param location
+ * @return TagInfo structure for given location
+ */
+ public TagInfo getTagInfo(String location)
+ {
+ if (Config.startWithProtocol(location))
+ {
+ try
+ {
+ return getTagInfo(new URL(location));
+ }
+ catch (MalformedURLException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return getTagInfo(new File(location));
+ }
+ }
+
+ /**
+ * Get TagInfo for given file.
+ *
+ * @param location
+ * @return TagInfo structure for given location
+ */
+ public TagInfo getTagInfo(File location)
+ {
+ TagInfo taginfo;
+ // Check Mpeg format.
+ try
+ {
+ taginfo = getTagInfoImplInstance(MpegTagInfoClass);
+ taginfo.load(location);
+ }
+ catch (IOException ex)
+ {
+ log.debug(ex);
+ taginfo = null;
+ }
+ catch (UnsupportedAudioFileException ex)
+ {
+ // Not Mpeg Format
+ taginfo = null;
+ }
+ if (taginfo == null)
+ {
+ // Check Ogg Vorbis format.
+ try
+ {
+ //taginfo = new OggVorbisInfo(location);
+ taginfo = getTagInfoImplInstance(VorbisTagInfoClass);
+ taginfo.load(location);
+ }
+ catch (UnsupportedAudioFileException ex)
+ {
+ // Not Ogg Vorbis Format
+ taginfo = null;
+ }
+ catch (IOException ex)
+ {
+ log.debug(ex);
+ taginfo = null;
+ }
+ }
+ if (taginfo == null)
+ {
+ // Check APE format.
+ try
+ {
+ taginfo = getTagInfoImplInstance(APETagInfoClass);
+ taginfo.load(location);
+ }
+ catch (UnsupportedAudioFileException ex)
+ {
+ // Not APE Format
+ taginfo = null;
+ }
+ catch (IOException ex)
+ {
+ log.debug(ex);
+ taginfo = null;
+ }
+ }
+ if (taginfo == null)
+ {
+ // Check Flac format.
+ try
+ {
+ taginfo = getTagInfoImplInstance(FlacTagInfoClass);
+ taginfo.load(location);
+ }
+ catch (UnsupportedAudioFileException ex)
+ {
+ // Not Flac Format
+ taginfo = null;
+ }
+ catch (IOException ex)
+ {
+ log.debug(ex);
+ taginfo = null;
+ }
+ }
+ return taginfo;
+ }
+
+ /**
+ * Return dialog (graphical) to display tag info.
+ *
+ * @param taginfo
+ * @return TagInfoDialog for given TagInfo
+ */
+ public TagInfoDialog getTagInfoDialog(TagInfo taginfo)
+ {
+ TagInfoDialog dialog;
+ if (taginfo != null)
+ {
+ if (taginfo instanceof OggVorbisInfo)
+ {
+ dialog = new OggVorbisDialog(conf.getTopParent(), "OggVorbis info", (OggVorbisInfo) taginfo);
+ }
+ else if (taginfo instanceof MpegInfo)
+ {
+ dialog = new MpegDialog(conf.getTopParent(), "Mpeg info", (MpegInfo) taginfo);
+ }
+ else if (taginfo instanceof APEInfo)
+ {
+ dialog = new APEDialog(conf.getTopParent(), "Ape info", (APEInfo) taginfo);
+ }
+ else if (taginfo instanceof FlacInfo)
+ {
+ dialog = new FlacDialog(conf.getTopParent(), "Flac info", (FlacInfo) taginfo);
+ }
+ else
+ {
+ dialog = new EmptyDialog(conf.getTopParent(), "No info", taginfo);
+ }
+ }
+ else
+ {
+ dialog = new EmptyDialog(conf.getTopParent(), "No info", null);
+ }
+ return dialog;
+ }
+
+ /**
+ * Load and check class implementation from classname.
+ *
+ * @param classname
+ * @return TagInfo implementation for given class name
+ */
+ public Class getTagInfoImpl(String classname)
+ {
+ Class aClass = null;
+ boolean interfaceFound = false;
+ if (classname != null)
+ {
+ try
+ {
+ aClass = Class.forName(classname);
+ Class superClass = aClass;
+ // Looking for TagInfo interface implementation.
+ while (superClass != null)
+ {
+ Class[] interfaces = superClass.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++)
+ {
+ if ((interfaces[i].getName()).equals("javazoom.jlgui.player.amp.tag.TagInfo"))
+ {
+ interfaceFound = true;
+ break;
+ }
+ }
+ if (interfaceFound) break;
+ superClass = superClass.getSuperclass();
+ }
+ if (interfaceFound) log.info(classname + " loaded");
+ else log.info(classname + " not loaded");
+ }
+ catch (ClassNotFoundException e)
+ {
+ log.error("Error : " + classname + " : " + e.getMessage());
+ }
+ }
+ return aClass;
+ }
+
+ /**
+ * Return new instance of given class.
+ *
+ * @param aClass
+ * @return TagInfo for given class
+ */
+ public TagInfo getTagInfoImplInstance(Class aClass)
+ {
+ TagInfo instance = null;
+ if (aClass != null)
+ {
+ try
+ {
+ Class[] argsClass = new Class[] {};
+ Constructor c = aClass.getConstructor(argsClass);
+ instance = (TagInfo) (c.newInstance(null));
+ }
+ catch (Exception e)
+ {
+ log.error("Cannot Instanciate : " + aClass.getName() + " : " + e.getMessage());
+ }
+ }
+ return instance;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/tag/ui/APEDialog.java b/java/src/javazoom/jlgui/player/amp/tag/ui/APEDialog.java
new file mode 100644
index 0000000..001bca3
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/ui/APEDialog.java
@@ -0,0 +1,187 @@
+/*
+ * APEDialog.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag.ui;
+
+import java.text.DecimalFormat;
+import javax.swing.JFrame;
+import javazoom.jlgui.player.amp.tag.APEInfo;
+
+/**
+ * APEDialog class implements a DialogBox to diplay APE info.
+ */
+public class APEDialog extends TagInfoDialog
+{
+ private APEInfo _apeinfo = null;
+
+ /**
+ * Creates new form ApeDialog
+ */
+ public APEDialog(JFrame parent, String title, APEInfo mi)
+ {
+ super(parent, title);
+ initComponents();
+ _apeinfo = mi;
+ int size = _apeinfo.getLocation().length();
+ locationLabel.setText(size > 50 ? ("..." + _apeinfo.getLocation().substring(size - 50)) : _apeinfo.getLocation());
+ if ((_apeinfo.getTitle() != null) && (!_apeinfo.getTitle().equals(""))) textField.append("Title=" + _apeinfo.getTitle() + "\n");
+ if ((_apeinfo.getArtist() != null) && (!_apeinfo.getArtist().equals(""))) textField.append("Artist=" + _apeinfo.getArtist() + "\n");
+ if ((_apeinfo.getAlbum() != null) && (!_apeinfo.getAlbum().equals(""))) textField.append("Album=" + _apeinfo.getAlbum() + "\n");
+ if (_apeinfo.getTrack() > 0) textField.append("Track=" + _apeinfo.getTrack() + "\n");
+ if ((_apeinfo.getYear() != null) && (!_apeinfo.getYear().equals(""))) textField.append("Year=" + _apeinfo.getYear() + "\n");
+ if ((_apeinfo.getGenre() != null) && (!_apeinfo.getGenre().equals(""))) textField.append("Genre=" + _apeinfo.getGenre() + "\n");
+ java.util.List comments = _apeinfo.getComment();
+ if (comments != null)
+ {
+ for (int i = 0; i < comments.size(); i++)
+ textField.append(comments.get(i) + "\n");
+ }
+ int secondsAmount = Math.round(_apeinfo.getPlayTime());
+ if (secondsAmount < 0) secondsAmount = 0;
+ int minutes = secondsAmount / 60;
+ int seconds = secondsAmount - (minutes * 60);
+ lengthLabel.setText("Length : " + minutes + ":" + seconds);
+ DecimalFormat df = new DecimalFormat("#,###,###");
+ sizeLabel.setText("Size : " + df.format(_apeinfo.getSize()) + " bytes");
+ versionLabel.setText("Version: " + df.format(_apeinfo.getVersion()));
+ compressionLabel.setText("Compression: " + _apeinfo.getCompressionlevel());
+ channelsLabel.setText("Channels: " + _apeinfo.getChannels());
+ bitspersampleLabel.setText("Bits Per Sample: " + _apeinfo.getBitsPerSample());
+ bitrateLabel.setText("Average Bitrate: " + (_apeinfo.getBitRate() / 1000) + " kbps");
+ samplerateLabel.setText("Sample Rate: " + _apeinfo.getSamplingRate() + " Hz");
+ peaklevelLabel.setText("Peak Level: " + (_apeinfo.getPeaklevel() > 0 ? String.valueOf(_apeinfo.getPeaklevel()) : ""));
+ copyrightLabel.setText("Copyrighted: " + (_apeinfo.getCopyright() != null ? _apeinfo.getCopyright() : ""));
+ buttonsPanel.add(_close);
+ pack();
+ }
+
+ /**
+ * This method is called from within the constructor to
+ * initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is
+ * always regenerated by the Form Editor.
+ */
+ // //GEN-BEGIN:initComponents
+ private void initComponents()
+ {
+ java.awt.GridBagConstraints gridBagConstraints;
+ jPanel3 = new javax.swing.JPanel();
+ jPanel1 = new javax.swing.JPanel();
+ jLabel1 = new javax.swing.JLabel();
+ locationLabel = new javax.swing.JLabel();
+ jLabel2 = new javax.swing.JLabel();
+ jLabel3 = new javax.swing.JLabel();
+ jScrollPane1 = new javax.swing.JScrollPane();
+ textField = new javax.swing.JTextArea();
+ jPanel2 = new javax.swing.JPanel();
+ lengthLabel = new javax.swing.JLabel();
+ sizeLabel = new javax.swing.JLabel();
+ versionLabel = new javax.swing.JLabel();
+ compressionLabel = new javax.swing.JLabel();
+ channelsLabel = new javax.swing.JLabel();
+ bitspersampleLabel = new javax.swing.JLabel();
+ bitrateLabel = new javax.swing.JLabel();
+ samplerateLabel = new javax.swing.JLabel();
+ peaklevelLabel = new javax.swing.JLabel();
+ copyrightLabel = new javax.swing.JLabel();
+ buttonsPanel = new javax.swing.JPanel();
+ getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.Y_AXIS));
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setResizable(false);
+ jPanel3.setLayout(new java.awt.GridBagLayout());
+ jPanel1.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
+ jLabel1.setText("File/URL :");
+ jPanel1.add(jLabel1);
+ jPanel1.add(locationLabel);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridwidth = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jPanel1, gridBagConstraints);
+ jLabel2.setText("Standard Tags");
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jLabel2, gridBagConstraints);
+ jLabel3.setText("File/Stream info");
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jLabel3, gridBagConstraints);
+ textField.setColumns(20);
+ textField.setRows(10);
+ jScrollPane1.setViewportView(textField);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jScrollPane1, gridBagConstraints);
+ jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.Y_AXIS));
+ jPanel2.add(lengthLabel);
+ jPanel2.add(sizeLabel);
+ jPanel2.add(versionLabel);
+ jPanel2.add(compressionLabel);
+ jPanel2.add(channelsLabel);
+ jPanel2.add(bitspersampleLabel);
+ jPanel2.add(bitrateLabel);
+ jPanel2.add(samplerateLabel);
+ jPanel2.add(peaklevelLabel);
+ jPanel2.add(copyrightLabel);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jPanel2, gridBagConstraints);
+ getContentPane().add(jPanel3);
+ getContentPane().add(buttonsPanel);
+ //pack();
+ }
+ // //GEN-END:initComponents
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JLabel bitrateLabel;
+ private javax.swing.JLabel bitspersampleLabel;
+ private javax.swing.JPanel buttonsPanel;
+ private javax.swing.JLabel channelsLabel;
+ private javax.swing.JLabel compressionLabel;
+ private javax.swing.JLabel copyrightLabel;
+ private javax.swing.JLabel jLabel1;
+ private javax.swing.JLabel jLabel2;
+ private javax.swing.JLabel jLabel3;
+ private javax.swing.JPanel jPanel1;
+ private javax.swing.JPanel jPanel2;
+ private javax.swing.JPanel jPanel3;
+ private javax.swing.JScrollPane jScrollPane1;
+ private javax.swing.JLabel lengthLabel;
+ private javax.swing.JLabel locationLabel;
+ private javax.swing.JLabel peaklevelLabel;
+ private javax.swing.JLabel samplerateLabel;
+ private javax.swing.JLabel sizeLabel;
+ private javax.swing.JTextArea textField;
+ private javax.swing.JLabel versionLabel;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/java/src/javazoom/jlgui/player/amp/tag/ui/EmptyDialog.java b/java/src/javazoom/jlgui/player/amp/tag/ui/EmptyDialog.java
new file mode 100644
index 0000000..147f6c9
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/ui/EmptyDialog.java
@@ -0,0 +1,75 @@
+/*
+ * EmptyDialog.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag.ui;
+
+import javax.swing.JFrame;
+import javazoom.jlgui.player.amp.tag.TagInfo;
+
+/**
+ * OggVorbisDialog class implements a DialogBox to diplay OggVorbis info.
+ */
+public class EmptyDialog extends TagInfoDialog
+{
+ private TagInfo _info = null;
+
+ /**
+ * Creates new form MpegDialog
+ */
+ public EmptyDialog(JFrame parent, String title, TagInfo mi)
+ {
+ super(parent, title);
+ initComponents();
+ _info = mi;
+ buttonsPanel.add(_close);
+ pack();
+ }
+
+ /**
+ * This method is called from within the constructor to
+ * initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is
+ * always regenerated by the Form Editor.
+ */
+ // //GEN-BEGIN:initComponents
+ private void initComponents()
+ {
+ jPanel3 = new javax.swing.JPanel();
+ jLabel1 = new javax.swing.JLabel();
+ buttonsPanel = new javax.swing.JPanel();
+ getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.Y_AXIS));
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setResizable(false);
+ jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+ jLabel1.setText("No Information Available");
+ jPanel3.add(jLabel1);
+ getContentPane().add(jPanel3);
+ getContentPane().add(buttonsPanel);
+ //pack();
+ }
+ // //GEN-END:initComponents
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JPanel buttonsPanel;
+ private javax.swing.JLabel jLabel1;
+ private javax.swing.JPanel jPanel3;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/java/src/javazoom/jlgui/player/amp/tag/ui/FlacDialog.java b/java/src/javazoom/jlgui/player/amp/tag/ui/FlacDialog.java
new file mode 100644
index 0000000..f506a67
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/ui/FlacDialog.java
@@ -0,0 +1,165 @@
+/*
+ * FlacDialog.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag.ui;
+
+import java.text.DecimalFormat;
+import javax.swing.JFrame;
+import javazoom.jlgui.player.amp.tag.FlacInfo;
+
+/**
+ * FlacDialog class implements a DialogBox to diplay Flac info.
+ */
+public class FlacDialog extends TagInfoDialog
+{
+ private FlacInfo _flacinfo = null;
+
+ /**
+ * Creates new form FlacDialog
+ */
+ public FlacDialog(JFrame parent, String title, FlacInfo mi)
+ {
+ super(parent, title);
+ initComponents();
+ _flacinfo = mi;
+ int size = _flacinfo.getLocation().length();
+ locationLabel.setText(size > 50 ? ("..." + _flacinfo.getLocation().substring(size - 50)) : _flacinfo.getLocation());
+ if ((_flacinfo.getTitle() != null) && (!_flacinfo.getTitle().equals(""))) textField.append("Title=" + _flacinfo.getTitle() + "\n");
+ if ((_flacinfo.getArtist() != null) && (!_flacinfo.getArtist().equals(""))) textField.append("Artist=" + _flacinfo.getArtist() + "\n");
+ if ((_flacinfo.getAlbum() != null) && (!_flacinfo.getAlbum().equals(""))) textField.append("Album=" + _flacinfo.getAlbum() + "\n");
+ if (_flacinfo.getTrack() > 0) textField.append("Track=" + _flacinfo.getTrack() + "\n");
+ if ((_flacinfo.getYear() != null) && (!_flacinfo.getYear().equals(""))) textField.append("Year=" + _flacinfo.getYear() + "\n");
+ if ((_flacinfo.getGenre() != null) && (!_flacinfo.getGenre().equals(""))) textField.append("Genre=" + _flacinfo.getGenre() + "\n");
+ java.util.List comments = _flacinfo.getComment();
+ if (comments != null)
+ {
+ for (int i = 0; i < comments.size(); i++)
+ textField.append(comments.get(i) + "\n");
+ }
+ DecimalFormat df = new DecimalFormat("#,###,###");
+ sizeLabel.setText("Size : " + df.format(_flacinfo.getSize()) + " bytes");
+ channelsLabel.setText("Channels: " + _flacinfo.getChannels());
+ bitspersampleLabel.setText("Bits Per Sample: " + _flacinfo.getBitsPerSample());
+ samplerateLabel.setText("Sample Rate: " + _flacinfo.getSamplingRate() + " Hz");
+ buttonsPanel.add(_close);
+ pack();
+ }
+
+ /**
+ * This method is called from within the constructor to
+ * initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is
+ * always regenerated by the Form Editor.
+ */
+ // //GEN-BEGIN:initComponents
+ private void initComponents()
+ {
+ java.awt.GridBagConstraints gridBagConstraints;
+ jPanel3 = new javax.swing.JPanel();
+ jPanel1 = new javax.swing.JPanel();
+ jLabel1 = new javax.swing.JLabel();
+ locationLabel = new javax.swing.JLabel();
+ jLabel2 = new javax.swing.JLabel();
+ jLabel3 = new javax.swing.JLabel();
+ jScrollPane1 = new javax.swing.JScrollPane();
+ textField = new javax.swing.JTextArea();
+ jPanel2 = new javax.swing.JPanel();
+ lengthLabel = new javax.swing.JLabel();
+ sizeLabel = new javax.swing.JLabel();
+ channelsLabel = new javax.swing.JLabel();
+ bitspersampleLabel = new javax.swing.JLabel();
+ bitrateLabel = new javax.swing.JLabel();
+ samplerateLabel = new javax.swing.JLabel();
+ buttonsPanel = new javax.swing.JPanel();
+ getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.Y_AXIS));
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setResizable(false);
+ jPanel3.setLayout(new java.awt.GridBagLayout());
+ jPanel1.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
+ jLabel1.setText("File/URL :");
+ jPanel1.add(jLabel1);
+ jPanel1.add(locationLabel);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridwidth = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jPanel1, gridBagConstraints);
+ jLabel2.setText("Standard Tags");
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jLabel2, gridBagConstraints);
+ jLabel3.setText("File/Stream info");
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jLabel3, gridBagConstraints);
+ textField.setColumns(20);
+ textField.setRows(10);
+ jScrollPane1.setViewportView(textField);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jScrollPane1, gridBagConstraints);
+ jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.Y_AXIS));
+ jPanel2.add(lengthLabel);
+ jPanel2.add(sizeLabel);
+ jPanel2.add(channelsLabel);
+ jPanel2.add(bitspersampleLabel);
+ jPanel2.add(bitrateLabel);
+ jPanel2.add(samplerateLabel);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jPanel2, gridBagConstraints);
+ getContentPane().add(jPanel3);
+ getContentPane().add(buttonsPanel);
+ //pack();
+ }
+ // //GEN-END:initComponents
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JLabel bitrateLabel;
+ private javax.swing.JLabel bitspersampleLabel;
+ private javax.swing.JPanel buttonsPanel;
+ private javax.swing.JLabel channelsLabel;
+ private javax.swing.JLabel jLabel1;
+ private javax.swing.JLabel jLabel2;
+ private javax.swing.JLabel jLabel3;
+ private javax.swing.JPanel jPanel1;
+ private javax.swing.JPanel jPanel2;
+ private javax.swing.JPanel jPanel3;
+ private javax.swing.JScrollPane jScrollPane1;
+ private javax.swing.JLabel lengthLabel;
+ private javax.swing.JLabel locationLabel;
+ private javax.swing.JLabel samplerateLabel;
+ private javax.swing.JLabel sizeLabel;
+ private javax.swing.JTextArea textField;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/java/src/javazoom/jlgui/player/amp/tag/ui/MpegDialog.java b/java/src/javazoom/jlgui/player/amp/tag/ui/MpegDialog.java
new file mode 100644
index 0000000..2782bed
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/ui/MpegDialog.java
@@ -0,0 +1,194 @@
+/*
+ * MpegDialog.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag.ui;
+
+import java.text.DecimalFormat;
+import javax.swing.JFrame;
+import javazoom.jlgui.player.amp.tag.MpegInfo;
+
+/**
+ * OggVorbisDialog class implements a DialogBox to diplay OggVorbis info.
+ */
+public class MpegDialog extends TagInfoDialog
+{
+ private MpegInfo _mpeginfo = null;
+
+ /**
+ * Creates new form MpegDialog
+ */
+ public MpegDialog(JFrame parent, String title, MpegInfo mi)
+ {
+ super(parent, title);
+ initComponents();
+ _mpeginfo = mi;
+ int size = _mpeginfo.getLocation().length();
+ locationLabel.setText(size > 50 ? ("..." + _mpeginfo.getLocation().substring(size - 50)) : _mpeginfo.getLocation());
+ if ((_mpeginfo.getTitle() != null) && ((!_mpeginfo.getTitle().equals("")))) textField.append("Title=" + _mpeginfo.getTitle() + "\n");
+ if ((_mpeginfo.getArtist() != null) && ((!_mpeginfo.getArtist().equals("")))) textField.append("Artist=" + _mpeginfo.getArtist() + "\n");
+ if ((_mpeginfo.getAlbum() != null) && ((!_mpeginfo.getAlbum().equals("")))) textField.append("Album=" + _mpeginfo.getAlbum() + "\n");
+ if (_mpeginfo.getTrack() > 0) textField.append("Track=" + _mpeginfo.getTrack() + "\n");
+ if ((_mpeginfo.getYear() != null) && ((!_mpeginfo.getYear().equals("")))) textField.append("Year=" + _mpeginfo.getYear() + "\n");
+ if ((_mpeginfo.getGenre() != null) && ((!_mpeginfo.getGenre().equals("")))) textField.append("Genre=" + _mpeginfo.getGenre() + "\n");
+ java.util.List comments = _mpeginfo.getComment();
+ if (comments != null)
+ {
+ for (int i = 0; i < comments.size(); i++)
+ textField.append(comments.get(i) + "\n");
+ }
+ int secondsAmount = Math.round(_mpeginfo.getPlayTime());
+ if (secondsAmount < 0) secondsAmount = 0;
+ int minutes = secondsAmount / 60;
+ int seconds = secondsAmount - (minutes * 60);
+ lengthLabel.setText("Length : " + minutes + ":" + seconds);
+ DecimalFormat df = new DecimalFormat("#,###,###");
+ sizeLabel.setText("Size : " + df.format(_mpeginfo.getSize()) + " bytes");
+ versionLabel.setText(_mpeginfo.getVersion() + " " + _mpeginfo.getLayer());
+ bitrateLabel.setText((_mpeginfo.getBitRate() / 1000) + " kbps");
+ samplerateLabel.setText(_mpeginfo.getSamplingRate() + " Hz " + _mpeginfo.getChannelsMode());
+ vbrLabel.setText("VBR : " + _mpeginfo.getVBR());
+ crcLabel.setText("CRCs : " + _mpeginfo.getCRC());
+ copyrightLabel.setText("Copyrighted : " + _mpeginfo.getCopyright());
+ originalLabel.setText("Original : " + _mpeginfo.getOriginal());
+ emphasisLabel.setText("Emphasis : " + _mpeginfo.getEmphasis());
+ buttonsPanel.add(_close);
+ pack();
+ }
+
+ /**
+ * Returns VorbisInfo.
+ */
+ public MpegInfo getOggVorbisInfo()
+ {
+ return _mpeginfo;
+ }
+
+ /**
+ * This method is called from within the constructor to
+ * initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is
+ * always regenerated by the Form Editor.
+ */
+ // //GEN-BEGIN:initComponents
+ private void initComponents()
+ {
+ java.awt.GridBagConstraints gridBagConstraints;
+ jPanel3 = new javax.swing.JPanel();
+ jPanel1 = new javax.swing.JPanel();
+ jLabel1 = new javax.swing.JLabel();
+ locationLabel = new javax.swing.JLabel();
+ jLabel2 = new javax.swing.JLabel();
+ jLabel3 = new javax.swing.JLabel();
+ jScrollPane1 = new javax.swing.JScrollPane();
+ textField = new javax.swing.JTextArea();
+ jPanel2 = new javax.swing.JPanel();
+ lengthLabel = new javax.swing.JLabel();
+ sizeLabel = new javax.swing.JLabel();
+ versionLabel = new javax.swing.JLabel();
+ bitrateLabel = new javax.swing.JLabel();
+ samplerateLabel = new javax.swing.JLabel();
+ vbrLabel = new javax.swing.JLabel();
+ crcLabel = new javax.swing.JLabel();
+ copyrightLabel = new javax.swing.JLabel();
+ originalLabel = new javax.swing.JLabel();
+ emphasisLabel = new javax.swing.JLabel();
+ buttonsPanel = new javax.swing.JPanel();
+ getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.Y_AXIS));
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setResizable(false);
+ jPanel3.setLayout(new java.awt.GridBagLayout());
+ jPanel1.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
+ jLabel1.setText("File/URL :");
+ jPanel1.add(jLabel1);
+ jPanel1.add(locationLabel);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridwidth = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jPanel1, gridBagConstraints);
+ jLabel2.setText("Standard Tags");
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jLabel2, gridBagConstraints);
+ jLabel3.setText("File/Stream info");
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jLabel3, gridBagConstraints);
+ textField.setColumns(20);
+ textField.setRows(10);
+ jScrollPane1.setViewportView(textField);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jScrollPane1, gridBagConstraints);
+ jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.Y_AXIS));
+ jPanel2.add(lengthLabel);
+ jPanel2.add(sizeLabel);
+ jPanel2.add(versionLabel);
+ jPanel2.add(bitrateLabel);
+ jPanel2.add(samplerateLabel);
+ jPanel2.add(vbrLabel);
+ jPanel2.add(crcLabel);
+ jPanel2.add(copyrightLabel);
+ jPanel2.add(originalLabel);
+ jPanel2.add(emphasisLabel);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jPanel2, gridBagConstraints);
+ getContentPane().add(jPanel3);
+ getContentPane().add(buttonsPanel);
+ //pack();
+ }
+ // //GEN-END:initComponents
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JLabel bitrateLabel;
+ private javax.swing.JPanel buttonsPanel;
+ private javax.swing.JLabel copyrightLabel;
+ private javax.swing.JLabel crcLabel;
+ private javax.swing.JLabel emphasisLabel;
+ private javax.swing.JLabel jLabel1;
+ private javax.swing.JLabel jLabel2;
+ private javax.swing.JLabel jLabel3;
+ private javax.swing.JPanel jPanel1;
+ private javax.swing.JPanel jPanel2;
+ private javax.swing.JPanel jPanel3;
+ private javax.swing.JScrollPane jScrollPane1;
+ private javax.swing.JLabel lengthLabel;
+ private javax.swing.JLabel locationLabel;
+ private javax.swing.JLabel originalLabel;
+ private javax.swing.JLabel samplerateLabel;
+ private javax.swing.JLabel sizeLabel;
+ private javax.swing.JTextArea textField;
+ private javax.swing.JLabel vbrLabel;
+ private javax.swing.JLabel versionLabel;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/java/src/javazoom/jlgui/player/amp/tag/ui/OggVorbisDialog.java b/java/src/javazoom/jlgui/player/amp/tag/ui/OggVorbisDialog.java
new file mode 100644
index 0000000..16a84e6
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/ui/OggVorbisDialog.java
@@ -0,0 +1,196 @@
+/*
+ * OggVorbisDialog.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag.ui;
+
+import java.text.DecimalFormat;
+import javax.swing.JFrame;
+import javazoom.jlgui.player.amp.tag.OggVorbisInfo;
+
+/**
+ * OggVorbisDialog class implements a DialogBox to diplay OggVorbis info.
+ */
+public class OggVorbisDialog extends TagInfoDialog
+{
+ private OggVorbisInfo _vorbisinfo = null;
+
+ /**
+ * Creates new form MpegDialog
+ */
+ public OggVorbisDialog(JFrame parent, String title, OggVorbisInfo mi)
+ {
+ super(parent, title);
+ initComponents();
+ _vorbisinfo = mi;
+ int size = _vorbisinfo.getLocation().length();
+ locationLabel.setText(size > 50 ? ("..." + _vorbisinfo.getLocation().substring(size - 50)) : _vorbisinfo.getLocation());
+ if ((_vorbisinfo.getTitle() != null) && ((!_vorbisinfo.getTitle().equals("")))) textField.append("Title=" + _vorbisinfo.getTitle() + "\n");
+ if ((_vorbisinfo.getArtist() != null) && ((!_vorbisinfo.getArtist().equals("")))) textField.append("Artist=" + _vorbisinfo.getArtist() + "\n");
+ if ((_vorbisinfo.getAlbum() != null) && ((!_vorbisinfo.getAlbum().equals("")))) textField.append("Album=" + _vorbisinfo.getAlbum() + "\n");
+ if (_vorbisinfo.getTrack() > 0) textField.append("Track=" + _vorbisinfo.getTrack() + "\n");
+ if ((_vorbisinfo.getYear() != null) && ((!_vorbisinfo.getYear().equals("")))) textField.append("Year=" + _vorbisinfo.getYear() + "\n");
+ if ((_vorbisinfo.getGenre() != null) && ((!_vorbisinfo.getGenre().equals("")))) textField.append("Genre=" + _vorbisinfo.getGenre() + "\n");
+ java.util.List comments = _vorbisinfo.getComment();
+ for (int i = 0; i < comments.size(); i++)
+ textField.append(comments.get(i) + "\n");
+ int secondsAmount = Math.round(_vorbisinfo.getPlayTime());
+ if (secondsAmount < 0) secondsAmount = 0;
+ int minutes = secondsAmount / 60;
+ int seconds = secondsAmount - (minutes * 60);
+ lengthLabel.setText("Length : " + minutes + ":" + seconds);
+ bitrateLabel.setText("Average bitrate : " + _vorbisinfo.getAverageBitrate() / 1000 + " kbps");
+ DecimalFormat df = new DecimalFormat("#,###,###");
+ sizeLabel.setText("File size : " + df.format(_vorbisinfo.getSize()) + " bytes");
+ nominalbitrateLabel.setText("Nominal bitrate : " + (_vorbisinfo.getBitRate() / 1000) + " kbps");
+ maxbitrateLabel.setText("Max bitrate : " + _vorbisinfo.getMaxBitrate() / 1000 + " kbps");
+ minbitrateLabel.setText("Min bitrate : " + _vorbisinfo.getMinBitrate() / 1000 + " kbps");
+ channelsLabel.setText("Channel : " + _vorbisinfo.getChannels());
+ samplerateLabel.setText("Sampling rate : " + _vorbisinfo.getSamplingRate() + " Hz");
+ serialnumberLabel.setText("Serial number : " + _vorbisinfo.getSerial());
+ versionLabel.setText("Version : " + _vorbisinfo.getVersion());
+ vendorLabel.setText("Vendor : " + _vorbisinfo.getVendor());
+ buttonsPanel.add(_close);
+ pack();
+ }
+
+ /**
+ * Returns VorbisInfo.
+ */
+ public OggVorbisInfo getOggVorbisInfo()
+ {
+ return _vorbisinfo;
+ }
+
+ /**
+ * This method is called from within the constructor to
+ * initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is
+ * always regenerated by the Form Editor.
+ */
+ // //GEN-BEGIN:initComponents
+ private void initComponents()
+ {
+ java.awt.GridBagConstraints gridBagConstraints;
+ jPanel3 = new javax.swing.JPanel();
+ jPanel1 = new javax.swing.JPanel();
+ jLabel1 = new javax.swing.JLabel();
+ locationLabel = new javax.swing.JLabel();
+ jLabel2 = new javax.swing.JLabel();
+ jLabel3 = new javax.swing.JLabel();
+ jScrollPane1 = new javax.swing.JScrollPane();
+ textField = new javax.swing.JTextArea();
+ jPanel2 = new javax.swing.JPanel();
+ lengthLabel = new javax.swing.JLabel();
+ bitrateLabel = new javax.swing.JLabel();
+ sizeLabel = new javax.swing.JLabel();
+ nominalbitrateLabel = new javax.swing.JLabel();
+ maxbitrateLabel = new javax.swing.JLabel();
+ minbitrateLabel = new javax.swing.JLabel();
+ channelsLabel = new javax.swing.JLabel();
+ samplerateLabel = new javax.swing.JLabel();
+ serialnumberLabel = new javax.swing.JLabel();
+ versionLabel = new javax.swing.JLabel();
+ vendorLabel = new javax.swing.JLabel();
+ buttonsPanel = new javax.swing.JPanel();
+ getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.Y_AXIS));
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setResizable(false);
+ jPanel3.setLayout(new java.awt.GridBagLayout());
+ jPanel1.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
+ jLabel1.setText("File/URL :");
+ jPanel1.add(jLabel1);
+ jPanel1.add(locationLabel);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridwidth = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jPanel1, gridBagConstraints);
+ jLabel2.setText("Standard Tags");
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jLabel2, gridBagConstraints);
+ jLabel3.setText("File/Stream info");
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jLabel3, gridBagConstraints);
+ textField.setColumns(20);
+ textField.setRows(10);
+ jScrollPane1.setViewportView(textField);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jScrollPane1, gridBagConstraints);
+ jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.Y_AXIS));
+ jPanel2.add(lengthLabel);
+ jPanel2.add(bitrateLabel);
+ jPanel2.add(sizeLabel);
+ jPanel2.add(nominalbitrateLabel);
+ jPanel2.add(maxbitrateLabel);
+ jPanel2.add(minbitrateLabel);
+ jPanel2.add(channelsLabel);
+ jPanel2.add(samplerateLabel);
+ jPanel2.add(serialnumberLabel);
+ jPanel2.add(versionLabel);
+ jPanel2.add(vendorLabel);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+ gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+ jPanel3.add(jPanel2, gridBagConstraints);
+ getContentPane().add(jPanel3);
+ getContentPane().add(buttonsPanel);
+ //pack();
+ }
+ // //GEN-END:initComponents
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JLabel bitrateLabel;
+ private javax.swing.JPanel buttonsPanel;
+ private javax.swing.JLabel channelsLabel;
+ private javax.swing.JLabel jLabel1;
+ private javax.swing.JLabel jLabel2;
+ private javax.swing.JLabel jLabel3;
+ private javax.swing.JPanel jPanel1;
+ private javax.swing.JPanel jPanel2;
+ private javax.swing.JPanel jPanel3;
+ private javax.swing.JScrollPane jScrollPane1;
+ private javax.swing.JLabel lengthLabel;
+ private javax.swing.JLabel locationLabel;
+ private javax.swing.JLabel maxbitrateLabel;
+ private javax.swing.JLabel minbitrateLabel;
+ private javax.swing.JLabel nominalbitrateLabel;
+ private javax.swing.JLabel samplerateLabel;
+ private javax.swing.JLabel serialnumberLabel;
+ private javax.swing.JLabel sizeLabel;
+ private javax.swing.JTextArea textField;
+ private javax.swing.JLabel vendorLabel;
+ private javax.swing.JLabel versionLabel;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/java/src/javazoom/jlgui/player/amp/tag/ui/TagInfoDialog.java b/java/src/javazoom/jlgui/player/amp/tag/ui/TagInfoDialog.java
new file mode 100644
index 0000000..bd12b12
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/ui/TagInfoDialog.java
@@ -0,0 +1,60 @@
+/*
+ * TagInfoDialog.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag.ui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+
+/**
+ * This class define a Dialog for TagiInfo to display.
+ */
+public class TagInfoDialog extends JDialog implements ActionListener
+{
+ protected JButton _close = null;
+
+ /**
+ * Constructor.
+ * @param parent
+ * @param title
+ */
+ public TagInfoDialog(JFrame parent, String title)
+ {
+ super(parent, title, true);
+ _close = new JButton("Close");
+ _close.addActionListener(this);
+ }
+
+ /* (non-Javadoc)
+ * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ if (e.getSource() == _close)
+ {
+ this.dispose();
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/tag/ui/TagSearch.java b/java/src/javazoom/jlgui/player/amp/tag/ui/TagSearch.java
new file mode 100644
index 0000000..3faf9d6
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/ui/TagSearch.java
@@ -0,0 +1,434 @@
+/*
+ * TagSearch.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.tag.ui;
+
+import java.awt.BorderLayout;
+import java.awt.GridLayout;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ResourceBundle;
+import java.util.Vector;
+import javax.swing.ButtonGroup;
+import javax.swing.DefaultListModel;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollBar;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.WindowConstants;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javazoom.jlgui.player.amp.PlayerUI;
+import javazoom.jlgui.player.amp.playlist.Playlist;
+import javazoom.jlgui.player.amp.playlist.PlaylistItem;
+import javazoom.jlgui.player.amp.tag.TagInfo;
+
+/**
+ * This class allows to search and play for a particular track in the current playlist.
+ */
+public class TagSearch extends JFrame
+{
+ private static String sep = System.getProperty("file.separator");
+ private JTextField searchField;
+ private JList list;
+ private DefaultListModel m;
+ private PlayerUI player;
+ private Vector _playlist, restrictedPlaylist;
+ private String lastSearch = null;
+ private JScrollPane scroll;
+ private ResourceBundle bundle;
+ private JRadioButton all, artist, album, title;
+
+ public TagSearch(PlayerUI ui)
+ {
+ super();
+ player = ui;
+ _playlist = null;
+ restrictedPlaylist = null;
+ bundle = ResourceBundle.getBundle("javazoom/jlgui/player/amp/tag/ui/tag");
+ initComponents();
+ }
+
+ public void display()
+ {
+ if (list.getModel().getSize() != 0)
+ {
+ setVisible(true);
+ }
+ else
+ {
+ JOptionPane.showMessageDialog(player.getParent(), bundle.getString("emptyPlaylistMsg"), bundle.getString("emptyPlaylistTitle"), JOptionPane.OK_OPTION);
+ }
+ }
+
+ /**
+ * Initialises the User Interface.
+ */
+ private void initComponents()
+ {
+ setLayout(new GridLayout(1, 1));
+ setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+ setTitle(bundle.getString("title"));
+ this.setLocation(player.getX() + player.getWidth(), player.getY());
+ JPanel main = new JPanel(new BorderLayout(0, 1));
+ main.setBorder(new EmptyBorder(10, 10, 10, 10));
+ main.setMinimumSize(new java.awt.Dimension(0, 0));
+ main.setPreferredSize(new java.awt.Dimension(300, 400));
+ JPanel searchPane = new JPanel(new GridLayout(4, 1, 10, 2));
+ JLabel searchLabel = new JLabel(bundle.getString("searchLabel"));
+ searchField = new JTextField();
+ searchField.addKeyListener(new KeyboardListener());
+ searchPane.add(searchLabel);
+ searchPane.add(searchField);
+ all = new JRadioButton(bundle.getString("radioAll"), true);
+ artist = new JRadioButton(bundle.getString("radioArtist"), false);
+ album = new JRadioButton(bundle.getString("radioAlbum"), false);
+ title = new JRadioButton(bundle.getString("radioTitle"), false);
+ all.addChangeListener(new RadioListener());
+ ButtonGroup filters = new ButtonGroup();
+ filters.add(all);
+ filters.add(artist);
+ filters.add(album);
+ filters.add(title);
+ JPanel topButtons = new JPanel(new GridLayout(1, 2));
+ JPanel bottomButtons = new JPanel(new GridLayout(1, 2));
+ topButtons.add(all);
+ topButtons.add(artist);
+ bottomButtons.add(album);
+ bottomButtons.add(title);
+ searchPane.add(topButtons);
+ searchPane.add(bottomButtons);
+ list = new JList();
+ list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ initList();
+ list.addMouseListener(new ClickListener());
+ list.addKeyListener(new KeyboardListener());
+ scroll = new JScrollPane(list);
+ main.add(searchPane, BorderLayout.NORTH);
+ main.add(scroll, BorderLayout.CENTER);
+ add(main);
+ pack();
+ }
+
+ /**
+ * Initialises the list so that it displays the details of all songs in the playlist.
+ */
+ private void initList()
+ {
+ Playlist playlist = player.getPlaylist();
+ int c = player.getPlaylist().getPlaylistSize();
+ _playlist = new Vector();
+ for (int i = 0; i < c; i++)
+ {
+ _playlist.addElement(playlist.getItemAt(i));
+ }
+ restrictedPlaylist = _playlist;
+ m = new DefaultListModel();
+ for (int i = 0; i < _playlist.size(); i++)
+ {
+ PlaylistItem plItem = (PlaylistItem) _playlist.get(i);
+ if (plItem.isFile()) m.addElement(getDisplayString(plItem));
+ }
+ list.setModel(m);
+ }
+
+ public String getDisplayString(PlaylistItem pi)
+ {
+ TagInfo song = pi.getTagInfo();
+ String element;
+ String location = pi.getLocation();
+ location = location.substring(location.lastIndexOf(sep) + 1, location.lastIndexOf("."));
+ if (song == null)
+ {
+ element = location;
+ }
+ else
+ {
+ if (song.getArtist() == null || song.getArtist().equals(""))
+ {
+ element = location;
+ }
+ else
+ {
+ element = song.getArtist().trim();
+ if (song.getTitle() == null || song.getTitle().equals(""))
+ {
+ element += " - " + location;
+ }
+ else
+ {
+ element += " - " + song.getTitle().trim();
+ }
+ }
+ }
+ return element;
+ }
+
+ /**
+ * Searches the playlist for a song containing the words in the given search string.
+ * It searches on the title, artist, album and filename of each song in the playlist.
+ *
+ * @param searchString The string to search for in all songs in the playlist
+ **/
+ private void searchList(String searchString)
+ {
+ String[] s = searchString.split(" ");
+ String lastS = "";
+ if (s.length > 0) lastS = s[s.length - 1];
+ if (lastS.equals(""))
+ {
+ list.setModel(m);
+ restrictedPlaylist = _playlist;
+ }
+ else
+ {
+ DefaultListModel newModel = new DefaultListModel();
+ if (lastSearch != null)
+ {
+ if (searchString.length() <= 1 || !searchString.substring(searchString.length() - 2).equals(lastSearch))
+ {
+ list.setModel(m);
+ restrictedPlaylist = _playlist;
+ }
+ }
+ Vector pI = restrictedPlaylist;
+ restrictedPlaylist = new Vector();
+ for (int a = 0; a < s.length; a++)
+ {
+ String currentS = s[a];
+ int size = list.getModel().getSize();
+ boolean[] remove = new boolean[size];
+ for (int i = 0; i < size; i++)
+ {
+ final int TITLE_SEARCH = 0;
+ final int ARTIST_SEARCH = 1;
+ final int ALBUM_SEARCH = 2;
+ final int FILENAME_SEARCH = 3;
+ TagInfo pli = ((PlaylistItem) pI.get(i)).getTagInfo();
+ remove[i] = false;
+ boolean found = false;
+ int searchType;
+ if (artist.isSelected())
+ {
+ searchType = ARTIST_SEARCH;
+ }
+ else if (album.isSelected())
+ {
+ searchType = ALBUM_SEARCH;
+ }
+ else if (title.isSelected())
+ {
+ searchType = TITLE_SEARCH;
+ }
+ else
+ {
+ searchType = -1;
+ }
+ for (int j = 0; j <= FILENAME_SEARCH; j++)
+ {
+ String listString = "";
+ if (pli == null)
+ {
+ if (searchType != -1)
+ {
+ break;
+ }
+ j = FILENAME_SEARCH;
+ }
+ else if (searchType != -1)
+ {
+ j = searchType;
+ }
+ switch (j)
+ {
+ case (TITLE_SEARCH):
+ if (pli.getTitle() != null) listString = pli.getTitle().toLowerCase();
+ break;
+ case (ARTIST_SEARCH):
+ if (pli.getArtist() != null) listString = pli.getArtist().toLowerCase();
+ break;
+ case (ALBUM_SEARCH):
+ if (pli.getAlbum() != null) listString = pli.getAlbum().toLowerCase();
+ break;
+ case (FILENAME_SEARCH):
+ String location = ((PlaylistItem) pI.get(i)).getLocation().toLowerCase();
+ listString = location.substring(location.lastIndexOf(sep) + 1, location.lastIndexOf("."));
+ break;
+ }
+ currentS = currentS.toLowerCase();
+ if (found = search(currentS, listString))
+ {
+ break;
+ }
+ if (searchType != -1)
+ {
+ break;
+ }
+ }
+ //if(found)foundAt[a] = i;
+ if (found && a == 0)
+ {
+ //todo new
+ newModel.addElement(getDisplayString((PlaylistItem) pI.get(i)));
+ restrictedPlaylist.add(pI.get(i));
+ }
+ if (!found && a != 0)
+ {
+ remove[i] = true;
+ }
+ }
+ //remove all unmatching items
+ for (int x = size - 1; x >= 0; x--)
+ {
+ if (remove[x])
+ {
+ newModel.remove(x);
+ restrictedPlaylist.remove(x);
+ }
+ }
+ pI = restrictedPlaylist;
+ list.setModel(newModel);
+ }
+ list.setModel(newModel);
+ lastSearch = searchField.getText();
+ }
+ if (list.getModel().getSize() > 0) list.setSelectedIndex(0);
+ }
+
+ /**
+ * Searches to see if a particular string exists within another string
+ *
+ * @param pattern The string to search for
+ * @param text The string in which to search for the pattern string
+ * @return True if the pattern string exists in the text string
+ */
+ private boolean search(String pattern, String text)
+ {
+ int pStart = 0;
+ int tStart = 0;
+ char[] pChar = pattern.toCharArray();
+ char[] tChar = text.toCharArray();
+ while (pStart < pChar.length && tStart < tChar.length)
+ {
+ if (pChar[pStart] == tChar[tStart])
+ {
+ pStart++;
+ tStart++;
+ }
+ else
+ {
+ pStart = 0;
+ if (pChar[pStart] != tChar[tStart])
+ {
+ tStart++;
+ }
+ }
+ }
+ return pStart == pChar.length;
+ }
+
+ /**
+ * Calls the relavent methods in the player class to play a song.
+ */
+ private void playSong()
+ {
+ Playlist playlist = player.getPlaylist();
+ player.pressStop();
+ player.setCurrentSong((PlaylistItem) restrictedPlaylist.get(list.getSelectedIndex()));
+ playlist.setCursor(playlist.getIndex((PlaylistItem) restrictedPlaylist.get(list.getSelectedIndex())));
+ player.pressStart();
+ dispose();
+ }
+ /**
+ * Class to handle keyboard presses.
+ */
+ class KeyboardListener implements KeyListener
+ {
+ public void keyReleased(KeyEvent e)
+ {
+ if (e.getSource().equals(searchField))
+ {
+ if (e.getKeyCode() != KeyEvent.VK_DOWN && e.getKeyCode() != KeyEvent.VK_UP)
+ {
+ searchList(searchField.getText()); // Search for current search string
+ }
+ }
+ }
+
+ public void keyTyped(KeyEvent e)
+ {
+ if (list.getSelectedIndex() != -1)
+ {
+ if (e.getKeyChar() == KeyEvent.VK_ENTER)
+ {
+ playSong();
+ }
+ }
+ }
+
+ public void keyPressed(KeyEvent e)
+ {
+ int index = list.getSelectedIndex();
+ if (e.getKeyCode() == KeyEvent.VK_DOWN && index < list.getModel().getSize() - 1)
+ {
+ //list.setSelectedIndex(index+1);
+ JScrollBar vBar = scroll.getVerticalScrollBar();
+ vBar.setValue(vBar.getValue() + vBar.getUnitIncrement() * 5);
+ }
+ else if (e.getKeyCode() == KeyEvent.VK_UP && index >= 0)
+ {
+ JScrollBar vBar = scroll.getVerticalScrollBar();
+ vBar.setValue(vBar.getValue() - vBar.getUnitIncrement() * 5);
+ //list.setSelectedIndex(index-1);
+ }
+ }
+ }
+ /**
+ * Class to play a song if one is double-clicked on on the search list.
+ */
+ class ClickListener extends MouseAdapter
+ {
+ public void mouseClicked(MouseEvent e)
+ {
+ if (e.getClickCount() == 2 && list.getSelectedIndex() != -1)
+ {
+ playSong();
+ }
+ }
+ }
+ class RadioListener implements ChangeListener
+ {
+ public void stateChanged(ChangeEvent e)
+ {
+ searchList(searchField.getText());
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/tag/ui/tag.properties b/java/src/javazoom/jlgui/player/amp/tag/ui/tag.properties
new file mode 100644
index 0000000..9d9c18f
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/tag/ui/tag.properties
@@ -0,0 +1,8 @@
+emptyPlaylistMsg = No files in playlist
+emptyPlaylistTitle = No files in playlist
+title = Jump to song...
+searchLabel = Search for songs containing...
+radioAll = Anywhere
+radioArtist = Artist
+radioAlbum = Album
+radioTitle = Song Title
diff --git a/java/src/javazoom/jlgui/player/amp/util/BMPLoader.java b/java/src/javazoom/jlgui/player/amp/util/BMPLoader.java
new file mode 100644
index 0000000..a5e46c7
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/BMPLoader.java
@@ -0,0 +1,301 @@
+/*
+ * BMPLoader.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.image.ColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.MemoryImageSource;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A decoder for Windows bitmap (.BMP) files.
+ * Compression not supported.
+ */
+public class BMPLoader
+{
+ private InputStream is;
+ private int curPos = 0;
+ private int bitmapOffset; // starting position of image data
+ private int width; // image width in pixels
+ private int height; // image height in pixels
+ private short bitsPerPixel; // 1, 4, 8, or 24 (no color map)
+ private int compression; // 0 (none), 1 (8-bit RLE), or 2 (4-bit RLE)
+ private int actualSizeOfBitmap;
+ private int scanLineSize;
+ private int actualColorsUsed;
+ private byte r[], g[], b[]; // color palette
+ private int noOfEntries;
+ private byte[] byteData; // Unpacked data
+ private int[] intData; // Unpacked data
+
+ public BMPLoader()
+ {
+ }
+
+ public Image getBMPImage(InputStream stream) throws Exception
+ {
+ read(stream);
+ return Toolkit.getDefaultToolkit().createImage(getImageSource());
+ }
+
+ protected int readInt() throws IOException
+ {
+ int b1 = is.read();
+ int b2 = is.read();
+ int b3 = is.read();
+ int b4 = is.read();
+ curPos += 4;
+ return ((b4 << 24) + (b3 << 16) + (b2 << 8) + (b1 << 0));
+ }
+
+ protected short readShort() throws IOException
+ {
+ int b1 = is.read();
+ int b2 = is.read();
+ curPos += 4;
+ return (short) ((b2 << 8) + b1);
+ }
+
+ protected void getFileHeader() throws IOException, Exception
+ {
+ // Actual contents (14 bytes):
+ short fileType = 0x4d42;// always "BM"
+ int fileSize; // size of file in bytes
+ short reserved1 = 0; // always 0
+ short reserved2 = 0; // always 0
+ fileType = readShort();
+ if (fileType != 0x4d42) throw new Exception("Not a BMP file"); // wrong file type
+ fileSize = readInt();
+ reserved1 = readShort();
+ reserved2 = readShort();
+ bitmapOffset = readInt();
+ }
+
+ protected void getBitmapHeader() throws IOException
+ {
+ // Actual contents (40 bytes):
+ int size; // size of this header in bytes
+ short planes; // no. of color planes: always 1
+ int sizeOfBitmap; // size of bitmap in bytes (may be 0: if so, calculate)
+ int horzResolution; // horizontal resolution, pixels/meter (may be 0)
+ int vertResolution; // vertical resolution, pixels/meter (may be 0)
+ int colorsUsed; // no. of colors in palette (if 0, calculate)
+ int colorsImportant; // no. of important colors (appear first in palette) (0 means all are important)
+ boolean topDown;
+ int noOfPixels;
+ size = readInt();
+ width = readInt();
+ height = readInt();
+ planes = readShort();
+ bitsPerPixel = readShort();
+ compression = readInt();
+ sizeOfBitmap = readInt();
+ horzResolution = readInt();
+ vertResolution = readInt();
+ colorsUsed = readInt();
+ colorsImportant = readInt();
+ topDown = (height < 0);
+ noOfPixels = width * height;
+ // Scan line is padded with zeroes to be a multiple of four bytes
+ scanLineSize = ((width * bitsPerPixel + 31) / 32) * 4;
+ if (sizeOfBitmap != 0) actualSizeOfBitmap = sizeOfBitmap;
+ else
+ // a value of 0 doesn't mean zero - it means we have to calculate it
+ actualSizeOfBitmap = scanLineSize * height;
+ if (colorsUsed != 0) actualColorsUsed = colorsUsed;
+ else
+ // a value of 0 means we determine this based on the bits per pixel
+ if (bitsPerPixel < 16) actualColorsUsed = 1 << bitsPerPixel;
+ else actualColorsUsed = 0; // no palette
+ }
+
+ protected void getPalette() throws IOException
+ {
+ noOfEntries = actualColorsUsed;
+ //IJ.write("noOfEntries: " + noOfEntries);
+ if (noOfEntries > 0)
+ {
+ r = new byte[noOfEntries];
+ g = new byte[noOfEntries];
+ b = new byte[noOfEntries];
+ int reserved;
+ for (int i = 0; i < noOfEntries; i++)
+ {
+ b[i] = (byte) is.read();
+ g[i] = (byte) is.read();
+ r[i] = (byte) is.read();
+ reserved = is.read();
+ curPos += 4;
+ }
+ }
+ }
+
+ protected void unpack(byte[] rawData, int rawOffset, int[] intData, int intOffset, int w)
+ {
+ int j = intOffset;
+ int k = rawOffset;
+ int mask = 0xff;
+ for (int i = 0; i < w; i++)
+ {
+ int b0 = (((int) (rawData[k++])) & mask);
+ int b1 = (((int) (rawData[k++])) & mask) << 8;
+ int b2 = (((int) (rawData[k++])) & mask) << 16;
+ intData[j] = 0xff000000 | b0 | b1 | b2;
+ j++;
+ }
+ }
+
+ protected void unpack(byte[] rawData, int rawOffset, int bpp, byte[] byteData, int byteOffset, int w) throws Exception
+ {
+ int j = byteOffset;
+ int k = rawOffset;
+ byte mask;
+ int pixPerByte;
+ switch (bpp)
+ {
+ case 1:
+ mask = (byte) 0x01;
+ pixPerByte = 8;
+ break;
+ case 4:
+ mask = (byte) 0x0f;
+ pixPerByte = 2;
+ break;
+ case 8:
+ mask = (byte) 0xff;
+ pixPerByte = 1;
+ break;
+ default:
+ throw new Exception("Unsupported bits-per-pixel value");
+ }
+ for (int i = 0;;)
+ {
+ int shift = 8 - bpp;
+ for (int ii = 0; ii < pixPerByte; ii++)
+ {
+ byte br = rawData[k];
+ br >>= shift;
+ byteData[j] = (byte) (br & mask);
+ //System.out.println("Setting byteData[" + j + "]=" + Test.byteToHex(byteData[j]));
+ j++;
+ i++;
+ if (i == w) return;
+ shift -= bpp;
+ }
+ k++;
+ }
+ }
+
+ protected int readScanLine(byte[] b, int off, int len) throws IOException
+ {
+ int bytesRead = 0;
+ int l = len;
+ int r = 0;
+ while (len > 0)
+ {
+ bytesRead = is.read(b, off, len);
+ if (bytesRead == -1) return r == 0 ? -1 : r;
+ if (bytesRead == len) return l;
+ len -= bytesRead;
+ off += bytesRead;
+ r += bytesRead;
+ }
+ return l;
+ }
+
+ protected void getPixelData() throws IOException, Exception
+ {
+ byte[] rawData; // the raw unpacked data
+ // Skip to the start of the bitmap data (if we are not already there)
+ long skip = bitmapOffset - curPos;
+ if (skip > 0)
+ {
+ is.skip(skip);
+ curPos += skip;
+ }
+ int len = scanLineSize;
+ if (bitsPerPixel > 8) intData = new int[width * height];
+ else byteData = new byte[width * height];
+ rawData = new byte[actualSizeOfBitmap];
+ int rawOffset = 0;
+ int offset = (height - 1) * width;
+ for (int i = height - 1; i >= 0; i--)
+ {
+ int n = readScanLine(rawData, rawOffset, len);
+ if (n < len) throw new Exception("Scan line ended prematurely after " + n + " bytes");
+ if (bitsPerPixel > 8)
+ {
+ // Unpack and create one int per pixel
+ unpack(rawData, rawOffset, intData, offset, width);
+ }
+ else
+ {
+ // Unpack and create one byte per pixel
+ unpack(rawData, rawOffset, bitsPerPixel, byteData, offset, width);
+ }
+ rawOffset += len;
+ offset -= width;
+ }
+ }
+
+ public void read(InputStream is) throws IOException, Exception
+ {
+ this.is = is;
+ getFileHeader();
+ getBitmapHeader();
+ if (compression != 0) throw new Exception("BMP Compression not supported");
+ getPalette();
+ getPixelData();
+ }
+
+ public MemoryImageSource getImageSource()
+ {
+ ColorModel cm;
+ MemoryImageSource mis;
+ if (noOfEntries > 0)
+ {
+ // There is a color palette; create an IndexColorModel
+ cm = new IndexColorModel(bitsPerPixel, noOfEntries, r, g, b);
+ }
+ else
+ {
+ // There is no palette; use the default RGB color model
+ cm = ColorModel.getRGBdefault();
+ }
+ // Create MemoryImageSource
+ if (bitsPerPixel > 8)
+ {
+ // use one int per pixel
+ mis = new MemoryImageSource(width, height, cm, intData, 0, width);
+ }
+ else
+ {
+ // use one byte per pixel
+ mis = new MemoryImageSource(width, height, cm, byteData, 0, width);
+ }
+ return mis; // this can be used by JComponent.createImage()
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/Config.java b/java/src/javazoom/jlgui/player/amp/util/Config.java
new file mode 100644
index 0000000..e8f0d35
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/Config.java
@@ -0,0 +1,711 @@
+/*
+ * Config.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util;
+
+import java.io.File;
+import java.util.StringTokenizer;
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
+import javazoom.jlgui.player.amp.util.ini.Configuration;
+
+/**
+ * This class provides all parameters for jlGui coming from a file.
+ */
+public class Config
+{
+ public static String[] protocols = { "http:", "file:", "ftp:", "https:", "ftps:", "jar:" };
+ public static String TAGINFO_POLICY_FILE = "file";
+ public static String TAGINFO_POLICY_ALL = "all";
+ public static String TAGINFO_POLICY_NONE = "none";
+ private static String CONFIG_FILE_NAME = "jlgui.ini";
+ private Configuration _config = null;
+ // configuration keys
+ private static final String LAST_URL = "last_url",
+ LAST_DIR = "last_dir",
+ ORIGINE_X = "origine_x",
+ ORIGINE_Y = "origine_y",
+ LAST_SKIN = "last_skin",
+ LAST_SKIN_DIR = "last_skin_dir",
+ EXTENSIONS = "allowed_extensions",
+ PLAYLIST_IMPL = "playlist_impl",
+ TAGINFO_MPEG_IMPL = "taginfo_mpeg_impl",
+ TAGINFO_OGGVORBIS_IMPL = "taginfo_oggvorbis_impl",
+ TAGINFO_APE_IMPL = "taginfo_ape_impl",
+ TAGINFO_FLAC_IMPL = "taginfo_flac_impl",
+ LAST_PLAYLIST = "last_playlist",
+ PROXY_SERVER = "proxy_server",
+ PROXY_PORT = "proxy_port",
+ PROXY_LOGIN = "proxy_login",
+ PROXY_PASSWORD = "proxy_password",
+ PLAYLIST_ENABLED = "playlist_enabled",
+ SHUFFLE_ENABLED = "shuffle_enabled",
+ REPEAT_ENABLED = "repeat_enabled",
+ EQUALIZER_ENABLED = "equalizer_enabled",
+ EQUALIZER_ON = "equalizer_on",
+ EQUALIZER_AUTO = "equalizer_auto",
+ LAST_EQUALIZER = "last_equalizer",
+ SCREEN_LIMIT = "screen_limit",
+ TAGINFO_POLICY = "taginfo_policy",
+ VOLUME_VALUE = "volume_value",
+ AUDIO_DEVICE = "audio_device",
+ VISUAL_MODE = "visual_mode";
+
+ private static Config _instance = null;
+ private String _audioDevice = "";
+ private String _visualMode = "";
+ private String _extensions = "m3u,pls,wsz,snd,aifc,aif,wav,au,mp1,mp2,mp3,ogg,spx,flac,ape,mac";
+ private String _lastUrl = "";
+ private String _lastDir = "";
+ private String _lastSkinDir = "";
+ private String _lastEqualizer = "";
+ private String _defaultSkin = "";
+ private String _playlist = "javazoom.jlgui.player.amp.playlist.BasePlaylist";
+ private String _taginfoMpeg = "javazoom.jlgui.player.amp.tag.MpegInfo";
+ private String _taginfoOggVorbis = "javazoom.jlgui.player.amp.tag.OggVorbisInfo";
+ private String _taginfoAPE = "javazoom.jlgui.player.amp.tag.APEInfo";
+ private String _taginfoFlac = "javazoom.jlgui.player.amp.tag.FlacInfo";
+ private String _playlistFilename = "";
+ private int _x = 0;
+ private int _y = 0;
+ private String _proxyServer = "";
+ private String _proxyLogin = "";
+ private String _proxyPassword = "";
+ private int _proxyPort = -1;
+ private int _volume = -1;
+ private boolean _playlistEnabled = false;
+ private boolean _shuffleEnabled = false;
+ private boolean _repeatEnabled = false;
+ private boolean _equalizerEnabled = false;
+ private boolean _equalizerOn = false;
+ private boolean _equalizerAuto = false;
+ private boolean _screenLimit = false;
+ private String _taginfoPolicy = TAGINFO_POLICY_FILE;
+
+ private JFrame topParent = null;
+ private ImageIcon iconParent = null;
+
+ private Config()
+ {
+ }
+
+ /**
+ * Returns Config instance.
+ */
+ public synchronized static Config getInstance()
+ {
+ if (_instance == null)
+ {
+ _instance = new Config();
+ }
+ return _instance;
+ }
+
+ public void setTopParent(JFrame frame)
+ {
+ topParent = frame;
+ }
+
+ public JFrame getTopParent()
+ {
+ if (topParent == null)
+ {
+ topParent = new JFrame();
+ }
+ return topParent;
+ }
+
+ public void setIconParent(ImageIcon icon)
+ {
+ iconParent = icon;
+ }
+
+ public ImageIcon getIconParent()
+ {
+ return iconParent;
+ }
+
+ /**
+ * Returns JavaSound audio device.
+ * @return String
+ */
+ public String getAudioDevice()
+ {
+ return _audioDevice;
+ }
+
+ /**
+ * Set JavaSound audio device.
+ * @param dev String
+ */
+ public void setAudioDevice(String dev)
+ {
+ _audioDevice = dev;
+ }
+
+ /**
+ * Return visual mode.
+ * @return
+ */
+ public String getVisualMode()
+ {
+ return _visualMode;
+ }
+
+ /**
+ * Set visual mode.
+ * @param mode
+ */
+ public void setVisualMode(String mode)
+ {
+ _visualMode = mode;
+ }
+
+ /**
+ * Returns playlist filename.
+ */
+ public String getPlaylistFilename()
+ {
+ return _playlistFilename;
+ }
+
+ /**
+ * Sets playlist filename.
+ */
+ public void setPlaylistFilename(String pl)
+ {
+ _playlistFilename = pl;
+ }
+
+ /**
+ * Returns last equalizer values.
+ */
+ public int[] getLastEqualizer()
+ {
+ int[] vals = null;
+ if ((_lastEqualizer != null) && (!_lastEqualizer.equals("")))
+ {
+ vals = new int[11];
+ int i = 0;
+ StringTokenizer st = new StringTokenizer(_lastEqualizer, ",");
+ while (st.hasMoreTokens())
+ {
+ String v = st.nextToken();
+ vals[i++] = Integer.parseInt(v);
+ }
+ }
+ return vals;
+ }
+
+ /**
+ * Sets last equalizer values.
+ */
+ public void setLastEqualizer(int[] vals)
+ {
+ if (vals != null)
+ {
+ String dump = "";
+ for (int i = 0; i < vals.length; i++)
+ {
+ dump = dump + vals[i] + ",";
+ }
+ _lastEqualizer = dump.substring(0, (dump.length() - 1));
+ }
+ }
+
+ /**
+ * Return screen limit flag.
+ *
+ * @return is screen limit flag
+ */
+ public boolean isScreenLimit()
+ {
+ return _screenLimit;
+ }
+
+ /**
+ * Set screen limit flag.
+ *
+ * @param b
+ */
+ public void setScreenLimit(boolean b)
+ {
+ _screenLimit = b;
+ }
+
+ /**
+ * Returns last URL.
+ */
+ public String getLastURL()
+ {
+ return _lastUrl;
+ }
+
+ /**
+ * Sets last URL.
+ */
+ public void setLastURL(String url)
+ {
+ _lastUrl = url;
+ }
+
+ /**
+ * Returns last Directory.
+ */
+ public String getLastDir()
+ {
+ if ((_lastDir != null) && (!_lastDir.endsWith(File.separator)))
+ {
+ _lastDir = _lastDir + File.separator;
+ }
+ return _lastDir;
+ }
+
+ /**
+ * Sets last Directory.
+ */
+ public void setLastDir(String dir)
+ {
+ _lastDir = dir;
+ if ((_lastDir != null) && (!_lastDir.endsWith(File.separator)))
+ {
+ _lastDir = _lastDir + File.separator;
+ }
+ }
+
+ /**
+ * Returns last skin directory.
+ */
+ public String getLastSkinDir()
+ {
+ if ((_lastSkinDir != null) && (!_lastSkinDir.endsWith(File.separator)))
+ {
+ _lastSkinDir = _lastSkinDir + File.separator;
+ }
+ return _lastSkinDir;
+ }
+
+ /**
+ * Sets last skin directory.
+ */
+ public void setLastSkinDir(String dir)
+ {
+ _lastSkinDir = dir;
+ if ((_lastSkinDir != null) && (!_lastSkinDir.endsWith(File.separator)))
+ {
+ _lastSkinDir = _lastSkinDir + File.separator;
+ }
+ }
+
+ /**
+ * Returns audio extensions.
+ */
+ public String getExtensions()
+ {
+ return _extensions;
+ }
+
+ /**
+ * Returns proxy server.
+ */
+ public String getProxyServer()
+ {
+ return _proxyServer;
+ }
+
+ /**
+ * Returns proxy port.
+ */
+ public int getProxyPort()
+ {
+ return _proxyPort;
+ }
+
+ /**
+ * Returns volume value.
+ */
+ public int getVolume()
+ {
+ return _volume;
+ }
+
+ /**
+ * Returns volume value.
+ */
+ public void setVolume(int vol)
+ {
+ _volume = vol;
+ }
+
+ /**
+ * Returns X location.
+ */
+ public int getXLocation()
+ {
+ return _x;
+ }
+
+ /**
+ * Returns Y location.
+ */
+ public int getYLocation()
+ {
+ return _y;
+ }
+
+ /**
+ * Sets X,Y location.
+ */
+ public void setLocation(int x, int y)
+ {
+ _x = x;
+ _y = y;
+ }
+
+ /**
+ * Sets Proxy info.
+ */
+ public void setProxy(String url, int port, String login, String password)
+ {
+ _proxyServer = url;
+ _proxyPort = port;
+ _proxyLogin = login;
+ _proxyPassword = password;
+ }
+
+ /**
+ * Enables Proxy.
+ */
+ public boolean enableProxy()
+ {
+ if ((_proxyServer != null) && (!_proxyServer.equals("")))
+ {
+ System.getProperties().put("proxySet", "true");
+ System.getProperties().put("proxyHost", _proxyServer);
+ System.getProperties().put("proxyPort", "" + _proxyPort);
+ return true;
+ }
+ else return false;
+ }
+
+ /**
+ * Returns PlaylistUI state.
+ */
+ public boolean isPlaylistEnabled()
+ {
+ return _playlistEnabled;
+ }
+
+ /**
+ * Sets PlaylistUI state.
+ */
+ public void setPlaylistEnabled(boolean ena)
+ {
+ _playlistEnabled = ena;
+ }
+
+ /**
+ * Returns ShuffleUI state.
+ */
+ public boolean isShuffleEnabled()
+ {
+ return _shuffleEnabled;
+ }
+
+ /**
+ * Sets ShuffleUI state.
+ */
+ public void setShuffleEnabled(boolean ena)
+ {
+ _shuffleEnabled = ena;
+ }
+
+ /**
+ * Returns RepeatUI state.
+ */
+ public boolean isRepeatEnabled()
+ {
+ return _repeatEnabled;
+ }
+
+ /**
+ * Sets RepeatUI state.
+ */
+ public void setRepeatEnabled(boolean ena)
+ {
+ _repeatEnabled = ena;
+ }
+
+ /**
+ * Returns EqualizerUI state.
+ */
+ public boolean isEqualizerEnabled()
+ {
+ return _equalizerEnabled;
+ }
+
+ /**
+ * Sets EqualizerUI state.
+ */
+ public void setEqualizerEnabled(boolean ena)
+ {
+ _equalizerEnabled = ena;
+ }
+
+ /**
+ * Returns default skin.
+ */
+ public String getDefaultSkin()
+ {
+ return _defaultSkin;
+ }
+
+ /**
+ * Sets default skin.
+ */
+ public void setDefaultSkin(String skin)
+ {
+ _defaultSkin = skin;
+ }
+
+ /**
+ * Returns playlist classname implementation.
+ */
+ public String getPlaylistClassName()
+ {
+ return _playlist;
+ }
+
+ /**
+ * Set playlist classname implementation.
+ */
+ public void setPlaylistClassName(String s)
+ {
+ _playlist = s;
+ }
+
+ /**
+ * Returns Mpeg TagInfo classname implementation.
+ */
+ public String getMpegTagInfoClassName()
+ {
+ return _taginfoMpeg;
+ }
+
+ /**
+ * Returns Ogg Vorbis TagInfo classname implementation.
+ */
+ public String getOggVorbisTagInfoClassName()
+ {
+ return _taginfoOggVorbis;
+ }
+
+ /**
+ * Returns APE TagInfo classname implementation.
+ */
+ public String getAPETagInfoClassName()
+ {
+ return _taginfoAPE;
+ }
+
+ /**
+ * Returns Ogg Vorbis TagInfo classname implementation.
+ */
+ public String getFlacTagInfoClassName()
+ {
+ return _taginfoFlac;
+ }
+
+ /**
+ * Loads configuration for the specified file.
+ */
+ public void load(String configfile)
+ {
+ CONFIG_FILE_NAME = configfile;
+ load();
+ }
+
+ /**
+ * Loads configuration.
+ */
+ public void load()
+ {
+ _config = new Configuration(CONFIG_FILE_NAME);
+ // Creates config entries if needed.
+ if (_config.get(AUDIO_DEVICE) == null) _config.add(AUDIO_DEVICE, _audioDevice);
+ if (_config.get(VISUAL_MODE) == null) _config.add(VISUAL_MODE, _visualMode);
+ if (_config.get(LAST_URL) == null) _config.add(LAST_URL, _lastUrl);
+ if (_config.get(LAST_EQUALIZER) == null) _config.add(LAST_EQUALIZER, _lastEqualizer);
+ if (_config.get(LAST_DIR) == null) _config.add(LAST_DIR, _lastDir);
+ if (_config.get(LAST_SKIN_DIR) == null) _config.add(LAST_SKIN_DIR, _lastSkinDir);
+ if (_config.get(TAGINFO_POLICY) == null) _config.add(TAGINFO_POLICY, _taginfoPolicy);
+ if (_config.getInt(ORIGINE_X) == -1) _config.add(ORIGINE_X, _x);
+ if (_config.getInt(ORIGINE_Y) == -1) _config.add(ORIGINE_Y, _y);
+ if (_config.get(LAST_SKIN) == null) _config.add(LAST_SKIN, _defaultSkin);
+ if (_config.get(LAST_PLAYLIST) == null) _config.add(LAST_PLAYLIST, _playlistFilename);
+ if (_config.get(PLAYLIST_IMPL) == null) _config.add(PLAYLIST_IMPL, _playlist);
+ if (_config.get(TAGINFO_MPEG_IMPL) == null) _config.add(TAGINFO_MPEG_IMPL, _taginfoMpeg);
+ if (_config.get(TAGINFO_OGGVORBIS_IMPL) == null) _config.add(TAGINFO_OGGVORBIS_IMPL, _taginfoOggVorbis);
+ if (_config.get(TAGINFO_APE_IMPL) == null) _config.add(TAGINFO_APE_IMPL, _taginfoAPE);
+ if (_config.get(TAGINFO_FLAC_IMPL) == null) _config.add(TAGINFO_FLAC_IMPL, _taginfoFlac);
+ if (_config.get(EXTENSIONS) == null) _config.add(EXTENSIONS, _extensions);
+ if (_config.get(PROXY_SERVER) == null) _config.add(PROXY_SERVER, _proxyServer);
+ if (_config.getInt(PROXY_PORT) == -1) _config.add(PROXY_PORT, _proxyPort);
+ if (_config.getInt(VOLUME_VALUE) == -1) _config.add(VOLUME_VALUE, _volume);
+ if (_config.get(PROXY_LOGIN) == null) _config.add(PROXY_LOGIN, _proxyLogin);
+ if (_config.get(PROXY_PASSWORD) == null) _config.add(PROXY_PASSWORD, _proxyPassword);
+ if (!_config.getBoolean(PLAYLIST_ENABLED)) _config.add(PLAYLIST_ENABLED, _playlistEnabled);
+ if (!_config.getBoolean(SHUFFLE_ENABLED)) _config.add(SHUFFLE_ENABLED, _shuffleEnabled);
+ if (!_config.getBoolean(REPEAT_ENABLED)) _config.add(REPEAT_ENABLED, _repeatEnabled);
+ if (!_config.getBoolean(EQUALIZER_ENABLED)) _config.add(EQUALIZER_ENABLED, _equalizerEnabled);
+ if (!_config.getBoolean(EQUALIZER_ON)) _config.add(EQUALIZER_ON, _equalizerOn);
+ if (!_config.getBoolean(EQUALIZER_AUTO)) _config.add(EQUALIZER_AUTO, _equalizerAuto);
+ if (!_config.getBoolean(SCREEN_LIMIT)) _config.add(SCREEN_LIMIT, _screenLimit);
+ // Reads config entries
+ _audioDevice = _config.get(AUDIO_DEVICE, _audioDevice);
+ _visualMode = _config.get(VISUAL_MODE, _visualMode);
+ _lastUrl = _config.get(LAST_URL, _lastUrl);
+ _lastEqualizer = _config.get(LAST_EQUALIZER, _lastEqualizer);
+ _lastDir = _config.get(LAST_DIR, _lastDir);
+ _lastSkinDir = _config.get(LAST_SKIN_DIR, _lastSkinDir);
+ _x = _config.getInt(ORIGINE_X, _x);
+ _y = _config.getInt(ORIGINE_Y, _y);
+ _defaultSkin = _config.get(LAST_SKIN, _defaultSkin);
+ _playlistFilename = _config.get(LAST_PLAYLIST, _playlistFilename);
+ _taginfoPolicy = _config.get(TAGINFO_POLICY, _taginfoPolicy);
+ _extensions = _config.get(EXTENSIONS, _extensions);
+ _playlist = _config.get(PLAYLIST_IMPL, _playlist);
+ _taginfoMpeg = _config.get(TAGINFO_MPEG_IMPL, _taginfoMpeg);
+ _taginfoOggVorbis = _config.get(TAGINFO_OGGVORBIS_IMPL, _taginfoOggVorbis);
+ _taginfoAPE = _config.get(TAGINFO_APE_IMPL, _taginfoAPE);
+ _taginfoFlac = _config.get(TAGINFO_FLAC_IMPL, _taginfoFlac);
+ _proxyServer = _config.get(PROXY_SERVER, _proxyServer);
+ _proxyPort = _config.getInt(PROXY_PORT, _proxyPort);
+ _volume = _config.getInt(VOLUME_VALUE, _volume);
+ _proxyLogin = _config.get(PROXY_LOGIN, _proxyLogin);
+ _proxyPassword = _config.get(PROXY_PASSWORD, _proxyPassword);
+ _playlistEnabled = _config.getBoolean(PLAYLIST_ENABLED, _playlistEnabled);
+ _shuffleEnabled = _config.getBoolean(SHUFFLE_ENABLED, _shuffleEnabled);
+ _repeatEnabled = _config.getBoolean(REPEAT_ENABLED, _repeatEnabled);
+ _equalizerEnabled = _config.getBoolean(EQUALIZER_ENABLED, _equalizerEnabled);
+ _equalizerOn = _config.getBoolean(EQUALIZER_ON, _equalizerOn);
+ _equalizerAuto = _config.getBoolean(EQUALIZER_AUTO, _equalizerAuto);
+ _screenLimit = _config.getBoolean(SCREEN_LIMIT, _screenLimit);
+ }
+
+ /**
+ * Saves configuration.
+ */
+ public void save()
+ {
+ if (_config != null)
+ {
+ _config.add(ORIGINE_X, _x);
+ _config.add(ORIGINE_Y, _y);
+ if (_lastDir != null) _config.add(LAST_DIR, _lastDir);
+ if (_lastSkinDir != null) _config.add(LAST_SKIN_DIR, _lastSkinDir);
+ if (_audioDevice != null) _config.add(AUDIO_DEVICE, _audioDevice);
+ if (_visualMode != null) _config.add(VISUAL_MODE, _visualMode);
+ if (_lastUrl != null) _config.add(LAST_URL, _lastUrl);
+ if (_lastEqualizer != null) _config.add(LAST_EQUALIZER, _lastEqualizer);
+ if (_playlistFilename != null) _config.add(LAST_PLAYLIST, _playlistFilename);
+ if (_playlist != null) _config.add(PLAYLIST_IMPL, _playlist);
+ if (_defaultSkin != null) _config.add(LAST_SKIN, _defaultSkin);
+ if (_taginfoPolicy != null) _config.add(TAGINFO_POLICY, _taginfoPolicy);
+ if (_volume != -1) _config.add(VOLUME_VALUE, _volume);
+ _config.add(PLAYLIST_ENABLED, _playlistEnabled);
+ _config.add(SHUFFLE_ENABLED, _shuffleEnabled);
+ _config.add(REPEAT_ENABLED, _repeatEnabled);
+ _config.add(EQUALIZER_ENABLED, _equalizerEnabled);
+ _config.add(EQUALIZER_ON, _equalizerOn);
+ _config.add(EQUALIZER_AUTO, _equalizerAuto);
+ _config.add(SCREEN_LIMIT, _screenLimit);
+ _config.save();
+ }
+ }
+
+ /**
+ * @return equalizer auto flag
+ */
+ public boolean isEqualizerAuto()
+ {
+ return _equalizerAuto;
+ }
+
+ /**
+ * @return equalizer on flag
+ */
+ public boolean isEqualizerOn()
+ {
+ return _equalizerOn;
+ }
+
+ /**
+ * @param b
+ */
+ public void setEqualizerAuto(boolean b)
+ {
+ _equalizerAuto = b;
+ }
+
+ /**
+ * @param b
+ */
+ public void setEqualizerOn(boolean b)
+ {
+ _equalizerOn = b;
+ }
+
+ public static boolean startWithProtocol(String input)
+ {
+ boolean ret = false;
+ if (input != null)
+ {
+ input = input.toLowerCase();
+ for (int i = 0; i < protocols.length; i++)
+ {
+ if (input.startsWith(protocols[i]))
+ {
+ ret = true;
+ break;
+ }
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * @return tag info policy
+ */
+ public String getTaginfoPolicy()
+ {
+ return _taginfoPolicy;
+ }
+
+ /**
+ * @param string
+ */
+ public void setTaginfoPolicy(String string)
+ {
+ _taginfoPolicy = string;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/FileNameFilter.java b/java/src/javazoom/jlgui/player/amp/util/FileNameFilter.java
new file mode 100644
index 0000000..4a0685a
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/FileNameFilter.java
@@ -0,0 +1,108 @@
+/*
+ * FileNameFilter.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+/**
+ * FileName filter that works for both javax.swing.filechooser and java.io.
+ */
+public class FileNameFilter extends javax.swing.filechooser.FileFilter implements java.io.FileFilter
+{
+ protected java.util.List extensions = new ArrayList();
+ protected String default_extension = null;
+ protected String description;
+ protected boolean allowDir = true;
+
+ /**
+ * Constructs the list of extensions out of a string of comma-separated
+ * elements, each of which represents one extension.
+ *
+ * @param ext the list of comma-separated extensions
+ */
+ public FileNameFilter(String ext, String description)
+ {
+ this(ext, description, true);
+ }
+
+ public FileNameFilter(String ext, String description, boolean allowDir)
+ {
+ this.description = description;
+ this.allowDir = allowDir;
+ StringTokenizer st = new StringTokenizer(ext, ", ");
+ String extension;
+ while (st.hasMoreTokens())
+ {
+ extension = st.nextToken();
+ extensions.add(extension);
+ if (default_extension == null) default_extension = extension;
+ }
+ }
+
+ /**
+ * determines if the filename is an acceptable one. If a
+ * filename ends with one of the extensions the filter was
+ * initialized with, then the function returns true. if not,
+ * the function returns false.
+ *
+ * @param dir the directory the file is in
+ * @return true if the filename has a valid extension, false otherwise
+ */
+ public boolean accept(File dir)
+ {
+ for (int i = 0; i < extensions.size(); i++)
+ {
+ if (allowDir)
+ {
+ if (dir.isDirectory() || dir.getName().endsWith("." + (String) extensions.get(i))) return true;
+ }
+ else
+ {
+ if (dir.getName().endsWith("." + (String) extensions.get(i))) return true;
+ }
+ }
+ return extensions.size() == 0;
+ }
+
+ /**
+ * Returns the default extension.
+ *
+ * @return the default extension
+ */
+ public String getDefaultExtension()
+ {
+ return default_extension;
+ }
+
+ public void setDefaultExtension(String ext)
+ {
+ default_extension = ext;
+ }
+
+ public String getDescription()
+ {
+ return description;
+ }
+}
\ No newline at end of file
diff --git a/java/src/javazoom/jlgui/player/amp/util/FileSelector.java b/java/src/javazoom/jlgui/player/amp/util/FileSelector.java
new file mode 100644
index 0000000..be2bdd9
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/FileSelector.java
@@ -0,0 +1,156 @@
+/*
+ * FileSelector.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util;
+
+import java.io.File;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javazoom.jlgui.player.amp.Loader;
+
+/**
+ * This class is used to select a file or directory for loading or saving.
+ */
+public class FileSelector
+{
+ public static final int OPEN = 1;
+ public static final int SAVE = 2;
+ public static final int SAVE_AS = 3;
+ public static final int DIRECTORY = 4;
+ private File[] files = null;
+ private File directory = null;
+ private static FileSelector instance = null;
+
+ public File[] getFiles()
+ {
+ return files;
+ }
+
+ public File getDirectory()
+ {
+ return directory;
+ }
+
+ public static final FileSelector getInstance()
+ {
+ if (instance == null) instance = new FileSelector();
+ return instance;
+ }
+
+ /**
+ * Opens a dialog box so that the user can search for a file
+ * with the given extension and returns the filename selected.
+ *
+ * @param extensions the extension of the filename to be selected,
+ * or "" if any filename can be used
+ * @param directory the folder to be put in the starting directory
+ * @param mode the action that will be performed on the file, used to tell what
+ * files are valid
+ * @return the selected file
+ */
+ public static File[] selectFile(Loader loader, int mode, boolean multiple, String extensions, String description, File directory)
+ {
+ return selectFile(loader, mode, multiple, null, extensions, description, null, directory);
+ }
+
+ /**
+ * Opens a dialog box so that the user can search for a file
+ * with the given extension and returns the filename selected.
+ *
+ * @param extensions the extension of the filename to be selected,
+ * or "" if any filename can be used
+ * @param titlePrefix the string to be put in the title, followed by : SaveAs
+ * @param mode the action that will be performed on the file, used to tell what
+ * files are valid
+ * @param defaultFile the default file
+ * @param directory the string to be put in the starting directory
+ * @return the selected filename
+ */
+ public static File[] selectFile(Loader loader, int mode, boolean multiple, File defaultFile, String extensions, String description, String titlePrefix, File directory)
+ {
+ JFrame mainWindow = null;
+ if (loader instanceof JFrame)
+ {
+ mainWindow = (JFrame) loader;
+ }
+ JFileChooser filePanel = new JFileChooser();
+ StringBuffer windowTitle = new StringBuffer();
+ if (titlePrefix != null && titlePrefix.length() > 0) windowTitle.append(titlePrefix).append(": ");
+ switch (mode)
+ {
+ case OPEN:
+ windowTitle.append("Open");
+ break;
+ case SAVE:
+ windowTitle.append("Save");
+ break;
+ case SAVE_AS:
+ windowTitle.append("Save As");
+ break;
+ case DIRECTORY:
+ windowTitle.append("Choose Directory");
+ break;
+ }
+ filePanel.setDialogTitle(windowTitle.toString());
+ FileNameFilter filter = new FileNameFilter(extensions, description);
+ filePanel.setFileFilter(filter);
+ if (defaultFile != null) filePanel.setSelectedFile(defaultFile);
+ if (directory != null) filePanel.setCurrentDirectory(directory);
+ filePanel.setMultiSelectionEnabled(multiple);
+ int retVal = -1;
+ switch (mode)
+ {
+ case OPEN:
+ filePanel.setDialogType(JFileChooser.OPEN_DIALOG);
+ retVal = filePanel.showOpenDialog(mainWindow);
+ break;
+ case SAVE:
+ filePanel.setDialogType(JFileChooser.SAVE_DIALOG);
+ retVal = filePanel.showSaveDialog(mainWindow);
+ break;
+ case SAVE_AS:
+ filePanel.setDialogType(JFileChooser.SAVE_DIALOG);
+ retVal = filePanel.showSaveDialog(mainWindow);
+ break;
+ case DIRECTORY:
+ filePanel.setDialogType(JFileChooser.SAVE_DIALOG);
+ filePanel.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ retVal = filePanel.showDialog(mainWindow, "Select");
+ break;
+ }
+ if (retVal == JFileChooser.APPROVE_OPTION)
+ {
+ if (multiple) getInstance().files = filePanel.getSelectedFiles();
+ else
+ {
+ getInstance().files = new File[1];
+ getInstance().files[0] = filePanel.getSelectedFile();
+ }
+ getInstance().directory = filePanel.getCurrentDirectory();
+ }
+ else
+ {
+ getInstance().files = null;
+ }
+ return getInstance().files;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/FileUtil.java b/java/src/javazoom/jlgui/player/amp/util/FileUtil.java
new file mode 100644
index 0000000..34a33ba
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/FileUtil.java
@@ -0,0 +1,167 @@
+/*
+ * FileUtil.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * @author Scott Pennell
+ */
+public class FileUtil
+{
+ private static List supportedExtensions = null;
+
+ public static File[] findFilesRecursively(File directory)
+ {
+ if (directory.isFile())
+ {
+ File[] f = new File[1];
+ f[0] = directory;
+ return f;
+ }
+ List list = new ArrayList();
+ addSongsRecursive(list, directory);
+ return ((File[]) list.toArray(new File[list.size()]));
+ }
+
+ private static void addSongsRecursive(List found, File rootDir)
+ {
+ if (rootDir == null) return; // we do not want waste time
+ File[] files = rootDir.listFiles();
+ if (files == null) return;
+ for (int i = 0; i < files.length; i++)
+ {
+ File file = new File(rootDir, files[i].getName());
+ if (file.isDirectory()) addSongsRecursive(found, file);
+ else
+ {
+ if (isMusicFile(files[i]))
+ {
+ found.add(file);
+ }
+ }
+ }
+ }
+
+ public static boolean isMusicFile(File f)
+ {
+ List exts = getSupportedExtensions();
+ int sz = exts.size();
+ String ext;
+ String name = f.getName();
+ for (int i = 0; i < sz; i++)
+ {
+ ext = (String) exts.get(i);
+ if (ext.equals(".wsz") || ext.equals(".m3u")) continue;
+ if (name.endsWith(ext)) return true;
+ }
+ return false;
+ }
+
+ public static List getSupportedExtensions()
+ {
+ if (supportedExtensions == null)
+ {
+ String ext = Config.getInstance().getExtensions();
+ StringTokenizer st = new StringTokenizer(ext, ",");
+ supportedExtensions = new ArrayList();
+ while (st.hasMoreTokens())
+ supportedExtensions.add("." + st.nextElement());
+ }
+ return (supportedExtensions);
+ }
+
+ public static String getSupprtedExtensions()
+ {
+ List exts = getSupportedExtensions();
+ StringBuffer s = new StringBuffer();
+ int sz = exts.size();
+ String ext;
+ for (int i = 0; i < sz; i++)
+ {
+ ext = (String) exts.get(i);
+ if (ext.equals(".wsz") || ext.equals(".m3u")) continue;
+ if (i == 0) s.append(ext);
+ else s.append(";").append(ext);
+ }
+ return s.toString();
+ }
+
+ public static String padString(String s, int length)
+ {
+ return padString(s, ' ', length);
+ }
+
+ public static String padString(String s, char padChar, int length)
+ {
+ int slen, numPads = 0;
+ if (s == null)
+ {
+ s = "";
+ numPads = length;
+ }
+ else if ((slen = s.length()) > length)
+ {
+ s = s.substring(0, length);
+ }
+ else if (slen < length)
+ {
+ numPads = length - slen;
+ }
+ if (numPads == 0) return s;
+ char[] c = new char[numPads];
+ Arrays.fill(c, padChar);
+ return s + new String(c);
+ }
+
+ public static String rightPadString(String s, int length)
+ {
+ return (rightPadString(s, ' ', length));
+ }
+
+ public static String rightPadString(String s, char padChar, int length)
+ {
+ int slen, numPads = 0;
+ if (s == null)
+ {
+ s = "";
+ numPads = length;
+ }
+ else if ((slen = s.length()) > length)
+ {
+ s = s.substring(length);
+ }
+ else if (slen < length)
+ {
+ numPads = length - slen;
+ }
+ if (numPads == 0) return (s);
+ char[] c = new char[numPads];
+ Arrays.fill(c, padChar);
+ return new String(c) + s;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ini/Alphabetizer.java b/java/src/javazoom/jlgui/player/amp/util/ini/Alphabetizer.java
new file mode 100644
index 0000000..ac016a3
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ini/Alphabetizer.java
@@ -0,0 +1,79 @@
+/*
+ * Alphabetizer.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ini;
+
+/**
+ * This class alphabetizes strings.
+ *
+ * @author Matt "Spiked Bat" Segur
+ */
+public class Alphabetizer
+{
+ public static boolean lessThan(String str1, String str2)
+ {
+ return compare(str1, str2) < 0;
+ }
+
+ public static boolean greaterThan(String str1, String str2)
+ {
+ return compare(str1, str2) > 0;
+ }
+
+ public static boolean equalTo(String str1, String str2)
+ {
+ return compare(str1, str2) == 0;
+ }
+
+ /**
+ * Performs a case-insensitive comparison of the two strings.
+ */
+ public static int compare(String s1, String s2)
+ {
+ if (s1 == null && s2 == null) return 0;
+ else if (s1 == null) return -1;
+ else if (s2 == null) return +1;
+ int len1 = s1.length();
+ int len2 = s2.length();
+ int len = Math.min(len1, len2);
+ for (int i = 0; i < len; i++)
+ {
+ int comparison = compare(s1.charAt(i), s2.charAt(i));
+ if (comparison != 0) return comparison;
+ }
+ if (len1 < len2) return -1;
+ else if (len1 > len2) return +1;
+ else return 0;
+ }
+
+ /**
+ * Performs a case-insensitive comparison of the two characters.
+ */
+ public static int compare(char c1, char c2)
+ {
+ if (65 <= c1 && c1 <= 91) c1 += 32;
+ if (65 <= c2 && c2 <= 91) c2 += 32;
+ if (c1 < c2) return -1;
+ else if (c1 > c2) return +1;
+ else return 0;
+ }
+}
\ No newline at end of file
diff --git a/java/src/javazoom/jlgui/player/amp/util/ini/Array.java b/java/src/javazoom/jlgui/player/amp/util/ini/Array.java
new file mode 100644
index 0000000..7f1ced3
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ini/Array.java
@@ -0,0 +1,114 @@
+/*
+ * Array.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ini;
+
+/**
+ * This class represents an array of objects.
+ *
+ * @author Jeremy Cloud
+ * @version 1.0.0
+ */
+public class Array
+{
+ public static Object[] copy(Object[] sors, Object[] dest)
+ {
+ System.arraycopy(sors, 0, dest, 0, sors.length);
+ return dest;
+ }
+
+ public static String[] doubleArray(String[] sors)
+ {
+ System.out.print("** doubling string array... ");
+ int new_size = (sors.length <= 8 ? 16 : sors.length << 1);
+ String[] dest = new String[new_size];
+ System.arraycopy(sors, 0, dest, 0, sors.length);
+ System.out.println("done **.");
+ return dest;
+ }
+
+ public static int[] doubleArray(int[] sors)
+ {
+ int new_size = (sors.length < 8 ? 16 : sors.length << 1);
+ int[] dest = new int[new_size];
+ System.arraycopy(sors, 0, dest, 0, sors.length);
+ return dest;
+ }
+
+ public static int[] grow(int[] sors, double growth_rate)
+ {
+ int new_size = Math.max((int) (sors.length * growth_rate), sors.length + 1);
+ int[] dest = new int[new_size];
+ System.arraycopy(sors, 0, dest, 0, sors.length);
+ return dest;
+ }
+
+ public static boolean[] grow(boolean[] sors, double growth_rate)
+ {
+ int new_size = Math.max((int) (sors.length * growth_rate), sors.length + 1);
+ boolean[] dest = new boolean[new_size];
+ System.arraycopy(sors, 0, dest, 0, sors.length);
+ return dest;
+ }
+
+ public static Object[] grow(Object[] sors, double growth_rate)
+ {
+ int new_size = Math.max((int) (sors.length * growth_rate), sors.length + 1);
+ Object[] dest = new Object[new_size];
+ System.arraycopy(sors, 0, dest, 0, sors.length);
+ return dest;
+ }
+
+ public static String[] grow(String[] sors, double growth_rate)
+ {
+ int new_size = Math.max((int) (sors.length * growth_rate), sors.length + 1);
+ String[] dest = new String[new_size];
+ System.arraycopy(sors, 0, dest, 0, sors.length);
+ return dest;
+ }
+
+ /**
+ * @param start - inclusive
+ * @param end - exclusive
+ */
+ public static void shiftUp(Object[] array, int start, int end)
+ {
+ int count = end - start;
+ if (count > 0) System.arraycopy(array, start, array, start + 1, count);
+ }
+
+ /**
+ * @param start - inclusive
+ * @param end - exclusive
+ */
+ public static void shiftDown(Object[] array, int start, int end)
+ {
+ int count = end - start;
+ if (count > 0) System.arraycopy(array, start, array, start - 1, count);
+ }
+
+ public static void shift(Object[] array, int start, int amount)
+ {
+ int count = array.length - start - (amount > 0 ? amount : 0);
+ System.arraycopy(array, start, array, start + amount, count);
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ini/CRC32OutputStream.java b/java/src/javazoom/jlgui/player/amp/util/ini/CRC32OutputStream.java
new file mode 100644
index 0000000..c38fb91
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ini/CRC32OutputStream.java
@@ -0,0 +1,50 @@
+/*
+ * CRC32OutputStream.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ini;
+
+import java.io.OutputStream;
+import java.util.zip.CRC32;
+
+/**
+ * @author Jeremy Cloud
+ * @version 1.0.0
+ */
+public class CRC32OutputStream extends OutputStream
+{
+ private CRC32 crc;
+
+ public CRC32OutputStream()
+ {
+ crc = new CRC32();
+ }
+
+ public void write(int new_byte)
+ {
+ crc.update(new_byte);
+ }
+
+ public long getValue()
+ {
+ return crc.getValue();
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ini/Configuration.java b/java/src/javazoom/jlgui/player/amp/util/ini/Configuration.java
new file mode 100644
index 0000000..3a815e1
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ini/Configuration.java
@@ -0,0 +1,441 @@
+/*
+ * Configuration.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ini;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import javazoom.jlgui.player.amp.util.Config;
+
+/**
+ * A Configuration is used to save a set of configuration
+ * properties. The properties can be written out to disk
+ * in "name=value" form, and read back in.
+ *
+ * @author Jeremy Cloud
+ * @version 1.2.0
+ */
+public class Configuration
+{
+ private File config_file = null;
+ private URL config_url = null;
+ private Hashtable props = new Hashtable(64);
+
+ /**
+ * Constructs a new Configuration object that stores
+ * it's properties in the file with the given name.
+ */
+ public Configuration(String file_name)
+ {
+ // E.B - URL support
+ if (Config.startWithProtocol(file_name))
+ {
+ try
+ {
+ this.config_url = new URL(file_name);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ load();
+ }
+ else
+ {
+ this.config_file = new File(file_name);
+ load();
+ }
+ }
+
+ /**
+ * Constructs a new Configuration object that stores
+ * it's properties in the given file.
+ */
+ public Configuration(File config_file)
+ {
+ this.config_file = config_file;
+ load();
+ }
+
+ /**
+ * Constructs a new Configuration object that stores
+ * it's properties in the given file.
+ */
+ public Configuration(URL config_file)
+ {
+ this.config_url = config_file;
+ load();
+ }
+
+ /**
+ * Constructs a new Configuration object that doesn't
+ * have a file associated with it.
+ */
+ public Configuration()
+ {
+ this.config_file = null;
+ }
+
+ /**
+ * @return The config file.
+ */
+ public File getConfigFile()
+ {
+ return config_file;
+ }
+
+ /**
+ * Adds a the property with the given name and value.
+ *
+ * @param name The name of the property.
+ * @param value The value of the property.
+ */
+ public void add(String name, String value)
+ {
+ props.put(name, value);
+ }
+
+ /**
+ * Adds the boolean property.
+ *
+ * @param name The name of the property.
+ * @param value The value of the property.
+ */
+ public void add(String name, boolean value)
+ {
+ props.put(name, value ? "true" : "false");
+ }
+
+ /**
+ * Adds the integer property.
+ *
+ * @param name The name of the property.
+ * @param value The value of the property.
+ */
+ public void add(String name, int value)
+ {
+ props.put(name, Integer.toString(value));
+ }
+
+ /**
+ * Adds the double property.
+ *
+ * @param name The name of the property.
+ * @param value The value of the property.
+ */
+ public void add(String name, double value)
+ {
+ props.put(name, Double.toString(value));
+ }
+
+ /**
+ * Returns the value of the property with the
+ * given name. Null is returned if the named
+ * property is not found.
+ *
+ * @param The name of the desired property.
+ * @return The value of the property.
+ */
+ public String get(String name)
+ {
+ return (String) props.get(name);
+ }
+
+ /**
+ * Returns the value of the property with the
+ * given name. 'default_value' is returned if the
+ * named property is not found.
+ *
+ * @param The name of the desired property.
+ * @param default_value The default value of the property which is returned
+ * if the property does not have a specified value.
+ * @return The value of the property.
+ */
+ public String get(String name, String default_value)
+ {
+ Object value = props.get(name);
+ return value != null ? (String) value : default_value;
+ }
+
+ /**
+ * Returns the value of the property with the given name.
+ * 'false' is returned if the property does not have a
+ * specified value.
+ *
+ * @param name The name of the desired property.
+ * @param return The value of the property.
+ */
+ public boolean getBoolean(String name)
+ {
+ Object value = props.get(name);
+ return value != null ? value.equals("true") : false;
+ }
+
+ /**
+ * Returns the value of the property with the given name.
+ *
+ * @param name The name of the desired property.
+ * @param default_value The default value of the property which is returned
+ * if the property does not have a specified value.
+ * @param return The value of the property.
+ */
+ public boolean getBoolean(String name, boolean default_value)
+ {
+ Object value = props.get(name);
+ return value != null ? value.equals("true") : default_value;
+ }
+
+ /**
+ * Returns the value of the property with the given name.
+ * '0' is returned if the property does not have a
+ * specified value.
+ *
+ * @param name The name of the desired property.
+ * @param return The value of the property.
+ */
+ public int getInt(String name)
+ {
+ try
+ {
+ return Integer.parseInt((String) props.get(name));
+ }
+ catch (Exception e)
+ {
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the value of the property with the given name.
+ *
+ * @param name The name of the desired property.
+ * @param default_value The default value of the property which is returned
+ * if the property does not have a specified value.
+ * @param return The value of the property.
+ */
+ public int getInt(String name, int default_value)
+ {
+ try
+ {
+ return Integer.parseInt((String) props.get(name));
+ }
+ catch (Exception e)
+ {
+ }
+ return default_value;
+ }
+
+ /**
+ * Returns the value of the property with the given name.
+ * '0' is returned if the property does not have a
+ * specified value.
+ *
+ * @param name The name of the desired property.
+ * @param return The value of the property.
+ */
+ public double getDouble(String name)
+ {
+ try
+ {
+ return new Double((String) props.get(name)).doubleValue();
+ }
+ catch (Exception e)
+ {
+ }
+ return -1d;
+ }
+
+ /**
+ * Returns the value of the property with the given name.
+ *
+ * @param name The name of the desired property.
+ * @param default_value The default value of the property which is returned
+ * if the property does not have a specified value.
+ * @param return The value of the property.
+ */
+ public double getDouble(String name, double default_value)
+ {
+ try
+ {
+ return new Double((String) props.get(name)).doubleValue();
+ }
+ catch (Exception e)
+ {
+ }
+ return default_value;
+ }
+
+ /**
+ * Removes the property with the given name.
+ *
+ * @param name The name of the property to remove.
+ */
+ public void remove(String name)
+ {
+ props.remove(name);
+ }
+
+ /**
+ * Removes all the properties.
+ */
+ public void removeAll()
+ {
+ props.clear();
+ }
+
+ /**
+ * Loads the property list from the configuration file.
+ *
+ * @return True if the file was loaded successfully, false if
+ * the file does not exists or an error occurred reading
+ * the file.
+ */
+ public boolean load()
+ {
+ if ((config_file == null) && (config_url == null)) return false;
+ // Loads from URL.
+ if (config_url != null)
+ {
+ try
+ {
+ return load(new BufferedReader(new InputStreamReader(config_url.openStream())));
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ // Loads from file.
+ else
+ {
+ if (!config_file.exists()) return false;
+ try
+ {
+ return load(new BufferedReader(new FileReader(config_file)));
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return false;
+ }
+ }
+ }
+
+ public boolean load(BufferedReader buffy) throws IOException
+ {
+ Hashtable props = this.props;
+ String line = null;
+ while ((line = buffy.readLine()) != null)
+ {
+ int eq_idx = line.indexOf('=');
+ if (eq_idx > 0)
+ {
+ String name = line.substring(0, eq_idx).trim();
+ String value = line.substring(eq_idx + 1).trim();
+ props.put(name, value);
+ }
+ }
+ buffy.close();
+ return true;
+ }
+
+ /**
+ * Saves the property list to the config file.
+ *
+ * @return True if the save was successful, false othewise.
+ */
+ public boolean save()
+ {
+ if (config_url != null) return false;
+ try
+ {
+ PrintWriter out = new PrintWriter(new FileWriter(config_file));
+ return save(out);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ public boolean save(PrintWriter out) throws IOException
+ {
+ Hashtable props = this.props;
+ Enumeration names = props.keys();
+ SortedStrings sorter = new SortedStrings();
+ while (names.hasMoreElements())
+ {
+ sorter.add((String) names.nextElement());
+ }
+ for (int i = 0; i < sorter.stringCount(); i++)
+ {
+ String name = sorter.stringAt(i);
+ String value = (String) props.get(name);
+ out.print(name);
+ out.print("=");
+ out.println(value);
+ }
+ out.close();
+ return true;
+ }
+
+ public void storeCRC()
+ {
+ add("crc", generateCRC());
+ }
+
+ public boolean isValidCRC()
+ {
+ String crc = generateCRC();
+ String stored_crc = (String) props.get("crc");
+ if (stored_crc == null) return false;
+ return stored_crc.equals(crc);
+ }
+
+ private String generateCRC()
+ {
+ Hashtable props = this.props;
+ CRC32OutputStream crc = new CRC32OutputStream();
+ PrintWriter pr = new PrintWriter(crc);
+ Enumeration names = props.keys();
+ while (names.hasMoreElements())
+ {
+ String name = (String) names.nextElement();
+ if (!name.equals("crc"))
+ {
+ pr.println((String) props.get(name));
+ }
+ }
+ pr.flush();
+ return "" + crc.getValue();
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ini/SortedStrings.java b/java/src/javazoom/jlgui/player/amp/util/ini/SortedStrings.java
new file mode 100644
index 0000000..c6aa391
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ini/SortedStrings.java
@@ -0,0 +1,338 @@
+/*
+ * SortedStrings.
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ini;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * An object that represents an array of alpabetized Strings. Implemented
+ * with an String array that grows as appropriate.
+ */
+public class SortedStrings extends Alphabetizer implements Cloneable
+{
+ public static final int DEFAULT_SIZE = 32;
+ private String[] strings;
+ private int string_count;
+ private double growth_rate = 2.0;
+
+ /**
+ * Constructor creates a new SortedStrings object of default
+ * size.
+ */
+ public SortedStrings()
+ {
+ clear();
+ }
+
+ /**
+ * Constructor creates a new SortedStrings object of size passed.
+ */
+ public SortedStrings(int initial_size)
+ {
+ clear(initial_size);
+ }
+
+ /**
+ * Contructor creates a new SortedStrings object using a DataInput
+ * object. The first int in the DataInput object is assumed to be
+ * the size wanted for the SortedStrings object.
+ */
+ public SortedStrings(DataInput in) throws IOException
+ {
+ int count = string_count = in.readInt();
+ String[] arr = strings = new String[count];
+ for (int i = 0; i < count; i++)
+ arr[i] = in.readUTF();
+ }
+
+ /**
+ * Contructor creates a new SortedStrings object, initializing it
+ * with the String[] passed.
+ */
+ public SortedStrings(String[] array)
+ {
+ this(array.length);
+ int new_size = array.length;
+ for (int i = 0; i < new_size; i++)
+ add(array[i]);
+ }
+
+ /**
+ * Clones the SortedStrings object.
+ */
+ public Object clone()
+ {
+ try
+ {
+ SortedStrings clone = (SortedStrings) super.clone();
+ clone.strings = (String[]) strings.clone();
+ return clone;
+ }
+ catch (CloneNotSupportedException e)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Writes a the SortedStrings object to the DataOutput object.
+ */
+ public void emit(DataOutput out) throws IOException
+ {
+ int count = string_count;
+ String[] arr = strings;
+ out.writeInt(count);
+ for (int i = 0; i < count; i++)
+ out.writeUTF(arr[i]);
+ }
+
+ /**
+ * Merge two sorted lists of integers. The time complexity of
+ * the merge is O(n).
+ */
+ public SortedStrings merge(SortedStrings that)
+ {
+ int count1 = this.string_count;
+ int count2 = that.string_count;
+ String[] ints1 = this.strings;
+ String[] ints2 = that.strings;
+ String num1, num2;
+ int i1 = 0, i2 = 0;
+ SortedStrings res = new SortedStrings(count1 + count2);
+ while (i1 < count1 && i2 < count2)
+ {
+ num1 = ints1[i1];
+ num2 = ints2[i2];
+ if (compare(num1, num2) < 0)
+ {
+ res.add(num1);
+ i1++;
+ }
+ else if (compare(num2, num1) < 0)
+ {
+ res.add(num2);
+ i2++;
+ }
+ else
+ {
+ res.add(num1);
+ i1++;
+ i2++;
+ }
+ }
+ if (i1 < count1)
+ {
+ for (; i1 < count1; i1++)
+ res.add(ints1[i1]);
+ }
+ else for (; i2 < count2; i2++)
+ res.add(ints2[i2]);
+ return res;
+ }
+
+ /**
+ * Returns a SortedStrings object that has the Strings
+ * from this object that are not in the one passed.
+ */
+ public SortedStrings diff(SortedStrings that)
+ {
+ int count1 = this.string_count;
+ int count2 = that.string_count;
+ String[] ints1 = this.strings;
+ String[] ints2 = that.strings;
+ String num1, num2;
+ int i1 = 0, i2 = 0;
+ SortedStrings res = new SortedStrings(count1);
+ while (i1 < count1 && i2 < count2)
+ {
+ num1 = ints1[i1];
+ num2 = ints2[i2];
+ if (compare(num1, num2) < 0)
+ {
+ res.add(num1);
+ i1++;
+ }
+ else if (compare(num2, num1) < 0) i2++;
+ else
+ {
+ i1++;
+ i2++;
+ }
+ }
+ if (i1 < count1)
+ {
+ for (; i1 < count1; i1++)
+ res.add(ints1[i1]);
+ }
+ return res;
+ }
+
+ /**
+ * Clears the Strings from the object and creates a new one
+ * of the default size.
+ */
+ public void clear()
+ {
+ clear(DEFAULT_SIZE);
+ }
+
+ /**
+ * Clears the Strings from the object and creates a new one
+ * of the size passed.
+ */
+ public void clear(int initial_size)
+ {
+ strings = new String[initial_size];
+ string_count = 0;
+ }
+
+ /**
+ * Adds the String passed to the array in its proper place -- sorted.
+ */
+ public void add(String num)
+ {
+ if (string_count == 0 || greaterThan(num, strings[string_count - 1]))
+ {
+ if (string_count == strings.length) strings = (String[]) Array.grow(strings, growth_rate);
+ strings[string_count] = num;
+ string_count++;
+ }
+ else insert(search(num), num);
+ }
+
+ /**
+ * Inserts the String passed to the array at the index passed.
+ */
+ private void insert(int index, String num)
+ {
+ if (strings[index] == num) return;
+ else
+ {
+ if (string_count == strings.length) strings = (String[]) Array.grow(strings, growth_rate);
+ System.arraycopy(strings, index, strings, index + 1, string_count - index);
+ strings[index] = num;
+ string_count++;
+ }
+ }
+
+ /**
+ * Removes the String passed from the array.
+ */
+ public void remove(String num)
+ {
+ int index = search(num);
+ if (index < string_count && equalTo(strings[index], num)) removeIndex(index);
+ }
+
+ /**
+ * Removes the String from the beginning of the array to the
+ * index passed.
+ */
+ public void removeIndex(int index)
+ {
+ if (index < string_count)
+ {
+ System.arraycopy(strings, index + 1, strings, index, string_count - index - 1);
+ string_count--;
+ }
+ }
+
+ /**
+ * Returns true flag if the String passed is in the array.
+ */
+ public boolean contains(String num)
+ {
+ int index = search(num);
+ return index < string_count && equalTo(strings[search(num)], num);
+ }
+
+ /**
+ * Returns the number of Strings in the array.
+ */
+ public int stringCount()
+ {
+ return string_count;
+ }
+
+ /**
+ * Returns String index of the int passed.
+ */
+ public int indexOf(String num)
+ {
+ int index = search(num);
+ return index < string_count && equalTo(strings[index], num) ? index : -1;
+ }
+
+ /**
+ * Returns the String value at the index passed.
+ */
+ public String stringAt(int index)
+ {
+ return strings[index];
+ }
+
+ /**
+ * Returns the index where the String value passed is located
+ * or where it should be sorted to if it is not present.
+ */
+ protected int search(String num)
+ {
+ String[] strings = this.strings;
+ int lb = 0, ub = string_count, index;
+ String index_key;
+ while (true)
+ {
+ if (lb >= ub - 1)
+ {
+ if (lb < string_count && !greaterThan(num, strings[lb])) return lb;
+ else return lb + 1;
+ }
+ index = (lb + ub) / 2;
+ index_key = strings[index];
+ if (greaterThan(num, index_key)) lb = index + 1;
+ else if (lessThan(num, index_key)) ub = index;
+ else return index;
+ }
+ }
+
+ /**
+ * Returns an String[] that contains the value in the SortedStrings
+ * object.
+ */
+ public String[] toStringArray()
+ {
+ String[] array = new String[string_count];
+ System.arraycopy(strings, 0, array, 0, string_count);
+ return array;
+ }
+
+ /**
+ * Returns a sorted String[] from the String[] passed.
+ */
+ public static String[] sort(String[] input)
+ {
+ SortedStrings new_strings = new SortedStrings(input);
+ return new_strings.toStringArray();
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/DevicePreference.java b/java/src/javazoom/jlgui/player/amp/util/ui/DevicePreference.java
new file mode 100644
index 0000000..b08201f
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/DevicePreference.java
@@ -0,0 +1,120 @@
+/*
+ * DevicePreference.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ui;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.text.MessageFormat;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ResourceBundle;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.TitledBorder;
+import javazoom.jlgui.basicplayer.BasicController;
+import javazoom.jlgui.basicplayer.BasicPlayer;
+
+public class DevicePreference extends PreferenceItem implements ActionListener
+{
+ private BasicPlayer bplayer = null;
+ private static DevicePreference instance = null;
+
+ private DevicePreference()
+ {
+ }
+
+ public static DevicePreference getInstance()
+ {
+ if (instance == null)
+ {
+ instance = new DevicePreference();
+ }
+ return instance;
+ }
+
+ public void loadUI()
+ {
+ removeAll();
+ bundle = ResourceBundle.getBundle("javazoom/jlgui/player/amp/util/ui/device");
+ setBorder(new TitledBorder(getResource("title")));
+ BoxLayout layout = new BoxLayout(this, BoxLayout.Y_AXIS);
+ setLayout(layout);
+ BasicController controller = null;
+ if (player != null) controller = player.getController();
+ if ((controller != null) && (controller instanceof BasicPlayer))
+ {
+ bplayer = (BasicPlayer) controller;
+ List devices = bplayer.getMixers();
+ String mixer = bplayer.getMixerName();
+ ButtonGroup group = new ButtonGroup();
+ Iterator it = devices.iterator();
+ while (it.hasNext())
+ {
+ String name = (String) it.next();
+ JRadioButton radio = new JRadioButton(name);
+ if (name.equals(mixer))
+ {
+ radio.setSelected(true);
+ }
+ else
+ {
+ radio.setSelected(false);
+ }
+ group.add(radio);
+ radio.addActionListener(this);
+ radio.setAlignmentX(Component.LEFT_ALIGNMENT);
+ add(radio);
+ }
+ JPanel lineInfo = new JPanel();
+ lineInfo.setLayout(new BoxLayout(lineInfo, BoxLayout.Y_AXIS));
+ lineInfo.setAlignmentX(Component.LEFT_ALIGNMENT);
+ lineInfo.setBorder(new EmptyBorder(4, 6, 0, 0));
+ if (getResource("line.buffer.size") != null)
+ {
+ Object[] args = { new Integer(bplayer.getLineCurrentBufferSize()) };
+ String str = MessageFormat.format(getResource("line.buffer.size"), args);
+ JLabel lineBufferSizeLabel = new JLabel(str);
+ lineInfo.add(lineBufferSizeLabel);
+ }
+ if (getResource("help") != null)
+ {
+ lineInfo.add(Box.createRigidArea(new Dimension(0, 30)));
+ JLabel helpLabel = new JLabel(getResource("help"));
+ lineInfo.add(helpLabel);
+ }
+ add(lineInfo);
+ }
+ }
+
+ public void actionPerformed(ActionEvent ev)
+ {
+ if (bplayer != null) bplayer.setMixerName(ev.getActionCommand());
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/EmptyPreference.java b/java/src/javazoom/jlgui/player/amp/util/ui/EmptyPreference.java
new file mode 100644
index 0000000..272755b
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/EmptyPreference.java
@@ -0,0 +1,52 @@
+/*
+ * EmptyPreference.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ui;
+
+import javax.swing.border.TitledBorder;
+
+public class EmptyPreference extends PreferenceItem
+{
+ private static EmptyPreference instance = null;
+
+ private EmptyPreference()
+ {
+ }
+
+ public static EmptyPreference getInstance()
+ {
+ if (instance == null)
+ {
+ instance = new EmptyPreference();
+ }
+ return instance;
+ }
+
+ public void loadUI()
+ {
+ if (loaded == false)
+ {
+ setBorder(new TitledBorder(""));
+ loaded = true;
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/NodeItem.java b/java/src/javazoom/jlgui/player/amp/util/ui/NodeItem.java
new file mode 100644
index 0000000..9a5628e
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/NodeItem.java
@@ -0,0 +1,46 @@
+/*
+ * NodeItem.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ui;
+
+public class NodeItem
+{
+ private String name = null;
+ private String impl = null;
+
+ public NodeItem(String name, String impl)
+ {
+ super();
+ this.name = name;
+ this.impl = impl;
+ }
+
+ public String getImpl()
+ {
+ return impl;
+ }
+
+ public String toString()
+ {
+ return name;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/OutputPreference.java b/java/src/javazoom/jlgui/player/amp/util/ui/OutputPreference.java
new file mode 100644
index 0000000..3b1bc42
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/OutputPreference.java
@@ -0,0 +1,54 @@
+/*
+ * OutputPreference.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ui;
+
+import java.util.ResourceBundle;
+import javax.swing.border.TitledBorder;
+
+public class OutputPreference extends PreferenceItem
+{
+ private static OutputPreference instance = null;
+
+ private OutputPreference()
+ {
+ }
+
+ public static OutputPreference getInstance()
+ {
+ if (instance == null)
+ {
+ instance = new OutputPreference();
+ }
+ return instance;
+ }
+
+ public void loadUI()
+ {
+ if (loaded == false)
+ {
+ bundle = ResourceBundle.getBundle("javazoom/jlgui/player/amp/util/ui/output");
+ setBorder(new TitledBorder(getResource("title")));
+ loaded = true;
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/PreferenceItem.java b/java/src/javazoom/jlgui/player/amp/util/ui/PreferenceItem.java
new file mode 100644
index 0000000..3297e61
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/PreferenceItem.java
@@ -0,0 +1,78 @@
+/*
+ * PreferenceItem.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ui;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javazoom.jlgui.player.amp.PlayerUI;
+
+public abstract class PreferenceItem extends JPanel
+{
+ protected PlayerUI player = null;
+ protected ResourceBundle bundle = null;
+ protected boolean loaded = false;
+ protected JFrame parent = null;
+
+ /**
+ * Return I18N value of a given key.
+ * @param key
+ * @return
+ */
+ public String getResource(String key)
+ {
+ String value = null;
+ if (key != null)
+ {
+ try
+ {
+ value = bundle.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ }
+ }
+ return value;
+ }
+
+
+ public void setPlayer(PlayerUI player)
+ {
+ this.player = player;
+ }
+
+ public JFrame getParentFrame()
+ {
+ return parent;
+ }
+
+
+ public void setParentFrame(JFrame parent)
+ {
+ this.parent = parent;
+ }
+
+
+ public abstract void loadUI();
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/Preferences.java b/java/src/javazoom/jlgui/player/amp/util/ui/Preferences.java
new file mode 100644
index 0000000..20d80a1
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/Preferences.java
@@ -0,0 +1,279 @@
+/*
+ * Preferences.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ui;
+
+import java.awt.BorderLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.lang.reflect.Method;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+import javazoom.jlgui.player.amp.PlayerUI;
+import javazoom.jlgui.player.amp.util.Config;
+
+public class Preferences extends JFrame implements TreeSelectionListener, ActionListener
+{
+ private static Preferences instance = null;
+ private JTree tree = null;
+ private ResourceBundle bundle = null;
+ private DefaultMutableTreeNode options = null;
+ private DefaultMutableTreeNode filetypes = null;
+ private DefaultMutableTreeNode device = null;
+ private DefaultMutableTreeNode proxy = null;
+ private DefaultMutableTreeNode plugins = null;
+ private DefaultMutableTreeNode visual = null;
+ private DefaultMutableTreeNode visuals = null;
+ private DefaultMutableTreeNode output = null;
+ //private DefaultMutableTreeNode drm = null;
+ private DefaultMutableTreeNode skins = null;
+ private DefaultMutableTreeNode browser = null;
+ private JScrollPane treePane = null;
+ private JScrollPane workPane = null;
+ private JButton close = null;
+ private PlayerUI player = null;
+
+ public Preferences(PlayerUI player)
+ {
+ super();
+ this.player = player;
+ setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ ImageIcon icon = Config.getInstance().getIconParent();
+ if (icon != null) setIconImage(icon.getImage());
+ }
+
+ public static synchronized Preferences getInstance(PlayerUI player)
+ {
+ if (instance == null)
+ {
+ instance = new Preferences(player);
+ instance.loadUI();
+ }
+ return instance;
+ }
+
+ private void loadUI()
+ {
+ bundle = ResourceBundle.getBundle("javazoom/jlgui/player/amp/util/ui/preferences");
+ setTitle(getResource("title"));
+ DefaultMutableTreeNode root = new DefaultMutableTreeNode();
+ // Options
+ if (getResource("tree.options") != null)
+ {
+ options = new DefaultMutableTreeNode(getResource("tree.options"));
+ if (getResource("tree.options.device") != null)
+ {
+ device = new DefaultMutableTreeNode();
+ device.setUserObject(new NodeItem(getResource("tree.options.device"), getResource("tree.options.device.impl")));
+ options.add(device);
+ }
+ if (getResource("tree.options.visual") != null)
+ {
+ visual = new DefaultMutableTreeNode();
+ visual.setUserObject(new NodeItem(getResource("tree.options.visual"), getResource("tree.options.visual.impl")));
+ options.add(visual);
+ }
+ if (getResource("tree.options.filetypes") != null)
+ {
+ filetypes = new DefaultMutableTreeNode();
+ filetypes.setUserObject(new NodeItem(getResource("tree.options.filetypes"), getResource("tree.options.filetypes.impl")));
+ options.add(filetypes);
+ }
+ if (getResource("tree.options.system") != null)
+ {
+ proxy = new DefaultMutableTreeNode();
+ proxy.setUserObject(new NodeItem(getResource("tree.options.system"), getResource("tree.options.system.impl")));
+ options.add(proxy);
+ }
+ root.add(options);
+ }
+ // Plugins
+ if (getResource("tree.plugins") != null)
+ {
+ plugins = new DefaultMutableTreeNode(getResource("tree.plugins"));
+ if (getResource("tree.plugins.visualization") != null)
+ {
+ visuals = new DefaultMutableTreeNode();
+ visuals.setUserObject(new NodeItem(getResource("tree.plugins.visualization"), getResource("tree.plugins.visualization.impl")));
+ plugins.add(visuals);
+ }
+ if (getResource("tree.plugins.output") != null)
+ {
+ output = new DefaultMutableTreeNode();
+ output.setUserObject(new NodeItem(getResource("tree.plugins.output"), getResource("tree.plugins.output.impl")));
+ plugins.add(output);
+ }
+ /*if (getResource("tree.plugins.drm") != null)
+ {
+ drm = new DefaultMutableTreeNode();
+ drm.setUserObject(new NodeItem(getResource("tree.plugins.drm"), getResource("tree.plugins.drm.impl")));
+ plugins.add(drm);
+ }*/
+ root.add(plugins);
+ }
+ // Skins
+ if (getResource("tree.skins") != null)
+ {
+ skins = new DefaultMutableTreeNode(getResource("tree.skins"));
+ if (getResource("tree.skins.browser") != null)
+ {
+ browser = new DefaultMutableTreeNode();
+ browser.setUserObject(new NodeItem(getResource("tree.skins.browser"), getResource("tree.skins.browser.impl")));
+ skins.add(browser);
+ }
+ root.add(skins);
+ }
+ tree = new JTree(root);
+ tree.setRootVisible(false);
+ DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
+ renderer.setLeafIcon(null);
+ renderer.setClosedIcon(null);
+ renderer.setOpenIcon(null);
+ tree.setCellRenderer(renderer);
+ tree.addTreeSelectionListener(this);
+ int i = 0;
+ while (i < tree.getRowCount())
+ {
+ tree.expandRow(i++);
+ }
+ tree.setBorder(new EmptyBorder(1, 4, 1, 2));
+ GridBagLayout layout = new GridBagLayout();
+ getContentPane().setLayout(layout);
+ GridBagConstraints cnts = new GridBagConstraints();
+ cnts.fill = GridBagConstraints.BOTH;
+ cnts.weightx = 0.3;
+ cnts.weighty = 1.0;
+ cnts.gridx = 0;
+ cnts.gridy = 0;
+ treePane = new JScrollPane(tree);
+ JPanel leftPane = new JPanel();
+ leftPane.setLayout(new BorderLayout());
+ leftPane.add(treePane, BorderLayout.CENTER);
+ if (getResource("button.close") != null)
+ {
+ close = new JButton(getResource("button.close"));
+ close.addActionListener(this);
+ leftPane.add(close, BorderLayout.SOUTH);
+ }
+ getContentPane().add(leftPane, cnts);
+ cnts.weightx = 1.0;
+ cnts.gridx = 1;
+ cnts.gridy = 0;
+ workPane = new JScrollPane(new JPanel());
+ getContentPane().add(workPane, cnts);
+ }
+
+ public void valueChanged(TreeSelectionEvent e)
+ {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
+ if (node == null) return;
+ if (node.isLeaf())
+ {
+ Object nodeItem = node.getUserObject();
+ if ((nodeItem != null) && (nodeItem instanceof NodeItem))
+ {
+ PreferenceItem pane = getPreferenceItem(((NodeItem) nodeItem).getImpl());
+ if (pane != null)
+ {
+ pane.setPlayer(player);
+ pane.loadUI();
+ pane.setParentFrame(this);
+ workPane.setViewportView(pane);
+ }
+ }
+ }
+ }
+
+ public void selectSkinBrowserPane()
+ {
+ TreeNode[] path = browser.getPath();
+ tree.setSelectionPath(new TreePath(path));
+ }
+
+ public void actionPerformed(ActionEvent ev)
+ {
+ if (ev.getSource() == close)
+ {
+ if (player != null)
+ {
+ Config config = player.getConfig();
+ config.save();
+ }
+ dispose();
+ }
+ }
+
+ /**
+ * Return I18N value of a given key.
+ * @param key
+ * @return
+ */
+ public String getResource(String key)
+ {
+ String value = null;
+ if (key != null)
+ {
+ try
+ {
+ value = bundle.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ }
+ }
+ return value;
+ }
+
+ public PreferenceItem getPreferenceItem(String impl)
+ {
+ PreferenceItem item = null;
+ if (impl != null)
+ {
+ try
+ {
+ Class aClass = Class.forName(impl);
+ Method method = aClass.getMethod("getInstance", null);
+ item = (PreferenceItem) method.invoke(null, null);
+ }
+ catch (Exception e)
+ {
+ // TODO
+ }
+ }
+ return item;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/SkinPreference.java b/java/src/javazoom/jlgui/player/amp/util/ui/SkinPreference.java
new file mode 100644
index 0000000..6c9e0e3
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/SkinPreference.java
@@ -0,0 +1,185 @@
+/*
+ * SkinPreference.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ui;
+
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.util.ResourceBundle;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javazoom.jlgui.player.amp.util.FileNameFilter;
+import javazoom.jlgui.player.amp.util.FileSelector;
+
+public class SkinPreference extends PreferenceItem implements ActionListener, ListSelectionListener
+{
+ public static final String DEFAULTSKIN = "";
+ public static final String SKINEXTENSION = "wsz";
+ private DefaultListModel listModel = null;
+ private JList skins = null;
+ private JTextArea info = null;
+ private JPanel listPane = null;
+ private JPanel infoPane = null;
+ private JPanel browsePane = null;
+ private JButton selectSkinDir = null;
+ private static SkinPreference instance = null;
+
+ private SkinPreference()
+ {
+ listModel = new DefaultListModel();
+ }
+
+ public static SkinPreference getInstance()
+ {
+ if (instance == null)
+ {
+ instance = new SkinPreference();
+ }
+ return instance;
+ }
+
+ public void loadUI()
+ {
+ if (loaded == false)
+ {
+ bundle = ResourceBundle.getBundle("javazoom/jlgui/player/amp/util/ui/skin");
+ setBorder(new TitledBorder(getResource("title")));
+ File dir = null;
+ if (player != null)
+ {
+ dir = new File(player.getConfig().getLastSkinDir());
+ }
+ loadSkins(dir);
+ skins = new JList(listModel);
+ skins.setBorder(new EmptyBorder(1, 2, 1, 1));
+ skins.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ skins.setLayoutOrientation(JList.VERTICAL);
+ skins.setVisibleRowCount(12);
+ skins.addListSelectionListener(this);
+ JScrollPane listScroller = new JScrollPane(skins);
+ listScroller.setPreferredSize(new Dimension(300, 140));
+ listPane = new JPanel();
+ listPane.add(listScroller);
+ infoPane = new JPanel();
+ info = new JTextArea(4, 35);
+ info.setEditable(false);
+ info.setCursor(null);
+ JScrollPane infoScroller = new JScrollPane(info);
+ infoScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+ infoScroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+ infoPane.add(infoScroller);
+ browsePane = new JPanel();
+ selectSkinDir = new JButton(getResource("browser.directory.button"));
+ selectSkinDir.addActionListener(this);
+ browsePane.add(selectSkinDir);
+ GridBagLayout layout = new GridBagLayout();
+ setLayout(layout);
+ GridBagConstraints cnts = new GridBagConstraints();
+ cnts.fill = GridBagConstraints.BOTH;
+ cnts.gridwidth = 1;
+ cnts.weightx = 1.0;
+ cnts.weighty = 0.60;
+ cnts.gridx = 0;
+ cnts.gridy = 0;
+ add(listPane, cnts);
+ cnts.gridwidth = 1;
+ cnts.weightx = 1.0;
+ cnts.weighty = 0.30;
+ cnts.gridx = 0;
+ cnts.gridy = 1;
+ add(infoPane, cnts);
+ cnts.weightx = 1.0;
+ cnts.weighty = 0.10;
+ cnts.gridx = 0;
+ cnts.gridy = 2;
+ add(browsePane, cnts);
+ loaded = true;
+ }
+ }
+
+ public void actionPerformed(ActionEvent ev)
+ {
+ if (ev.getActionCommand().equalsIgnoreCase(getResource("browser.directory.button")))
+ {
+ File[] file = FileSelector.selectFile(player.getLoader(), FileSelector.DIRECTORY, false, "", "Directories", new File(player.getConfig().getLastSkinDir()));
+ if ((file != null) && (file[0].isDirectory()))
+ {
+ player.getConfig().setLastSkinDir(file[0].getAbsolutePath());
+ loadSkins(file[0]);
+ }
+ }
+ }
+
+ public void valueChanged(ListSelectionEvent e)
+ {
+ if (e.getValueIsAdjusting() == false)
+ {
+ if (skins.getSelectedIndex() == -1)
+ {
+ }
+ else
+ {
+ String name = (String) listModel.get(skins.getSelectedIndex());
+ String filename = player.getConfig().getLastSkinDir() + name + "." + SKINEXTENSION;
+ player.getSkin().setPath(filename);
+ player.loadSkin();
+ player.getConfig().setDefaultSkin(filename);
+ String readme = player.getSkin().getReadme();
+ if (readme == null) readme = "";
+ info.setText(readme);
+ info.setCaretPosition(0);
+ }
+ }
+ }
+
+ private void loadSkins(File dir)
+ {
+ listModel.clear();
+ listModel.addElement(DEFAULTSKIN);
+ if ((dir != null) && (dir.exists()))
+ {
+ File[] files = dir.listFiles(new FileNameFilter(SKINEXTENSION, "Skins", false));
+ if ((files != null) && (files.length > 0))
+ {
+ for (int i = 0; i < files.length; i++)
+ {
+ String filename = files[i].getName();
+ listModel.addElement(filename.substring(0, filename.length() - 4));
+ }
+ }
+ }
+ }
+
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/SystemPreference.java b/java/src/javazoom/jlgui/player/amp/util/ui/SystemPreference.java
new file mode 100644
index 0000000..0ab6503
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/SystemPreference.java
@@ -0,0 +1,91 @@
+/*
+ * SystemPreference.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Font;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.TreeMap;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.TitledBorder;
+
+public class SystemPreference extends PreferenceItem
+{
+ private JTextArea info = null;
+ private boolean loaded = false;
+ private static SystemPreference instance = null;
+
+ private SystemPreference()
+ {
+ }
+
+ public static SystemPreference getInstance()
+ {
+ if (instance == null)
+ {
+ instance = new SystemPreference();
+ }
+ return instance;
+ }
+
+ public void loadUI()
+ {
+ if (loaded == false)
+ {
+ bundle = ResourceBundle.getBundle("javazoom/jlgui/player/amp/util/ui/system");
+ setBorder(new TitledBorder(getResource("title")));
+ setLayout(new BorderLayout());
+ info = new JTextArea(16,35);
+ info.setFont(new Font("Dialog", Font.PLAIN, 11));
+ info.setEditable(false);
+ info.setCursor(null);
+ info.setBorder(new EmptyBorder(1,2,1,1));
+ Properties props = System.getProperties();
+ Iterator it = props.keySet().iterator();
+ TreeMap map = new TreeMap();
+ while (it.hasNext())
+ {
+ String key = (String) it.next();
+ String value = props.getProperty(key);
+ map.put(key, value);
+ }
+ it = map.keySet().iterator();
+ while (it.hasNext())
+ {
+ String key = (String) it.next();
+ String value = (String) map.get(key);
+ info.append(key + "=" + value + "\r\n");
+ }
+ JScrollPane infoScroller = new JScrollPane(info);
+ infoScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+ infoScroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+ add(infoScroller, BorderLayout.CENTER);
+ info.setCaretPosition(0);
+ loaded = true;
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/TypePreference.java b/java/src/javazoom/jlgui/player/amp/util/ui/TypePreference.java
new file mode 100644
index 0000000..e1f62f4
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/TypePreference.java
@@ -0,0 +1,129 @@
+/*
+ * TypePreference.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ui;
+
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ResourceBundle;
+import java.util.StringTokenizer;
+import javax.swing.DefaultListModel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+public class TypePreference extends PreferenceItem implements ActionListener, ListSelectionListener
+{
+ private DefaultListModel listModel = null;
+ private JList types = null;
+ private JPanel listPane = null;
+ private JPanel extensionPane = null;
+ private static TypePreference instance = null;
+
+ private TypePreference()
+ {
+ listModel = new DefaultListModel();
+ }
+
+ public static TypePreference getInstance()
+ {
+ if (instance == null)
+ {
+ instance = new TypePreference();
+ }
+ return instance;
+ }
+
+ public void loadUI()
+ {
+ if (loaded == false)
+ {
+ bundle = ResourceBundle.getBundle("javazoom/jlgui/player/amp/util/ui/type");
+ setBorder(new TitledBorder(getResource("title")));
+ loadTypes();
+ types = new JList(listModel);
+ types.setBorder(new EmptyBorder(1, 2, 1, 1));
+ types.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ types.setLayoutOrientation(JList.VERTICAL);
+ types.setVisibleRowCount(12);
+ types.addListSelectionListener(this);
+ JScrollPane listScroller = new JScrollPane(types);
+ listScroller.setPreferredSize(new Dimension(80, 240));
+ listPane = new JPanel();
+ listPane.add(listScroller);
+ extensionPane = new JPanel();
+ GridBagLayout layout = new GridBagLayout();
+ setLayout(layout);
+ GridBagConstraints cnts = new GridBagConstraints();
+ cnts.fill = GridBagConstraints.BOTH;
+ cnts.gridwidth = 1;
+ cnts.weightx = 0.30;
+ cnts.weighty = 1.0;
+ cnts.gridx = 0;
+ cnts.gridy = 0;
+ add(listPane, cnts);
+ cnts.gridwidth = 1;
+ cnts.weightx = 0.70;
+ cnts.weighty = 1.0;
+ cnts.gridx = 1;
+ cnts.gridy = 0;
+ add(extensionPane, cnts);
+ loaded = true;
+ }
+ }
+
+ public void actionPerformed(ActionEvent ev)
+ {
+ }
+
+ public void valueChanged(ListSelectionEvent e)
+ {
+ if (e.getValueIsAdjusting() == false)
+ {
+ if (types.getSelectedIndex() == -1)
+ {
+ }
+ else
+ {
+ }
+ }
+ }
+
+ private void loadTypes()
+ {
+ String extensions = player.getConfig().getExtensions();
+ StringTokenizer st = new StringTokenizer(extensions, ",");
+ while (st.hasMoreTokens())
+ {
+ String type = st.nextToken();
+ listModel.addElement(type);
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/VisualPreference.java b/java/src/javazoom/jlgui/player/amp/util/ui/VisualPreference.java
new file mode 100644
index 0000000..1813c2c
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/VisualPreference.java
@@ -0,0 +1,292 @@
+/*
+ * VisualPreference.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ui;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Hashtable;
+import java.util.ResourceBundle;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JSlider;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javazoom.jlgui.player.amp.visual.ui.SpectrumTimeAnalyzer;
+
+public class VisualPreference extends PreferenceItem implements ActionListener, ChangeListener
+{
+ private JPanel modePane = null;
+ private JPanel spectrumPane = null;
+ private JPanel oscilloPane = null;
+ private JRadioButton spectrumMode = null;
+ private JRadioButton oscilloMode = null;
+ private JRadioButton offMode = null;
+ private JCheckBox peaksBox = null;
+ private JSlider analyzerFalloff = null;
+ private JSlider peaksFalloff = null;
+ private static VisualPreference instance = null;
+
+ private VisualPreference()
+ {
+ }
+
+ public static VisualPreference getInstance()
+ {
+ if (instance == null)
+ {
+ instance = new VisualPreference();
+ }
+ return instance;
+ }
+
+ public void loadUI()
+ {
+ if (loaded == false)
+ {
+ bundle = ResourceBundle.getBundle("javazoom/jlgui/player/amp/util/ui/visual");
+ setBorder(new TitledBorder(getResource("title")));
+ modePane = new JPanel();
+ modePane.setBorder(new TitledBorder(getResource("mode.title")));
+ modePane.setLayout(new FlowLayout());
+ spectrumMode = new JRadioButton(getResource("mode.spectrum"));
+ spectrumMode.addActionListener(this);
+ oscilloMode = new JRadioButton(getResource("mode.oscilloscope"));
+ oscilloMode.addActionListener(this);
+ offMode = new JRadioButton(getResource("mode.off"));
+ offMode.addActionListener(this);
+ SpectrumTimeAnalyzer analyzer = null;
+ if (player != null)
+ {
+ analyzer = player.getSkin().getAcAnalyzer();
+ int displayMode = SpectrumTimeAnalyzer.DISPLAY_MODE_OFF;
+ if (analyzer != null)
+ {
+ displayMode = analyzer.getDisplayMode();
+ }
+ if (displayMode == SpectrumTimeAnalyzer.DISPLAY_MODE_SPECTRUM_ANALYSER)
+ {
+ spectrumMode.setSelected(true);
+ }
+ else if (displayMode == SpectrumTimeAnalyzer.DISPLAY_MODE_SCOPE)
+ {
+ oscilloMode.setSelected(true);
+ }
+ else if (displayMode == SpectrumTimeAnalyzer.DISPLAY_MODE_OFF)
+ {
+ offMode.setSelected(true);
+ }
+ }
+ ButtonGroup modeGroup = new ButtonGroup();
+ modeGroup.add(spectrumMode);
+ modeGroup.add(oscilloMode);
+ modeGroup.add(offMode);
+ modePane.add(spectrumMode);
+ modePane.add(oscilloMode);
+ modePane.add(offMode);
+ spectrumPane = new JPanel();
+ spectrumPane.setLayout(new BoxLayout(spectrumPane, BoxLayout.Y_AXIS));
+ peaksBox = new JCheckBox(getResource("spectrum.peaks"));
+ peaksBox.setAlignmentX(Component.LEFT_ALIGNMENT);
+ peaksBox.addActionListener(this);
+ if ((analyzer != null) && (analyzer.isPeaksEnabled())) peaksBox.setSelected(true);
+ else peaksBox.setSelected(false);
+ spectrumPane.add(peaksBox);
+ // Analyzer falloff.
+ JLabel analyzerFalloffLabel = new JLabel(getResource("spectrum.analyzer.falloff"));
+ analyzerFalloffLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ spectrumPane.add(analyzerFalloffLabel);
+ int minDecay = (int) (SpectrumTimeAnalyzer.MIN_SPECTRUM_ANALYSER_DECAY * 100);
+ int maxDecay = (int) (SpectrumTimeAnalyzer.MAX_SPECTRUM_ANALYSER_DECAY * 100);
+ int decay = (maxDecay + minDecay) / 2;
+ if (analyzer != null)
+ {
+ decay = (int) (analyzer.getSpectrumAnalyserDecay() * 100);
+ }
+ analyzerFalloff = new JSlider(JSlider.HORIZONTAL, minDecay, maxDecay, decay);
+ analyzerFalloff.setMajorTickSpacing(1);
+ analyzerFalloff.setPaintTicks(true);
+ analyzerFalloff.setMaximumSize(new Dimension(150, analyzerFalloff.getPreferredSize().height));
+ analyzerFalloff.setAlignmentX(Component.LEFT_ALIGNMENT);
+ analyzerFalloff.setSnapToTicks(true);
+ analyzerFalloff.addChangeListener(this);
+ spectrumPane.add(analyzerFalloff);
+ // Peaks falloff.
+ JLabel peaksFalloffLabel = new JLabel(getResource("spectrum.peaks.falloff"));
+ peaksFalloffLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ spectrumPane.add(peaksFalloffLabel);
+ int peakDelay = SpectrumTimeAnalyzer.DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY;
+ int fps = SpectrumTimeAnalyzer.DEFAULT_FPS;
+ if (analyzer != null)
+ {
+ fps = analyzer.getFps();
+ peakDelay = analyzer.getPeakDelay();
+ }
+ peaksFalloff = new JSlider(JSlider.HORIZONTAL, 0, 4, computeSliderValue(peakDelay, fps));
+ peaksFalloff.setMajorTickSpacing(1);
+ peaksFalloff.setPaintTicks(true);
+ peaksFalloff.setSnapToTicks(true);
+ Hashtable labelTable = new Hashtable();
+ labelTable.put(new Integer(0), new JLabel("Slow"));
+ labelTable.put(new Integer(4), new JLabel("Fast"));
+ peaksFalloff.setLabelTable(labelTable);
+ peaksFalloff.setPaintLabels(true);
+ peaksFalloff.setMaximumSize(new Dimension(150, peaksFalloff.getPreferredSize().height));
+ peaksFalloff.setAlignmentX(Component.LEFT_ALIGNMENT);
+ peaksFalloff.addChangeListener(this);
+ spectrumPane.add(peaksFalloff);
+ // Spectrum pane
+ spectrumPane.setBorder(new TitledBorder(getResource("spectrum.title")));
+ if (getResource("oscilloscope.title") != null)
+ {
+ oscilloPane = new JPanel();
+ oscilloPane.setBorder(new TitledBorder(getResource("oscilloscope.title")));
+ }
+ GridBagLayout layout = new GridBagLayout();
+ setLayout(layout);
+ GridBagConstraints cnts = new GridBagConstraints();
+ cnts.fill = GridBagConstraints.BOTH;
+ cnts.gridwidth = 2;
+ cnts.weightx = 2.0;
+ cnts.weighty = 0.25;
+ cnts.gridx = 0;
+ cnts.gridy = 0;
+ add(modePane, cnts);
+ cnts.gridwidth = 1;
+ cnts.weightx = 1.0;
+ cnts.weighty = 1.0;
+ cnts.gridx = 0;
+ cnts.gridy = 1;
+ add(spectrumPane, cnts);
+ cnts.weightx = 1.0;
+ cnts.weighty = 1.0;
+ cnts.gridx = 1;
+ cnts.gridy = 1;
+ if (oscilloPane != null) add(oscilloPane, cnts);
+ if (analyzer == null)
+ {
+ disablePane(modePane);
+ disablePane(spectrumPane);
+ disablePane(oscilloPane);
+ }
+ loaded = true;
+ }
+ }
+
+ private void disablePane(JPanel pane)
+ {
+ if (pane != null)
+ {
+ Component[] cpns = pane.getComponents();
+ if (cpns != null)
+ {
+ for (int i = 0; i < cpns.length; i++)
+ {
+ cpns[i].setEnabled(false);
+ }
+ }
+ }
+ }
+
+ public void actionPerformed(ActionEvent ev)
+ {
+ if (player != null)
+ {
+ SpectrumTimeAnalyzer analyzer = player.getSkin().getAcAnalyzer();
+ if (analyzer != null)
+ {
+ if (ev.getSource().equals(spectrumMode))
+ {
+ analyzer.setDisplayMode(SpectrumTimeAnalyzer.DISPLAY_MODE_SPECTRUM_ANALYSER);
+ analyzer.startDSP(null);
+ }
+ else if (ev.getSource().equals(oscilloMode))
+ {
+ analyzer.setDisplayMode(SpectrumTimeAnalyzer.DISPLAY_MODE_SCOPE);
+ analyzer.startDSP(null);
+ }
+ else if (ev.getSource().equals(offMode))
+ {
+ analyzer.setDisplayMode(SpectrumTimeAnalyzer.DISPLAY_MODE_OFF);
+ analyzer.closeDSP();
+ analyzer.repaint();
+ }
+ else if (ev.getSource().equals(peaksBox))
+ {
+ if (peaksBox.isSelected()) analyzer.setPeaksEnabled(true);
+ else analyzer.setPeaksEnabled(false);
+ }
+ }
+ }
+ }
+
+ public void stateChanged(ChangeEvent ce)
+ {
+ if (player != null)
+ {
+ SpectrumTimeAnalyzer analyzer = player.getSkin().getAcAnalyzer();
+ if (analyzer != null)
+ {
+ if (ce.getSource() == analyzerFalloff)
+ {
+ if (!analyzerFalloff.getValueIsAdjusting())
+ {
+ analyzer.setSpectrumAnalyserDecay(analyzerFalloff.getValue() * 1.0f / 100.0f);
+ }
+ }
+ else if (ce.getSource() == peaksFalloff)
+ {
+ if (!peaksFalloff.getValueIsAdjusting())
+ {
+ analyzer.setPeakDelay(computeDelay(peaksFalloff.getValue(), analyzer.getFps()));
+ }
+ }
+ }
+ }
+ }
+
+ private int computeDelay(int slidervalue, int fps)
+ {
+ float p = SpectrumTimeAnalyzer.DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO;
+ float n = SpectrumTimeAnalyzer.DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO_RANGE;
+ int delay = Math.round(((-n * slidervalue * 1.0f / 2.0f) + p + n) * fps);
+ return delay;
+ }
+
+ private int computeSliderValue(int delay, int fps)
+ {
+ float p = SpectrumTimeAnalyzer.DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO;
+ float n = SpectrumTimeAnalyzer.DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO_RANGE;
+ int value = (int) Math.round((((p - (delay * 1.0 / fps * 1.0f)) * 2 / n) + 2));
+ return value;
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/VisualizationPreference.java b/java/src/javazoom/jlgui/player/amp/util/ui/VisualizationPreference.java
new file mode 100644
index 0000000..9c02fa8
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/VisualizationPreference.java
@@ -0,0 +1,54 @@
+/*
+ * VisualizationPreference.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.util.ui;
+
+import java.util.ResourceBundle;
+import javax.swing.border.TitledBorder;
+
+public class VisualizationPreference extends PreferenceItem
+{
+ private static VisualizationPreference instance = null;
+
+ private VisualizationPreference()
+ {
+ }
+
+ public static VisualizationPreference getInstance()
+ {
+ if (instance == null)
+ {
+ instance = new VisualizationPreference();
+ }
+ return instance;
+ }
+
+ public void loadUI()
+ {
+ if (loaded == false)
+ {
+ bundle = ResourceBundle.getBundle("javazoom/jlgui/player/amp/util/ui/visualization");
+ setBorder(new TitledBorder(getResource("title")));
+ loaded = true;
+ }
+ }
+}
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/device.properties b/java/src/javazoom/jlgui/player/amp/util/ui/device.properties
new file mode 100644
index 0000000..279243a
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/device.properties
@@ -0,0 +1,6 @@
+title=JavaSound Device
+line.buffer.size=Line buffer size : {0} bytes
+help=Note : Device update will occur on player restart only.
+
+
+
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/output.properties b/java/src/javazoom/jlgui/player/amp/util/ui/output.properties
new file mode 100644
index 0000000..c54c46a
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/output.properties
@@ -0,0 +1,2 @@
+title=Output plugins
+
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/preferences.properties b/java/src/javazoom/jlgui/player/amp/util/ui/preferences.properties
new file mode 100644
index 0000000..3787d34
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/preferences.properties
@@ -0,0 +1,27 @@
+title=Preferences
+
+tree.options=Options
+tree.options.device=Device
+tree.options.device.impl=javazoom.jlgui.player.amp.util.ui.DevicePreference
+tree.options.visual=Visual
+tree.options.visual.impl=javazoom.jlgui.player.amp.util.ui.VisualPreference
+tree.options.system=System
+tree.options.system.impl=javazoom.jlgui.player.amp.util.ui.SystemPreference
+tree.options.filetypes=File Types
+tree.options.filetypes.impl=javazoom.jlgui.player.amp.util.ui.TypePreference
+
+#tree.plugins=Plugins
+#tree.plugins.visualization=Visualization
+#tree.plugins.visualization.impl=javazoom.jlgui.player.amp.util.ui.VisualizationPreference
+
+#tree.plugins.output=Output
+#tree.plugins.output.impl=javazoom.jlgui.player.amp.util.ui.OutputPreference
+
+#tree.plugins.drm=DRM
+#tree.plugins.drm.impl=javazoom.jlgui.player.amp.util.ui.EmptyPreference
+
+tree.skins=Skins
+tree.skins.browser=Browser
+tree.skins.browser.impl=javazoom.jlgui.player.amp.util.ui.SkinPreference
+
+button.close=Close
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/skin.properties b/java/src/javazoom/jlgui/player/amp/util/ui/skin.properties
new file mode 100644
index 0000000..6433f43
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/skin.properties
@@ -0,0 +1,4 @@
+title=Skins
+
+browser.directory.button=Set skins directory ...
+
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/system.properties b/java/src/javazoom/jlgui/player/amp/util/ui/system.properties
new file mode 100644
index 0000000..a0f7dd4
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/system.properties
@@ -0,0 +1,3 @@
+title=System properties
+
+
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/type.properties b/java/src/javazoom/jlgui/player/amp/util/ui/type.properties
new file mode 100644
index 0000000..061309d
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/type.properties
@@ -0,0 +1,2 @@
+title=Supported File types
+
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/visual.properties b/java/src/javazoom/jlgui/player/amp/util/ui/visual.properties
new file mode 100644
index 0000000..be5fe0c
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/visual.properties
@@ -0,0 +1,15 @@
+title=Built-in visual options
+
+mode.title=Mode
+mode.spectrum=Spectrum analyzer
+mode.oscilloscope=Oscilloscope
+mode.off=Off
+mode.refresh.rate=50
+
+spectrum.title=Spectrum analyzer
+spectrum.peaks=Peaks
+spectrum.analyzer.falloff=Analyzer falloff :
+spectrum.peaks.falloff=Peaks falloff :
+
+#oscilloscope.title=Oscilloscope
+
diff --git a/java/src/javazoom/jlgui/player/amp/util/ui/visualization.properties b/java/src/javazoom/jlgui/player/amp/util/ui/visualization.properties
new file mode 100644
index 0000000..7c1585b
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/util/ui/visualization.properties
@@ -0,0 +1,2 @@
+title=Visualization plugins
+
diff --git a/java/src/javazoom/jlgui/player/amp/visual/ui/SpectrumTimeAnalyzer.java b/java/src/javazoom/jlgui/player/amp/visual/ui/SpectrumTimeAnalyzer.java
new file mode 100644
index 0000000..294dc82
--- /dev/null
+++ b/java/src/javazoom/jlgui/player/amp/visual/ui/SpectrumTimeAnalyzer.java
@@ -0,0 +1,775 @@
+/*
+ * SpectrumTimeAnalyzer.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.visual.ui;
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringTokenizer;
+import javax.sound.sampled.SourceDataLine;
+import javax.swing.JPanel;
+import javazoom.jlgui.player.amp.skin.AbsoluteConstraints;
+import kj.dsp.KJDigitalSignalProcessingAudioDataConsumer;
+import kj.dsp.KJDigitalSignalProcessor;
+import kj.dsp.KJFFT;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class SpectrumTimeAnalyzer extends JPanel implements KJDigitalSignalProcessor
+{
+ private static Log log = LogFactory.getLog(SpectrumTimeAnalyzer.class);
+ public static final int DISPLAY_MODE_SCOPE = 0;
+ public static final int DISPLAY_MODE_SPECTRUM_ANALYSER = 1;
+ public static final int DISPLAY_MODE_OFF = 2;
+ public static final int DEFAULT_WIDTH = 256;
+ public static final int DEFAULT_HEIGHT = 128;
+ public static final int DEFAULT_FPS = 50;
+ public static final int DEFAULT_SPECTRUM_ANALYSER_FFT_SAMPLE_SIZE = 512;
+ public static final int DEFAULT_SPECTRUM_ANALYSER_BAND_COUNT = 19;
+ public static final float DEFAULT_SPECTRUM_ANALYSER_DECAY = 0.05f;
+ public static final int DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY = 20;
+ public static final float DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO = 0.4f;
+ public static final float DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO_RANGE = 0.1f;
+ public static final float MIN_SPECTRUM_ANALYSER_DECAY = 0.02f;
+ public static final float MAX_SPECTRUM_ANALYSER_DECAY = 0.08f;
+ public static final Color DEFAULT_BACKGROUND_COLOR = new Color(0, 0, 128);
+ public static final Color DEFAULT_SCOPE_COLOR = new Color(255, 192, 0);
+ public static final float DEFAULT_VU_METER_DECAY = 0.02f;
+ private Image bi;
+ private int displayMode = DISPLAY_MODE_SCOPE;
+ private Color scopeColor = DEFAULT_SCOPE_COLOR;
+ private Color[] spectrumAnalyserColors = getDefaultSpectrumAnalyserColors();
+ private KJDigitalSignalProcessingAudioDataConsumer dsp = null;
+ private boolean dspStarted = false;
+ private Color peakColor = null;
+ private int[] peaks = new int[DEFAULT_SPECTRUM_ANALYSER_BAND_COUNT];
+ private int[] peaksDelay = new int[DEFAULT_SPECTRUM_ANALYSER_BAND_COUNT];
+ private int peakDelay = DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY;
+ private boolean peaksEnabled = true;
+ private List visColors = null;
+ private int barOffset = 1;
+ private int width;
+ private int height;
+ private int height_2;
+ // -- Spectrum analyser variables.
+ private KJFFT fft;
+ private float[] old_FFT;
+ private int saFFTSampleSize;
+ private int saBands;
+ private float saColorScale;
+ private float saMultiplier;
+ private float saDecay = DEFAULT_SPECTRUM_ANALYSER_DECAY;
+ private float sad;
+ private SourceDataLine m_line = null;
+ // -- VU Meter
+ private float oldLeft;
+ private float oldRight;
+ // private float vuAverage;
+ // private float vuSamples;
+ private float vuDecay = DEFAULT_VU_METER_DECAY;
+ private float vuColorScale;
+ // -- FPS calulations.
+ private long lfu = 0;
+ private int fc = 0;
+ private int fps = DEFAULT_FPS;
+ private boolean showFPS = false;
+
+ private AbsoluteConstraints constraints = null;
+
+ // private Runnable PAINT_SYNCHRONIZER = new AWTPaintSynchronizer();
+ public SpectrumTimeAnalyzer()
+ {
+ setOpaque(false);
+ initialize();
+ }
+
+ public void setConstraints(AbsoluteConstraints cnts)
+ {
+ constraints = cnts;
+ }
+
+ public AbsoluteConstraints getConstraints()
+ {
+ return constraints;
+ }
+
+ public boolean isPeaksEnabled()
+ {
+ return peaksEnabled;
+ }
+
+ public void setPeaksEnabled(boolean peaksEnabled)
+ {
+ this.peaksEnabled = peaksEnabled;
+ }
+
+ public int getFps()
+ {
+ return fps;
+ }
+
+ public void setFps(int fps)
+ {
+ this.fps = fps;
+ }
+
+ /**
+ * Starts DSP.
+ * @param line
+ */
+ public void startDSP(SourceDataLine line)
+ {
+ if (displayMode == DISPLAY_MODE_OFF) return;
+ if (line != null) m_line = line;
+ if (dsp == null)
+ {
+ dsp = new KJDigitalSignalProcessingAudioDataConsumer(2048, fps);
+ dsp.add(this);
+ }
+ if ((dsp != null) && (m_line != null))
+ {
+ if (dspStarted == true)
+ {
+ stopDSP();
+ }
+ dsp.start(m_line);
+ dspStarted = true;
+ log.debug("DSP started");
+ }
+ }
+
+ /**
+ * Stop DSP.
+ */
+ public void stopDSP()
+ {
+ if (dsp != null)
+ {
+ dsp.stop();
+ dspStarted = false;
+ log.debug("DSP stopped");
+ }
+ }
+
+ /**
+ * Close DSP
+ */
+ public void closeDSP()
+ {
+ if (dsp != null)
+ {
+ stopDSP();
+ dsp = null;
+ log.debug("DSP closed");
+ }
+ }
+
+ /**
+ * Setup DSP.
+ * @param line
+ */
+ public void setupDSP(SourceDataLine line)
+ {
+ if (dsp != null)
+ {
+ int channels = line.getFormat().getChannels();
+ if (channels == 1) dsp.setChannelMode(KJDigitalSignalProcessingAudioDataConsumer.CHANNEL_MODE_MONO);
+ else dsp.setChannelMode(KJDigitalSignalProcessingAudioDataConsumer.CHANNEL_MODE_STEREO);
+ int bits = line.getFormat().getSampleSizeInBits();
+ if (bits == 8) dsp.setSampleType(KJDigitalSignalProcessingAudioDataConsumer.SAMPLE_TYPE_EIGHT_BIT);
+ else dsp.setSampleType(KJDigitalSignalProcessingAudioDataConsumer.SAMPLE_TYPE_SIXTEEN_BIT);
+ }
+ }
+
+ /**
+ * Write PCM data to DSP.
+ * @param pcmdata
+ */
+ public void writeDSP(byte[] pcmdata)
+ {
+ if ((dsp != null) && (dspStarted == true)) dsp.writeAudioData(pcmdata);
+ }
+
+ /**
+ * Return DSP.
+ * @return
+ */
+ public KJDigitalSignalProcessingAudioDataConsumer getDSP()
+ {
+ return dsp;
+ }
+
+ /**
+ * Set visual colors from skin.
+ * @param viscolor
+ */
+ public void setVisColor(String viscolor)
+ {
+ ArrayList visColors = new ArrayList();
+ viscolor = viscolor.toLowerCase();
+ ByteArrayInputStream in = new ByteArrayInputStream(viscolor.getBytes());
+ BufferedReader bin = new BufferedReader(new InputStreamReader(in));
+ try
+ {
+ String line = null;
+ while ((line = bin.readLine()) != null)
+ {
+ visColors.add(getColor(line));
+ }
+ Color[] colors = new Color[visColors.size()];
+ visColors.toArray(colors);
+ Color[] specColors = new Color[15];
+ System.arraycopy(colors, 2, specColors, 0, 15);
+ List specList = Arrays.asList(specColors);
+ Collections.reverse(specList);
+ specColors = (Color[]) specList.toArray(specColors);
+ setSpectrumAnalyserColors(specColors);
+ setBackground((Color) visColors.get(0));
+ if (visColors.size()>23) setPeakColor((Color) visColors.get(23));
+ if (visColors.size()>18) setScopeColor((Color) visColors.get(18));
+ }
+ catch (IOException ex)
+ {
+ log.warn("Cannot parse viscolors", ex);
+ }
+ finally
+ {
+ try
+ {
+ if (bin != null) bin.close();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ /**
+ * Set visual peak color.
+ * @param c
+ */
+ public void setPeakColor(Color c)
+ {
+ peakColor = c;
+ }
+
+ /**
+ * Set peak falloff delay.
+ * @param framestowait
+ */
+ public void setPeakDelay(int framestowait)
+ {
+ int min = (int) Math.round((DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO - DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO_RANGE) * fps);
+ int max = (int) Math.round((DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO + DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO_RANGE) * fps);
+ if ((framestowait >= min) && (framestowait <= max))
+ {
+ peakDelay = framestowait;
+ }
+ else
+ {
+ peakDelay = (int) Math.round(DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO * fps);
+ }
+ }
+
+ /**
+ * Return peak falloff delay
+ * @return int framestowait
+ */
+ public int getPeakDelay()
+ {
+ return peakDelay;
+ }
+
+ /**
+ * Convert string to color.
+ * @param linecolor
+ * @return
+ */
+ public Color getColor(String linecolor)
+ {
+ Color color = Color.BLACK;
+ StringTokenizer st = new StringTokenizer(linecolor, ",");
+ int red = 0, green = 0, blue = 0;
+ try
+ {
+ if (st.hasMoreTokens()) red = Integer.parseInt(st.nextToken().trim());
+ if (st.hasMoreTokens()) green = Integer.parseInt(st.nextToken().trim());
+ if (st.hasMoreTokens())
+ {
+ String blueStr = st.nextToken().trim();
+ if (blueStr.length() > 3) blueStr = (blueStr.substring(0, 3)).trim();
+ blue = Integer.parseInt(blueStr);
+ }
+ color = new Color(red, green, blue);
+ }
+ catch (NumberFormatException e)
+ {
+ log.debug("Cannot parse viscolor : "+e.getMessage());
+ }
+ return color;
+ }
+
+ private void computeColorScale()
+ {
+ saColorScale = ((float) spectrumAnalyserColors.length / height) * barOffset * 1.0f;
+ vuColorScale = ((float) spectrumAnalyserColors.length / (width - 32)) * 2.0f;
+ }
+
+ private void computeSAMultiplier()
+ {
+ saMultiplier = (saFFTSampleSize / 2) / saBands;
+ }
+
+ private void drawScope(Graphics pGrp, float[] pSample)
+ {
+ pGrp.setColor(scopeColor);
+ int wLas = (int) (pSample[0] * (float) height_2) + height_2;
+ int wSt = 2;
+ for (int a = wSt, c = 0; c < width; a += wSt, c++)
+ {
+ int wAs = (int) (pSample[a] * (float) height_2) + height_2;
+ pGrp.drawLine(c, wLas, c + 1, wAs);
+ wLas = wAs;
+ }
+ }
+
+ private void drawSpectrumAnalyser(Graphics pGrp, float[] pSample, float pFrrh)
+ {
+ float c = 0;
+ float[] wFFT = fft.calculate(pSample);
+ float wSadfrr = (saDecay * pFrrh);
+ float wBw = ((float) width / (float) saBands);
+ for (int a = 0, bd = 0; bd < saBands; a += saMultiplier, bd++)
+ {
+ float wFs = 0;
+ // -- Average out nearest bands.
+ for (int b = 0; b < saMultiplier; b++)
+ {
+ wFs += wFFT[a + b];
+ }
+ // -- Log filter.
+ wFs = (wFs * (float) Math.log(bd + 2));
+ if (wFs > 1.0f)
+ {
+ wFs = 1.0f;
+ }
+ // -- Compute SA decay...
+ if (wFs >= (old_FFT[a] - wSadfrr))
+ {
+ old_FFT[a] = wFs;
+ }
+ else
+ {
+ old_FFT[a] -= wSadfrr;
+ if (old_FFT[a] < 0)
+ {
+ old_FFT[a] = 0;
+ }
+ wFs = old_FFT[a];
+ }
+ drawSpectrumAnalyserBar(pGrp, (int) c, height, (int) wBw - 1, (int) (wFs * height), bd);
+ c += wBw;
+ }
+ }
+
+ private void drawVUMeter(Graphics pGrp, float[] pLeft, float[] pRight, float pFrrh)
+ {
+ if (displayMode == DISPLAY_MODE_OFF) return;
+ float wLeft = 0.0f;
+ float wRight = 0.0f;
+ float wSadfrr = (vuDecay * pFrrh);
+ for (int a = 0; a < pLeft.length; a++)
+ {
+ wLeft += Math.abs(pLeft[a]);
+ wRight += Math.abs(pRight[a]);
+ }
+ wLeft = ((wLeft * 2.0f) / (float) pLeft.length);
+ wRight = ((wRight * 2.0f) / (float) pRight.length);
+ if (wLeft > 1.0f)
+ {
+ wLeft = 1.0f;
+ }
+ if (wRight > 1.0f)
+ {
+ wRight = 1.0f;
+ }
+ // vuAverage += ( ( wLeft + wRight ) / 2.0f );
+ // vuSamples++;
+ //
+ // if ( vuSamples > 128 ) {
+ // vuSamples /= 2.0f;
+ // vuAverage /= 2.0f;
+ // }
+ if (wLeft >= (oldLeft - wSadfrr))
+ {
+ oldLeft = wLeft;
+ }
+ else
+ {
+ oldLeft -= wSadfrr;
+ if (oldLeft < 0)
+ {
+ oldLeft = 0;
+ }
+ }
+ if (wRight >= (oldRight - wSadfrr))
+ {
+ oldRight = wRight;
+ }
+ else
+ {
+ oldRight -= wSadfrr;
+ if (oldRight < 0)
+ {
+ oldRight = 0;
+ }
+ }
+ int wHeight = (height >> 1) - 24;
+ drawVolumeMeterBar(pGrp, 16, 16, (int) (oldLeft * (float) (width - 32)), wHeight);
+ // drawVolumeMeterBar( pGrp, 16, wHeight + 22, (int)( ( vuAverage / vuSamples ) * (float)( width - 32 ) ), 4 );
+ drawVolumeMeterBar(pGrp, 16, wHeight + 32, (int) (oldRight * (float) (width - 32)), wHeight);
+ // pGrp.fillRect( 16, 16, (int)( oldLeft * (float)( width - 32 ) ), wHeight );
+ // pGrp.fillRect( 16, 64, (int)( oldRight * (float)( width - 32 ) ), wHeight );
+ }
+
+ private void drawSpectrumAnalyserBar(Graphics pGraphics, int pX, int pY, int pWidth, int pHeight, int band)
+ {
+ float c = 0;
+ for (int a = pY; a >= pY - pHeight; a -= barOffset)
+ {
+ c += saColorScale;
+ if (c < spectrumAnalyserColors.length)
+ {
+ pGraphics.setColor(spectrumAnalyserColors[(int) c]);
+ }
+ pGraphics.fillRect(pX, a, pWidth, 1);
+ }
+ if ((peakColor != null) && (peaksEnabled == true))
+ {
+ pGraphics.setColor(peakColor);
+ if (pHeight > peaks[band])
+ {
+ peaks[band] = pHeight;
+ peaksDelay[band] = peakDelay;
+ }
+ else
+ {
+ peaksDelay[band]--;
+ if (peaksDelay[band] < 0) peaks[band]--;
+ if (peaks[band] < 0) peaks[band] = 0;
+ }
+ pGraphics.fillRect(pX, pY - peaks[band], pWidth, 1);
+ }
+ }
+
+ private void drawVolumeMeterBar(Graphics pGraphics, int pX, int pY, int pWidth, int pHeight)
+ {
+ float c = 0;
+ for (int a = pX; a <= pX + pWidth; a += 2)
+ {
+ c += vuColorScale;
+ if (c < 256.0f)
+ {
+ pGraphics.setColor(spectrumAnalyserColors[(int) c]);
+ }
+ pGraphics.fillRect(a, pY, 1, pHeight);
+ }
+ }
+
+ private synchronized Image getDoubleBuffer()
+ {
+ if (bi == null || (bi.getWidth(null) != getSize().width || bi.getHeight(null) != getSize().height))
+ {
+ width = getSize().width;
+ height = getSize().height;
+ height_2 = height >> 1;
+ computeColorScale();
+ bi = getGraphicsConfiguration().createCompatibleVolatileImage(width, height);
+ }
+ return bi;
+ }
+
+ public static Color[] getDefaultSpectrumAnalyserColors()
+ {
+ Color[] wColors = new Color[256];
+ for (int a = 0; a < 128; a++)
+ {
+ wColors[a] = new Color(0, (a >> 1) + 192, 0);
+ }
+ for (int a = 0; a < 64; a++)
+ {
+ wColors[a + 128] = new Color(a << 2, 255, 0);
+ }
+ for (int a = 0; a < 64; a++)
+ {
+ wColors[a + 192] = new Color(255, 255 - (a << 2), 0);
+ }
+ return wColors;
+ }
+
+ /**
+ * @return Returns the current display mode, DISPLAY_MODE_SCOPE or DISPLAY_MODE_SPECTRUM_ANALYSER.
+ */
+ public int getDisplayMode()
+ {
+ return displayMode;
+ }
+
+ /**
+ * @return Returns the current number of bands displayed by the spectrum analyser.
+ */
+ public int getSpectrumAnalyserBandCount()
+ {
+ return saBands;
+ }
+
+ /**
+ * @return Returns the decay rate of the spectrum analyser's bands.
+ */
+ public float getSpectrumAnalyserDecay()
+ {
+ return saDecay;
+ }
+
+ /**
+ * @return Returns the color the scope is rendered in.
+ */
+ public Color getScopeColor()
+ {
+ return scopeColor;
+ }
+
+ /**
+ * @return Returns the color scale used to render the spectrum analyser bars.
+ */
+ public Color[] getSpectrumAnalyserColors()
+ {
+ return spectrumAnalyserColors;
+ }
+
+ private void initialize()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ setBackground(DEFAULT_BACKGROUND_COLOR);
+ prepareDisplayToggleListener();
+ setSpectrumAnalyserBandCount(DEFAULT_SPECTRUM_ANALYSER_BAND_COUNT);
+ setSpectrumAnalyserFFTSampleSize(DEFAULT_SPECTRUM_ANALYSER_FFT_SAMPLE_SIZE);
+ }
+
+ /**
+ * @return Returns 'true' if "Frames Per Second" are being calculated and displayed.
+ */
+ public boolean isShowingFPS()
+ {
+ return showFPS;
+ }
+
+ public void paintComponent(Graphics pGraphics)
+ {
+ if (displayMode == DISPLAY_MODE_OFF) return;
+ if (dspStarted)
+ {
+ pGraphics.drawImage(getDoubleBuffer(), 0, 0, null);
+ }
+ else
+ {
+ super.paintComponent(pGraphics);
+ }
+ }
+
+ private void prepareDisplayToggleListener()
+ {
+ setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ addMouseListener(new MouseAdapter()
+ {
+ public void mouseClicked(MouseEvent pEvent)
+ {
+ if (pEvent.getButton() == MouseEvent.BUTTON1)
+ {
+ if (displayMode + 1 > 1)
+ {
+ displayMode = 0;
+ }
+ else
+ {
+ displayMode++;
+ }
+ }
+ }
+ });
+ }
+
+ /* (non-Javadoc)
+ * @see kj.dsp.KJDigitalSignalProcessor#process(float[], float[], float)
+ */
+ public synchronized void process(float[] pLeft, float[] pRight, float pFrameRateRatioHint)
+ {
+ if (displayMode == DISPLAY_MODE_OFF) return;
+ Graphics wGrp = getDoubleBuffer().getGraphics();
+ wGrp.setColor(getBackground());
+ wGrp.fillRect(0, 0, getSize().width, getSize().height);
+ switch (displayMode)
+ {
+ case DISPLAY_MODE_SCOPE:
+ drawScope(wGrp, stereoMerge(pLeft, pRight));
+ break;
+ case DISPLAY_MODE_SPECTRUM_ANALYSER:
+ drawSpectrumAnalyser(wGrp, stereoMerge(pLeft, pRight), pFrameRateRatioHint);
+ break;
+ case DISPLAY_MODE_OFF:
+ drawVUMeter(wGrp, pLeft, pRight, pFrameRateRatioHint);
+ break;
+ }
+ // -- Show FPS if necessary.
+ if (showFPS)
+ {
+ // -- Calculate FPS.
+ if (System.currentTimeMillis() >= lfu + 1000)
+ {
+ lfu = System.currentTimeMillis();
+ fps = fc;
+ fc = 0;
+ }
+ fc++;
+ wGrp.setColor(Color.yellow);
+ wGrp.drawString("FPS: " + fps + " (FRRH: " + pFrameRateRatioHint + ")", 0, height - 1);
+ }
+ if (getGraphics() != null) getGraphics().drawImage(getDoubleBuffer(), 0, 0, null);
+ // repaint();
+ // try {
+ // EventQueue.invokeLater( new AWTPaintSynchronizer() );
+ // } catch ( Exception pEx ) {
+ // // -- Ignore exception.
+ // pEx.printStackTrace();
+ // }
+ }
+
+ /**
+ * Sets the current display mode.
+ *
+ * @param pMode Must be either DISPLAY_MODE_SCOPE or DISPLAY_MODE_SPECTRUM_ANALYSER.
+ */
+ public synchronized void setDisplayMode(int pMode)
+ {
+ displayMode = pMode;
+ }
+
+ /**
+ * Sets the color of the scope.
+ *
+ * @param pColor
+ */
+ public synchronized void setScopeColor(Color pColor)
+ {
+ scopeColor = pColor;
+ }
+
+ /**
+ * When 'true' is passed as a parameter, will overlay the "Frames Per Seconds"
+ * achieved by the component.
+ *
+ * @param pState
+ */
+ public synchronized void setShowFPS(boolean pState)
+ {
+ showFPS = pState;
+ }
+
+ /**
+ * Sets the numbers of bands rendered by the spectrum analyser.
+ *
+ * @param pCount Cannot be more than half the "FFT sample size".
+ */
+ public synchronized void setSpectrumAnalyserBandCount(int pCount)
+ {
+ saBands = pCount;
+ peaks = new int[saBands];
+ peaksDelay = new int[saBands];
+ computeSAMultiplier();
+ }
+
+ /**
+ * Sets the spectrum analyser band decay rate.
+ *
+ * @param pDecay Must be a number between 0.0 and 1.0 exclusive.
+ */
+ public synchronized void setSpectrumAnalyserDecay(float pDecay)
+ {
+ if ((pDecay >= MIN_SPECTRUM_ANALYSER_DECAY) && (pDecay <= MAX_SPECTRUM_ANALYSER_DECAY))
+ {
+ saDecay = pDecay;
+ }
+ else saDecay = DEFAULT_SPECTRUM_ANALYSER_DECAY;
+ }
+
+ /**
+ * Sets the spectrum analyser color scale.
+ *
+ * @param pColors Any amount of colors may be used. Must not be null.
+ */
+ public synchronized void setSpectrumAnalyserColors(Color[] pColors)
+ {
+ spectrumAnalyserColors = pColors;
+ computeColorScale();
+ }
+
+ /**
+ * Sets the FFT sample size to be just for calculating the spectrum analyser
+ * values. The default is 512.
+ *
+ * @param pSize Cannot be more than the size of the sample provided by the DSP.
+ */
+ public synchronized void setSpectrumAnalyserFFTSampleSize(int pSize)
+ {
+ saFFTSampleSize = pSize;
+ fft = new KJFFT(saFFTSampleSize);
+ old_FFT = new float[saFFTSampleSize];
+ computeSAMultiplier();
+ }
+
+ private float[] stereoMerge(float[] pLeft, float[] pRight)
+ {
+ for (int a = 0; a < pLeft.length; a++)
+ {
+ pLeft[a] = (pLeft[a] + pRight[a]) / 2.0f;
+ }
+ return pLeft;
+ }
+
+ /*public void update(Graphics pGraphics)
+ {
+ // -- Prevent AWT from clearing background.
+ paint(pGraphics);
+ }*/
+}