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); + }*/ +}