From c0e4c10b07ae0deafa669deda10b4aee12dd67f5 Mon Sep 17 00:00:00 2001 From: Bram Veenboer Date: Fri, 3 Jun 2011 12:37:02 +0000 Subject: [PATCH] Diverse wijzigingen mbt loggen en activate/deactivate aangebracht. jlgui player wordt niet gebruikt, dus verwijderd. --- java/cfg/jlgui.ini | 29 - java/cfg/log4j.properties | 3 +- .../jlgui/basicplayer/BasicController.java | 102 - .../jlgui/basicplayer/BasicPlayer.java | 1038 ---------- .../jlgui/basicplayer/BasicPlayerEvent.java | 121 -- .../basicplayer/BasicPlayerEventLauncher.java | 73 - .../basicplayer/BasicPlayerException.java | 107 - .../basicplayer/BasicPlayerListener.java | 72 - .../src/javazoom/jlgui/player/amp/Loader.java | 40 - .../jlgui/player/amp/PlayerActionEvent.java | 99 - .../javazoom/jlgui/player/amp/PlayerUI.java | 1827 ----------------- .../jlgui/player/amp/StandalonePlayer.java | 500 ----- .../player/amp/equalizer/ui/ControlCurve.java | 139 -- .../jlgui/player/amp/equalizer/ui/Cubic.java | 46 - .../player/amp/equalizer/ui/EqualizerUI.java | 441 ---- .../amp/equalizer/ui/NaturalSpline.java | 108 - .../player/amp/equalizer/ui/SplinePanel.java | 133 -- .../javazoom/jlgui/player/amp/jlguiicon.gif | Bin 566 -> 0 bytes java/src/javazoom/jlgui/player/amp/metrix.wsz | Bin 188618 -> 0 bytes .../player/amp/playlist/BasePlaylist.java | 586 ------ .../jlgui/player/amp/playlist/Playlist.java | 138 -- .../player/amp/playlist/PlaylistFactory.java | 107 - .../player/amp/playlist/PlaylistItem.java | 302 --- .../player/amp/playlist/ui/PlaylistUI.java | 882 -------- .../player/amp/skin/AbsoluteConstraints.java | 151 -- .../jlgui/player/amp/skin/AbsoluteLayout.java | 196 -- .../jlgui/player/amp/skin/ActiveFont.java | 88 - .../jlgui/player/amp/skin/ActiveJBar.java | 45 - .../jlgui/player/amp/skin/ActiveJButton.java | 48 - .../jlgui/player/amp/skin/ActiveJIcon.java | 62 - .../jlgui/player/amp/skin/ActiveJLabel.java | 104 - .../player/amp/skin/ActiveJNumberLabel.java | 61 - .../jlgui/player/amp/skin/ActiveJPopup.java | 70 - .../jlgui/player/amp/skin/ActiveJSlider.java | 58 - .../player/amp/skin/ActiveJToggleButton.java | 47 - .../jlgui/player/amp/skin/ActiveSliderUI.java | 146 -- .../jlgui/player/amp/skin/DragAdapter.java | 68 - .../player/amp/skin/DropTargetAdapter.java | 163 -- .../jlgui/player/amp/skin/ImageBorder.java | 65 - .../player/amp/skin/PlaylistUIDelegate.java | 276 --- .../jlgui/player/amp/skin/PopupAdapter.java | 61 - .../javazoom/jlgui/player/amp/skin/Skin.java | 1493 -------------- .../jlgui/player/amp/skin/SkinLoader.java | 124 -- .../javazoom/jlgui/player/amp/skin/Taftb.java | 153 -- .../jlgui/player/amp/skin/UrlDialog.java | 148 -- .../jlgui/player/amp/skin/skin.properties | 65 - .../jlgui/player/amp/tag/APEInfo.java | 340 --- .../jlgui/player/amp/tag/FlacInfo.java | 189 -- .../jlgui/player/amp/tag/MpegInfo.java | 315 --- .../jlgui/player/amp/tag/OggVorbisInfo.java | 307 --- .../jlgui/player/amp/tag/TagInfo.java | 120 -- .../jlgui/player/amp/tag/TagInfoFactory.java | 399 ---- .../jlgui/player/amp/tag/ui/APEDialog.java | 187 -- .../jlgui/player/amp/tag/ui/EmptyDialog.java | 75 - .../jlgui/player/amp/tag/ui/FlacDialog.java | 165 -- .../jlgui/player/amp/tag/ui/MpegDialog.java | 194 -- .../player/amp/tag/ui/OggVorbisDialog.java | 196 -- .../player/amp/tag/ui/TagInfoDialog.java | 60 - .../jlgui/player/amp/tag/ui/TagSearch.java | 434 ---- .../jlgui/player/amp/tag/ui/tag.properties | 8 - .../jlgui/player/amp/util/BMPLoader.java | 301 --- .../jlgui/player/amp/util/Config.java | 711 ------- .../jlgui/player/amp/util/FileNameFilter.java | 108 - .../jlgui/player/amp/util/FileSelector.java | 156 -- .../jlgui/player/amp/util/FileUtil.java | 167 -- .../player/amp/util/ini/Alphabetizer.java | 79 - .../jlgui/player/amp/util/ini/Array.java | 114 - .../amp/util/ini/CRC32OutputStream.java | 50 - .../player/amp/util/ini/Configuration.java | 441 ---- .../player/amp/util/ini/SortedStrings.java | 338 --- .../player/amp/util/ui/DevicePreference.java | 120 -- .../player/amp/util/ui/EmptyPreference.java | 52 - .../jlgui/player/amp/util/ui/NodeItem.java | 46 - .../player/amp/util/ui/OutputPreference.java | 54 - .../player/amp/util/ui/PreferenceItem.java | 78 - .../jlgui/player/amp/util/ui/Preferences.java | 279 --- .../player/amp/util/ui/SkinPreference.java | 185 -- .../player/amp/util/ui/SystemPreference.java | 91 - .../player/amp/util/ui/TypePreference.java | 129 -- .../player/amp/util/ui/VisualPreference.java | 292 --- .../amp/util/ui/VisualizationPreference.java | 54 - .../player/amp/util/ui/device.properties | 6 - .../player/amp/util/ui/output.properties | 2 - .../player/amp/util/ui/preferences.properties | 27 - .../jlgui/player/amp/util/ui/skin.properties | 4 - .../player/amp/util/ui/system.properties | 3 - .../jlgui/player/amp/util/ui/type.properties | 2 - .../player/amp/util/ui/visual.properties | 15 - .../amp/util/ui/visualization.properties | 2 - .../amp/visual/ui/SpectrumTimeAnalyzer.java | 775 ------- java/src/mimis/Application.java | 11 +- java/src/mimis/Client.java | 2 - java/src/mimis/Device.java | 14 +- java/src/mimis/Exitable.java | 2 +- java/src/mimis/GUI.java | 2 +- java/src/mimis/Main.java | 9 +- java/src/mimis/Manager.java | 2 +- java/src/mimis/Mimis.java | 27 +- java/src/mimis/Worker.java | 13 +- .../mimis/application/cmd/CMDApplication.java | 11 +- .../cmd/windows/WindowsApplication.java | 8 +- .../gomplayer/GomPlayerApplication.java | 2 +- .../cmd/windows/winamp/WinampApplication.java | 2 +- .../cmd/windows/wmp/WMPApplication.java | 3 +- .../application/itunes/iTunesApplication.java | 36 +- .../mimis/application/mpc/MPCApplication.java | 3 +- .../mimis/application/vlc/VLCApplication.java | 23 +- .../device/javainput/JavaInputDevice.java | 23 +- .../device/javainput/JavaInputListener.java | 54 +- .../javainput/extreme3d/Extreme3DDevice.java | 9 +- .../javainput/rumblepad/RumblepadDevice.java | 3 +- .../jintellitype/JIntellitypeDevice.java | 23 +- java/src/mimis/device/lirc/LircDevice.java | 6 +- java/src/mimis/device/lirc/LircService.java | 32 +- .../mimis/device/network/NetworkDevice.java | 17 +- .../src/mimis/device/player/PlayerDevice.java | 23 - .../mimis/device/wiimote/WiimoteDevice.java | 4 +- java/src/mimis/exception/ExitException.java | 5 + .../exception/worker/ActivateException.java | 7 + .../exception/worker/DeactivateException.java | 7 + java/src/mimis/manager/SelectButton.java | 18 +- java/src/mimis/util/Multiplexer.java | 14 +- 122 files changed, 221 insertions(+), 18449 deletions(-) delete mode 100644 java/cfg/jlgui.ini delete mode 100644 java/src/javazoom/jlgui/basicplayer/BasicController.java delete mode 100644 java/src/javazoom/jlgui/basicplayer/BasicPlayer.java delete mode 100644 java/src/javazoom/jlgui/basicplayer/BasicPlayerEvent.java delete mode 100644 java/src/javazoom/jlgui/basicplayer/BasicPlayerEventLauncher.java delete mode 100644 java/src/javazoom/jlgui/basicplayer/BasicPlayerException.java delete mode 100644 java/src/javazoom/jlgui/basicplayer/BasicPlayerListener.java delete mode 100644 java/src/javazoom/jlgui/player/amp/Loader.java delete mode 100644 java/src/javazoom/jlgui/player/amp/PlayerActionEvent.java delete mode 100644 java/src/javazoom/jlgui/player/amp/PlayerUI.java delete mode 100644 java/src/javazoom/jlgui/player/amp/StandalonePlayer.java delete mode 100644 java/src/javazoom/jlgui/player/amp/equalizer/ui/ControlCurve.java delete mode 100644 java/src/javazoom/jlgui/player/amp/equalizer/ui/Cubic.java delete mode 100644 java/src/javazoom/jlgui/player/amp/equalizer/ui/EqualizerUI.java delete mode 100644 java/src/javazoom/jlgui/player/amp/equalizer/ui/NaturalSpline.java delete mode 100644 java/src/javazoom/jlgui/player/amp/equalizer/ui/SplinePanel.java delete mode 100644 java/src/javazoom/jlgui/player/amp/jlguiicon.gif delete mode 100644 java/src/javazoom/jlgui/player/amp/metrix.wsz delete mode 100644 java/src/javazoom/jlgui/player/amp/playlist/BasePlaylist.java delete mode 100644 java/src/javazoom/jlgui/player/amp/playlist/Playlist.java delete mode 100644 java/src/javazoom/jlgui/player/amp/playlist/PlaylistFactory.java delete mode 100644 java/src/javazoom/jlgui/player/amp/playlist/PlaylistItem.java delete mode 100644 java/src/javazoom/jlgui/player/amp/playlist/ui/PlaylistUI.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/AbsoluteConstraints.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/AbsoluteLayout.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/ActiveFont.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/ActiveJBar.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/ActiveJButton.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/ActiveJIcon.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/ActiveJLabel.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/ActiveJNumberLabel.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/ActiveJPopup.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/ActiveJSlider.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/ActiveJToggleButton.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/ActiveSliderUI.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/DragAdapter.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/DropTargetAdapter.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/ImageBorder.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/PlaylistUIDelegate.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/PopupAdapter.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/Skin.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/SkinLoader.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/Taftb.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/UrlDialog.java delete mode 100644 java/src/javazoom/jlgui/player/amp/skin/skin.properties delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/APEInfo.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/FlacInfo.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/MpegInfo.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/OggVorbisInfo.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/TagInfo.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/TagInfoFactory.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/ui/APEDialog.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/ui/EmptyDialog.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/ui/FlacDialog.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/ui/MpegDialog.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/ui/OggVorbisDialog.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/ui/TagInfoDialog.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/ui/TagSearch.java delete mode 100644 java/src/javazoom/jlgui/player/amp/tag/ui/tag.properties delete mode 100644 java/src/javazoom/jlgui/player/amp/util/BMPLoader.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/Config.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/FileNameFilter.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/FileSelector.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/FileUtil.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ini/Alphabetizer.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ini/Array.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ini/CRC32OutputStream.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ini/Configuration.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ini/SortedStrings.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/DevicePreference.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/EmptyPreference.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/NodeItem.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/OutputPreference.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/PreferenceItem.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/Preferences.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/SkinPreference.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/SystemPreference.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/TypePreference.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/VisualPreference.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/VisualizationPreference.java delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/device.properties delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/output.properties delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/preferences.properties delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/skin.properties delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/system.properties delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/type.properties delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/visual.properties delete mode 100644 java/src/javazoom/jlgui/player/amp/util/ui/visualization.properties delete mode 100644 java/src/javazoom/jlgui/player/amp/visual/ui/SpectrumTimeAnalyzer.java delete mode 100644 java/src/mimis/device/player/PlayerDevice.java create mode 100644 java/src/mimis/exception/ExitException.java create mode 100644 java/src/mimis/exception/worker/ActivateException.java create mode 100644 java/src/mimis/exception/worker/DeactivateException.java diff --git a/java/cfg/jlgui.ini b/java/cfg/jlgui.ini deleted file mode 100644 index a8081f1..0000000 --- a/java/cfg/jlgui.ini +++ /dev/null @@ -1,29 +0,0 @@ -allowed_extensions=m3u,pls,wsz,snd,aifc,aif,wav,au,mp1,mp2,mp3,ogg,spx,flac,ape,mac -audio_device= -equalizer_auto=false -equalizer_enabled=false -equalizer_on=false -last_dir=C:\Users\Rik\Downloads\Skins\ -last_equalizer=50,50,92,100,10,40,0,100,50,50,50 -last_playlist= -last_skin=C:\Users\Rik\Downloads\Skins\GSM_Winamp_FrostedFlames.wsz -last_skin_dir= -last_url= -origine_x=636 -origine_y=282 -playlist_enabled=false -playlist_impl=javazoom.jlgui.player.amp.playlist.BasePlaylist -proxy_login= -proxy_password= -proxy_port=-1 -proxy_server= -repeat_enabled=false -screen_limit=false -shuffle_enabled=false -taginfo_ape_impl=javazoom.jlgui.player.amp.tag.APEInfo -taginfo_flac_impl=javazoom.jlgui.player.amp.tag.FlacInfo -taginfo_mpeg_impl=javazoom.jlgui.player.amp.tag.MpegInfo -taginfo_oggvorbis_impl=javazoom.jlgui.player.amp.tag.OggVorbisInfo -taginfo_policy=file -visual_mode= -volume_value=-1 diff --git a/java/cfg/log4j.properties b/java/cfg/log4j.properties index 62c7729..0430f10 100644 --- a/java/cfg/log4j.properties +++ b/java/cfg/log4j.properties @@ -1,5 +1,4 @@ log4j.rootLogger=DEBUG, CA log4j.appender.CA=org.apache.log4j.ConsoleAppender log4j.appender.CA.layout=org.apache.log4j.PatternLayout -log4j.appender.CA.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n -log4j.logger.org.hibernate=TRACE \ No newline at end of file +log4j.appender.CA.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n \ No newline at end of file diff --git a/java/src/javazoom/jlgui/basicplayer/BasicController.java b/java/src/javazoom/jlgui/basicplayer/BasicController.java deleted file mode 100644 index c194ffc..0000000 --- a/java/src/javazoom/jlgui/basicplayer/BasicController.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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 deleted file mode 100644 index e587bb7..0000000 --- a/java/src/javazoom/jlgui/basicplayer/BasicPlayer.java +++ /dev/null @@ -1,1038 +0,0 @@ -/* - * 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); - } - } - } - - /** - * NetworkClient 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) - { - // NetworkClient 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 running()", 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 deleted file mode 100644 index 9726c3b..0000000 --- a/java/src/javazoom/jlgui/basicplayer/BasicPlayerEvent.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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 deleted file mode 100644 index d3ef1ef..0000000 --- a/java/src/javazoom/jlgui/basicplayer/BasicPlayerEventLauncher.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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 deleted file mode 100644 index e2f2893..0000000 --- a/java/src/javazoom/jlgui/basicplayer/BasicPlayerException.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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 deleted file mode 100644 index 9e05d2e..0000000 --- a/java/src/javazoom/jlgui/basicplayer/BasicPlayerListener.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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 deleted file mode 100644 index dd70ea9..0000000 --- a/java/src/javazoom/jlgui/player/amp/Loader.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 deleted file mode 100644 index 0c1b98c..0000000 --- a/java/src/javazoom/jlgui/player/amp/PlayerActionEvent.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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 deleted file mode 100644 index dba11e0..0000000 --- a/java/src/javazoom/jlgui/player/amp/PlayerUI.java +++ /dev/null @@ -1,1827 +0,0 @@ -/* - * 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 deleted file mode 100644 index 9eab1f9..0000000 --- a/java/src/javazoom/jlgui/player/amp/StandalonePlayer.java +++ /dev/null @@ -1,500 +0,0 @@ -/* - * 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 deleted file mode 100644 index 951d879..0000000 --- a/java/src/javazoom/jlgui/player/amp/equalizer/ui/ControlCurve.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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 deleted file mode 100644 index f2471e4..0000000 --- a/java/src/javazoom/jlgui/player/amp/equalizer/ui/Cubic.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 deleted file mode 100644 index 7410296..0000000 --- a/java/src/javazoom/jlgui/player/amp/equalizer/ui/EqualizerUI.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - * 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 deleted file mode 100644 index 6e0ba31..0000000 --- a/java/src/javazoom/jlgui/player/amp/equalizer/ui/NaturalSpline.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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 deleted file mode 100644 index df2a091..0000000 --- a/java/src/javazoom/jlgui/player/amp/equalizer/ui/SplinePanel.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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 deleted file mode 100644 index d44ea3138460265e071cde9539aaffc465487bc9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 566 zcmZ?wbhEHb6krfwc*el+9|RbH@IM2H17rayAQp2f`t$dntY58MK)rlmgJMXta#*Ws zWQST*r)FG_Udlv+^eIM}(~PsGn`BQn&zogkJkOzGk!$U;uRs6zwyg1QTNl~CHEP1v zv{`$9{QjFUXJ65hBX#RecW%AVvE}@mFFz;jx;%aV_1TAR&N_Hw&f%Mjj^9~&^6rY$ z_tsx{wEyOd!*^aCy8ZIhgE#NK{@irw@y3gfwp@O^{p!=BcVAt4`u_5>57%CNy!!mZ z?bn}gz4~VU~g(}X>DRq zGVkb8GVAD5YElw)m~21UWya)ohPm_R&zrMgF~g#zqH0T)v2$>&SkNRb?d-f}Er*C2 zr~6WNSEmEpwsWZ2C^p&I+SwiAkYiAHbZj!Ry0-1Sla0xpCNm35OZM}o)`riYH)-qY z={vg_8+`g?X4WJuE-53gpsb>*5ws%Vpwk5=RxSyXf)5N%ESzEn87~r6C@pkgum%7F Cna8OB diff --git a/java/src/javazoom/jlgui/player/amp/metrix.wsz b/java/src/javazoom/jlgui/player/amp/metrix.wsz deleted file mode 100644 index 58fd9ad84f650e34519e29b59d72c61aa75c53cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188618 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¥+%L2*iQeuhL0oZ`~b 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 diff --git a/java/src/javazoom/jlgui/player/amp/playlist/BasePlaylist.java b/java/src/javazoom/jlgui/player/amp/playlist/BasePlaylist.java deleted file mode 100644 index ee21df1..0000000 --- a/java/src/javazoom/jlgui/player/amp/playlist/BasePlaylist.java +++ /dev/null @@ -1,586 +0,0 @@ -/* - * 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 deleted file mode 100644 index ade6beb..0000000 --- a/java/src/javazoom/jlgui/player/amp/playlist/Playlist.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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 deleted file mode 100644 index c9c38d1..0000000 --- a/java/src/javazoom/jlgui/player/amp/playlist/PlaylistFactory.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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 deleted file mode 100644 index df2440c..0000000 --- a/java/src/javazoom/jlgui/player/amp/playlist/PlaylistItem.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * 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 deleted file mode 100644 index b7d0222..0000000 --- a/java/src/javazoom/jlgui/player/amp/playlist/ui/PlaylistUI.java +++ /dev/null @@ -1,882 +0,0 @@ -/* - * 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 deleted file mode 100644 index d0961ed..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/AbsoluteConstraints.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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 deleted file mode 100644 index 4f9ead0..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/AbsoluteLayout.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * 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 deleted file mode 100644 index a0eba43..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/ActiveFont.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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 deleted file mode 100644 index d45c40d..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/ActiveJBar.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 deleted file mode 100644 index f6cde82..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/ActiveJButton.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 deleted file mode 100644 index c6d4bc1..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/ActiveJIcon.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 deleted file mode 100644 index 6e1aa71..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/ActiveJLabel.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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 deleted file mode 100644 index 0505543..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/ActiveJNumberLabel.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 deleted file mode 100644 index 191aa84..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/ActiveJPopup.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 deleted file mode 100644 index 75a10bc..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/DragAdapter.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 deleted file mode 100644 index 46b6a98..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/DropTargetAdapter.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 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 deleted file mode 100644 index 50fa8a1..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/ImageBorder.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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 deleted file mode 100644 index 1671688..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/PlaylistUIDelegate.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * 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 deleted file mode 100644 index 3616a74..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/PopupAdapter.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 deleted file mode 100644 index acd85fb..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/Skin.java +++ /dev/null @@ -1,1493 +0,0 @@ -/* - * 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 deleted file mode 100644 index 6ccb3df..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/SkinLoader.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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 deleted file mode 100644 index 9343d27..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/Taftb.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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 deleted file mode 100644 index e15005e..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/UrlDialog.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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 deleted file mode 100644 index a7c9235..0000000 --- a/java/src/javazoom/jlgui/player/amp/skin/skin.properties +++ /dev/null @@ -1,65 +0,0 @@ -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 deleted file mode 100644 index 838737f..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/APEInfo.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * 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 deleted file mode 100644 index 70d1712..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/FlacInfo.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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 deleted file mode 100644 index 18ee050..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/MpegInfo.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * 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 deleted file mode 100644 index 8ea28cd..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/OggVorbisInfo.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * 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 deleted file mode 100644 index 86e05d5..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/TagInfo.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 deleted file mode 100644 index 13281f1..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/TagInfoFactory.java +++ /dev/null @@ -1,399 +0,0 @@ -/* - * 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 deleted file mode 100644 index 001bca3..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/ui/APEDialog.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * 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 deleted file mode 100644 index 147f6c9..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/ui/EmptyDialog.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 deleted file mode 100644 index f506a67..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/ui/FlacDialog.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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 deleted file mode 100644 index 2782bed..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/ui/MpegDialog.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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 deleted file mode 100644 index 16a84e6..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/ui/OggVorbisDialog.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * 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 deleted file mode 100644 index bd12b12..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/ui/TagInfoDialog.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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 deleted file mode 100644 index 3faf9d6..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/ui/TagSearch.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * 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 deleted file mode 100644 index 9d9c18f..0000000 --- a/java/src/javazoom/jlgui/player/amp/tag/ui/tag.properties +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index a5e46c7..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/BMPLoader.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * 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 deleted file mode 100644 index e8f0d35..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/Config.java +++ /dev/null @@ -1,711 +0,0 @@ -/* - * 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 deleted file mode 100644 index 4a0685a..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/FileNameFilter.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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 deleted file mode 100644 index be2bdd9..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/FileSelector.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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 deleted file mode 100644 index 34a33ba..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/FileUtil.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * 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 deleted file mode 100644 index ac016a3..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ini/Alphabetizer.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 deleted file mode 100644 index 7f1ced3..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ini/Array.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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 deleted file mode 100644 index c38fb91..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ini/CRC32OutputStream.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 deleted file mode 100644 index 3a815e1..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ini/Configuration.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - * 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 deleted file mode 100644 index c6aa391..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ini/SortedStrings.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * 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 deleted file mode 100644 index b08201f..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/DevicePreference.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 deleted file mode 100644 index 272755b..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/EmptyPreference.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 deleted file mode 100644 index 9a5628e..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/NodeItem.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 deleted file mode 100644 index 3b1bc42..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/OutputPreference.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 deleted file mode 100644 index 3297e61..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/PreferenceItem.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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 deleted file mode 100644 index 20d80a1..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/Preferences.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * 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 deleted file mode 100644 index 6c9e0e3..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/SkinPreference.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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 deleted file mode 100644 index 0ab6503..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/SystemPreference.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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 deleted file mode 100644 index e1f62f4..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/TypePreference.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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 deleted file mode 100644 index 1813c2c..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/VisualPreference.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * 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 deleted file mode 100644 index 9c02fa8..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/VisualizationPreference.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 deleted file mode 100644 index 279243a..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/device.properties +++ /dev/null @@ -1,6 +0,0 @@ -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 deleted file mode 100644 index c54c46a..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/output.properties +++ /dev/null @@ -1,2 +0,0 @@ -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 deleted file mode 100644 index 3787d34..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/preferences.properties +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 6433f43..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/skin.properties +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index a0f7dd4..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/system.properties +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index 061309d..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/type.properties +++ /dev/null @@ -1,2 +0,0 @@ -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 deleted file mode 100644 index be5fe0c..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/visual.properties +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 7c1585b..0000000 --- a/java/src/javazoom/jlgui/player/amp/util/ui/visualization.properties +++ /dev/null @@ -1,2 +0,0 @@ -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 deleted file mode 100644 index 294dc82..0000000 --- a/java/src/javazoom/jlgui/player/amp/visual/ui/SpectrumTimeAnalyzer.java +++ /dev/null @@ -1,775 +0,0 @@ -/* - * 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); - }*/ -} diff --git a/java/src/mimis/Application.java b/java/src/mimis/Application.java index d27f488..29c9d71 100644 --- a/java/src/mimis/Application.java +++ b/java/src/mimis/Application.java @@ -1,6 +1,7 @@ package mimis; import mimis.event.EventHandler; +import mimis.exception.worker.DeactivateException; import mimis.manager.Titled; public abstract class Application extends EventHandler implements Titled, Exitable { @@ -16,10 +17,14 @@ public abstract class Application extends EventHandler implements Titled, Exitab return title; } - public void exit() { + public void stop() { if (active()) { - deactivate(); + try { + deactivate(); + } catch (DeactivateException e) { + log.error(e); + } } - stop(); + super.stop(); } } \ No newline at end of file diff --git a/java/src/mimis/Client.java b/java/src/mimis/Client.java index b5866f1..b458197 100644 --- a/java/src/mimis/Client.java +++ b/java/src/mimis/Client.java @@ -6,7 +6,6 @@ import mimis.device.jintellitype.JIntellitypeDevice; import mimis.device.lirc.LircDevice; import mimis.device.network.NetworkDevice; import mimis.device.panel.PanelDevice; -import mimis.device.player.PlayerDevice; import mimis.device.wiimote.WiimoteDevice; import mimis.event.EventRouter; import mimis.event.router.GlobalRouter; @@ -36,7 +35,6 @@ public class Client { new WiimoteDevice(), new PanelDevice(), new JIntellitypeDevice(), - new PlayerDevice(), new RumblepadDevice(), new Extreme3DDevice(), new NetworkDevice()}; diff --git a/java/src/mimis/Device.java b/java/src/mimis/Device.java index cfa5766..46c5ccc 100644 --- a/java/src/mimis/Device.java +++ b/java/src/mimis/Device.java @@ -4,6 +4,7 @@ import mimis.event.EventHandler; import mimis.event.Task; import mimis.event.task.Continuous; import mimis.event.task.Stopper; +import mimis.exception.worker.DeactivateException; import mimis.macro.Sequence; import mimis.macro.SequenceListener; import mimis.macro.State; @@ -23,8 +24,11 @@ public abstract class Device extends EventHandler implements Titled, Exitable { public Device(String title) { this.title = title; - active = false; + } + + public void start() { sequenceListener = new SequenceListener(this); + super.start(); } /* Register macro's */ @@ -84,9 +88,13 @@ public abstract class Device extends EventHandler implements Titled, Exitable { return title; } - public void exit() { + public void stop() { if (active()) { - deactivate(); + try { + deactivate(); + } catch (DeactivateException e) { + log.error(e); + } } stop(); } diff --git a/java/src/mimis/Exitable.java b/java/src/mimis/Exitable.java index 86d5ea6..8ead9d4 100644 --- a/java/src/mimis/Exitable.java +++ b/java/src/mimis/Exitable.java @@ -1,5 +1,5 @@ package mimis; public interface Exitable { - public void exit(); + public void stop(); } diff --git a/java/src/mimis/GUI.java b/java/src/mimis/GUI.java index 5a1d398..244eee6 100644 --- a/java/src/mimis/GUI.java +++ b/java/src/mimis/GUI.java @@ -72,7 +72,7 @@ public class GUI extends JFrame { if (e.getID() == WindowEvent.WINDOW_CLOSING) { log.debug("Window closing"); exit(); - mimis.exit(); + mimis.stop(); } } diff --git a/java/src/mimis/Main.java b/java/src/mimis/Main.java index 5f154b2..b04a679 100644 --- a/java/src/mimis/Main.java +++ b/java/src/mimis/Main.java @@ -12,10 +12,10 @@ import mimis.device.jintellitype.JIntellitypeDevice; import mimis.device.lirc.LircDevice; import mimis.device.network.NetworkDevice; import mimis.device.panel.PanelDevice; -import mimis.device.player.PlayerDevice; import mimis.device.wiimote.WiimoteDevice; import mimis.event.EventRouter; import mimis.event.router.LocalRouter; +import mimis.exception.worker.ActivateException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -42,7 +42,6 @@ public class Main { new WiimoteDevice(), new PanelDevice(), new JIntellitypeDevice(), - new PlayerDevice(), new RumblepadDevice(), new Extreme3DDevice(), new NetworkDevice()}; @@ -51,7 +50,11 @@ public class Main { public void start() { log.debug("Main"); Mimis mimis = new Mimis(eventRouter, applicationArray, deviceArray); - mimis.activate(); + try { + mimis.activate(); + } catch (ActivateException e) { + log.fatal(e); + } } public static void main(String[] args) { diff --git a/java/src/mimis/Manager.java b/java/src/mimis/Manager.java index cee411d..7a972e9 100644 --- a/java/src/mimis/Manager.java +++ b/java/src/mimis/Manager.java @@ -33,7 +33,7 @@ public class Manager extends Worker { public void stop() { super.stop(); for (T manageable : manageableArray) { - manageable.exit(); + manageable.stop(); } super.stop(); } diff --git a/java/src/mimis/Mimis.java b/java/src/mimis/Mimis.java index 4d90d58..33af2ea 100644 --- a/java/src/mimis/Mimis.java +++ b/java/src/mimis/Mimis.java @@ -2,13 +2,13 @@ package mimis; import mimis.event.EventHandler; import mimis.event.EventRouter; +import mimis.exception.worker.ActivateException; import mimis.util.ArrayCycle; import mimis.value.Action; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - public class Mimis extends EventHandler { protected Log log = LogFactory.getLog(getClass()); @@ -19,11 +19,11 @@ public class Mimis extends EventHandler { protected Manager applicationManager; protected Manager deviceManager; - + public Mimis(EventRouter eventRouter) { this(eventRouter, new Application[0], new Device[0]); } - + public Mimis(EventRouter eventRouter, Application[] applicationArray) { this(eventRouter, applicationArray, new Device[0]); } @@ -36,20 +36,20 @@ public class Mimis extends EventHandler { EventHandler.initialise(eventRouter); applicationManager = new Manager(applicationArray); deviceManager = new Manager(deviceArray); - + this.applicationArray = applicationArray; this.deviceArray = deviceArray; applicationCycle = new ArrayCycle(applicationArray); } - public void activate() { + public void activate() throws ActivateException { log.debug("Activate managers"); applicationManager.activate(); - deviceManager.start(); - + deviceManager.activate(); + log.debug("Create gui"); gui = new GUI(this, applicationManager, deviceManager); - + if (applicationCycle.size() > 0) { log.debug("Initialise application cycle"); eventRouter.set(applicationCycle.current()); @@ -57,15 +57,14 @@ public class Mimis extends EventHandler { super.activate(false); } - public void exit() { + public void stop() { log.debug("Stop event router"); eventRouter.stop(); - + log.debug("Stop managers"); applicationManager.stop(); - deviceManager.stop(); - - stop(); + deviceManager.stop(); + super.stop(); } protected void action(Action action) { @@ -80,7 +79,7 @@ public class Mimis extends EventHandler { System.out.println(applicationCycle.current()); break; case EXIT: - exit(); + stop(); break; } } diff --git a/java/src/mimis/Worker.java b/java/src/mimis/Worker.java index ea0a030..13bfaad 100644 --- a/java/src/mimis/Worker.java +++ b/java/src/mimis/Worker.java @@ -1,5 +1,8 @@ package mimis; +import mimis.exception.worker.ActivateException; +import mimis.exception.worker.DeactivateException; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -31,7 +34,11 @@ public abstract class Worker implements Runnable { public void stop() { log.trace("Stop"); if (active()) { - deactivate(); + try { + deactivate(); + } catch (DeactivateException e) { + log.error(e); + } } running = false; synchronized (this) { @@ -57,7 +64,7 @@ public abstract class Worker implements Runnable { return active; } - public void activate() { + public void activate() throws ActivateException { activate(THREAD); } @@ -71,7 +78,7 @@ public abstract class Worker implements Runnable { } } - public void deactivate() { + public void deactivate() throws DeactivateException { active = false; } diff --git a/java/src/mimis/application/cmd/CMDApplication.java b/java/src/mimis/application/cmd/CMDApplication.java index 3ef6454..de38840 100644 --- a/java/src/mimis/application/cmd/CMDApplication.java +++ b/java/src/mimis/application/cmd/CMDApplication.java @@ -3,6 +3,8 @@ package mimis.application.cmd; import java.io.IOException; import mimis.Application; +import mimis.exception.worker.ActivateException; +import mimis.exception.worker.DeactivateException; import mimis.util.Native; import mimis.util.VBScript; @@ -20,7 +22,7 @@ public abstract class CMDApplication extends Application { this.title = title; } - public void activate() { + public void activate() throws ActivateException { String key = String.format("%s\\%s", REGISTRY, program); // Check of naam is gevonden in register String path = Native.getValue(key); @@ -29,8 +31,7 @@ public abstract class CMDApplication extends Application { command = Native.replaceVariables(command); process = Runtime.getRuntime().exec(command); } catch (IOException e) { - e.printStackTrace(); - //throw new ApplicationInitialiseException(); + throw new ActivateException(); } super.activate(); } @@ -39,11 +40,11 @@ public abstract class CMDApplication extends Application { try { return active = VBScript.isRunning(program); } catch (IOException e) { - return false; + return active = false; } } - public void deactivate() { + public void deactivate() throws DeactivateException { if (process != null) { process.destroy(); } diff --git a/java/src/mimis/application/cmd/windows/WindowsApplication.java b/java/src/mimis/application/cmd/windows/WindowsApplication.java index b9776d8..5231cb7 100644 --- a/java/src/mimis/application/cmd/windows/WindowsApplication.java +++ b/java/src/mimis/application/cmd/windows/WindowsApplication.java @@ -1,6 +1,7 @@ package mimis.application.cmd.windows; import mimis.application.cmd.CMDApplication; +import mimis.exception.worker.ActivateException; import mimis.util.Windows; import mimis.value.Command; import mimis.value.Key; @@ -21,15 +22,16 @@ public abstract class WindowsApplication extends CMDApplication { handle = -1; } - public void initialise() { + public void activate() throws ActivateException { handle = Windows.findWindow(name, null); if (handle < 1) { - super.initialise(); + super.activate(); sleep(START_SLEEP); handle = Windows.findWindow(name, null); } + active = handle > 0; if (handle < 1) { - //throw new ApplicationInitialiseException(); + throw new ActivateException(); } } diff --git a/java/src/mimis/application/cmd/windows/gomplayer/GomPlayerApplication.java b/java/src/mimis/application/cmd/windows/gomplayer/GomPlayerApplication.java index 776c7c2..9a3d47b 100644 --- a/java/src/mimis/application/cmd/windows/gomplayer/GomPlayerApplication.java +++ b/java/src/mimis/application/cmd/windows/gomplayer/GomPlayerApplication.java @@ -13,7 +13,7 @@ public class GomPlayerApplication extends WindowsApplication { } public void action(Action action) { - System.out.println("GomPlayerApplication: " + action); + log.trace("GomPlayerApplication: " + action); switch (action) { case PLAY: command(0x800C); diff --git a/java/src/mimis/application/cmd/windows/winamp/WinampApplication.java b/java/src/mimis/application/cmd/windows/winamp/WinampApplication.java index 9a91cb8..738eb78 100644 --- a/java/src/mimis/application/cmd/windows/winamp/WinampApplication.java +++ b/java/src/mimis/application/cmd/windows/winamp/WinampApplication.java @@ -40,7 +40,7 @@ public class WinampApplication extends WindowsApplication { } public void action(Action action) { - System.out.println("WinampApplication: " + action); + log.trace("WinampApplication: " + action); switch (action) { case PLAY: System.out.println(user(0, IPC_ISPLAYING)); diff --git a/java/src/mimis/application/cmd/windows/wmp/WMPApplication.java b/java/src/mimis/application/cmd/windows/wmp/WMPApplication.java index 560d75b..09e1482 100644 --- a/java/src/mimis/application/cmd/windows/wmp/WMPApplication.java +++ b/java/src/mimis/application/cmd/windows/wmp/WMPApplication.java @@ -13,8 +13,7 @@ public class WMPApplication extends WindowsApplication { } public void action(Action action) { - System.out.println("WMPApplication: " + action); - System.out.println(handle); + log.trace("WMPApplication: " + action); switch (action) { case PLAY: command(18808); diff --git a/java/src/mimis/application/itunes/iTunesApplication.java b/java/src/mimis/application/itunes/iTunesApplication.java index b496d8c..61c1ded 100644 --- a/java/src/mimis/application/itunes/iTunesApplication.java +++ b/java/src/mimis/application/itunes/iTunesApplication.java @@ -1,7 +1,8 @@ package mimis.application.itunes; import mimis.Application; -import mimis.event.Feedback; +import mimis.exception.worker.ActivateException; +import mimis.exception.worker.DeactivateException; import mimis.value.Action; import com.dt.iTunesController.ITCOMDisabledReason; @@ -23,12 +24,8 @@ public class iTunesApplication extends Application implements iTunesEventsInterf super(TITLE); iTunes = new iTunes(); } - - /*public boolean active() { - return active; - }*/ - - public void activate() { + + public void activate() throws ActivateException { synchronized (iTunes) { iTunes.connect(); iTunes.addEventHandler(this); @@ -37,31 +34,29 @@ public class iTunesApplication extends Application implements iTunesEventsInterf } public boolean active() { - //log.info("Check iTunes"); try { - iTunes.getCurrentTrack(); + iTunes.getMute(); active = true; } catch (Exception e) { - //log.fatal(e); active = false; } - //log.info(active); return active; } - public void deactivate() { + public void deactivate() throws DeactivateException { try { synchronized (iTunes) { iTunes.quit(); } } catch (Exception e) { - log.info("Unexpected deactivation exception", e); + throw new DeactivateException(); + } finally { + super.deactivate(); } - super.deactivate(); } - + protected void action(Action action) { - System.out.println("iTunesApplication: " + action); + log.trace("iTunesApplication: " + action); switch (action) { case PLAY: iTunes.playPause(); @@ -108,20 +103,19 @@ public class iTunesApplication extends Application implements iTunesEventsInterf return iTunes.getSoundVolume(); } - /* iTunesEventInterface => naar eigen class? */ public void onDatabaseChangedEvent(int[][] deletedObjectIDs, int[][] changedObjectIDs) {} public void onPlayerPlayEvent(ITTrack iTrack) { if (active) { - System.out.println("iTunes play"); - eventRouter.add(new Feedback()); + log.trace("iTunesEvent: play"); } } + public void onPlayerStopEvent(ITTrack iTrack) { if (active) { - System.out.println("iTunes stop"); - eventRouter.add(new Feedback()); + log.trace("iTunesEvent: stop"); } } + public void onPlayerPlayingTrackChangedEvent(ITTrack iTrack) {} public void onCOMCallsDisabledEvent(ITCOMDisabledReason reason) {} public void onCOMCallsEnabledEvent() {} diff --git a/java/src/mimis/application/mpc/MPCApplication.java b/java/src/mimis/application/mpc/MPCApplication.java index f95f2f2..040dc2f 100644 --- a/java/src/mimis/application/mpc/MPCApplication.java +++ b/java/src/mimis/application/mpc/MPCApplication.java @@ -13,8 +13,7 @@ public class MPCApplication extends WindowsApplication { } public void action(Action action) { - System.out.println("MPCApplication: " + action); - System.out.println(handle); + log.trace("MPCApplication: " + action); switch (action) { case PLAY: command(889); diff --git a/java/src/mimis/application/vlc/VLCApplication.java b/java/src/mimis/application/vlc/VLCApplication.java index 7ce2258..2f88953 100644 --- a/java/src/mimis/application/vlc/VLCApplication.java +++ b/java/src/mimis/application/vlc/VLCApplication.java @@ -8,7 +8,6 @@ import java.net.URL; import mimis.application.cmd.CMDApplication; import mimis.value.Action; - public class VLCApplication extends CMDApplication { protected final static String PROGRAM = "vlc.exe"; protected final static String TITLE = "VLC media player"; @@ -27,19 +26,24 @@ public class VLCApplication extends CMDApplication { } public void command(String command) { - String request = "http://" + HOST + ":" + PORT + "/requests/status.xml?command=" + command; - try { - int response = ((HttpURLConnection)(new URL(request)).openConnection()).getResponseCode(); - System.out.printf("Response: %d\n", response); + //String request = "http://" + HOST + ":" + PORT + "/requests/status.xml?command=" + command; + String request = String.format("http://%s:%d/requests/status.xml?command=%s", HOST, PORT, command); + try { + // Todo: check response voor 200, status ok + //int response = ((HttpURLConnection)(new URL(request)).openConnection()).getResponseCode(); + URL url = new URL(request); + HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection(); + int response = httpUrlConnection.getResponseCode(); + log.debug("Response: " + response); } catch (MalformedURLException e) { - e.printStackTrace(); + log.error(e); } catch (IOException e) { - e.printStackTrace(); + log.error(e); } } public void action(Action action) { - System.out.println("VLCApplication: " + action); + log.trace("VLCApplication: " + action); switch (action) { case PLAY: command("pl_pause"); @@ -92,8 +96,7 @@ public class VLCApplication extends CMDApplication { } protected int toggleMute() { - muted =! muted; - return muted ? 0 : volume; + return (muted = !muted) ? 0 : volume; } public String title() { diff --git a/java/src/mimis/device/javainput/JavaInputDevice.java b/java/src/mimis/device/javainput/JavaInputDevice.java index 2619934..5045ed3 100644 --- a/java/src/mimis/device/javainput/JavaInputDevice.java +++ b/java/src/mimis/device/javainput/JavaInputDevice.java @@ -5,17 +5,18 @@ import mimis.Device; import mimis.exception.ButtonException; import mimis.exception.button.UnknownButtonException; import mimis.exception.button.UnknownDirectionException; -import mimis.exception.device.DeviceInitialiseException; import mimis.exception.device.DeviceNotFoundException; +import mimis.exception.worker.ActivateException; +import mimis.exception.worker.DeactivateException; import mimis.macro.state.Press; import mimis.macro.state.Release; + import de.hardcode.jxinput.JXInputDevice; import de.hardcode.jxinput.JXInputManager; import de.hardcode.jxinput.event.JXInputAxisEvent; import de.hardcode.jxinput.event.JXInputButtonEvent; import de.hardcode.jxinput.event.JXInputDirectionalEvent; - public abstract class JavaInputDevice extends Device { public JavaInputDevice(String title) { super(title); @@ -24,30 +25,28 @@ public abstract class JavaInputDevice extends Device { protected JavaInputListener javaInputListener; protected Button previousDirectionalButton; - public void activate(String name) throws DeviceInitialiseException { + public void activate(String name) throws ActivateException { try { javaInputListener = new JavaInputListener(this, getDevice(name)); - javaInputListener.start(); } catch (DeviceNotFoundException e) { - throw new DeviceInitialiseException(); - } + throw new ActivateException(); + } + javaInputListener.activate(); } - public void deactivate() { - javaInputListener.exit(); + public void deactivate() throws DeactivateException { + javaInputListener.deactivate(); } public void processEvent(JXInputAxisEvent event) { - //System.out.println(event); + log.trace("JXInputAxisEvent: " + event); } public void processEvent(JXInputButtonEvent event) throws ButtonException { Button button = getButton(event); if (event.getButton().getState()) { - System.out.println("Press: " + button); add(new Press(button)); } else { - System.out.println("Release: " + button); add(new Release(button)); } } @@ -56,11 +55,9 @@ public abstract class JavaInputDevice extends Device { Button button = getButton(event); if (event.getDirectional().isCentered()) { if (previousDirectionalButton != null) { - System.out.println("Release: " + previousDirectionalButton); add(new Release(previousDirectionalButton)); } } else { - System.out.println("Press: " + button); add(new Press(button)); previousDirectionalButton = button; } diff --git a/java/src/mimis/device/javainput/JavaInputListener.java b/java/src/mimis/device/javainput/JavaInputListener.java index 8dc3e5c..a59161d 100644 --- a/java/src/mimis/device/javainput/JavaInputListener.java +++ b/java/src/mimis/device/javainput/JavaInputListener.java @@ -3,6 +3,7 @@ package mimis.device.javainput; import java.util.LinkedList; import java.util.Queue; +import mimis.Worker; import mimis.exception.ButtonException; @@ -19,10 +20,7 @@ import de.hardcode.jxinput.event.JXInputDirectionalEvent; import de.hardcode.jxinput.event.JXInputDirectionalEventListener; import de.hardcode.jxinput.event.JXInputEventManager; -public class JavaInputListener implements Runnable, JXInputAxisEventListener, JXInputButtonEventListener, JXInputDirectionalEventListener { - protected static final int SLEEP = 100; - - protected boolean run; +public class JavaInputListener extends Worker implements Runnable, JXInputAxisEventListener, JXInputButtonEventListener, JXInputDirectionalEventListener { protected JavaInputDevice javaInputDevice; protected JXInputDevice jxinputDevice; protected Queue axisEventQueue; @@ -71,40 +69,20 @@ public class JavaInputListener implements Runnable, JXInputAxisEventListener, JX directionalEventQueue.add(event); } - public void start() { - new Thread(this).start(); - } - - public void run() { - run = true; - while (run) { - JXInputManager.updateFeatures(); - boolean sleep = true; - if (!axisEventQueue.isEmpty()) { - javaInputDevice.processEvent(axisEventQueue.poll()); - sleep = false; - } - if (!buttonEventQueue.isEmpty()) { - try { - javaInputDevice.processEvent(buttonEventQueue.poll()); - } catch (ButtonException e) {} - sleep = false; - } - if (!directionalEventQueue.isEmpty()) { - try { - javaInputDevice.processEvent(directionalEventQueue.poll()); - } catch (ButtonException e) {} - sleep = false; - } - if (sleep) { - try { - Thread.sleep(SLEEP); - } catch (InterruptedException e) {} - } + public void work() { + JXInputManager.updateFeatures(); + if (!axisEventQueue.isEmpty()) { + javaInputDevice.processEvent(axisEventQueue.poll()); + } else if (!buttonEventQueue.isEmpty()) { + try { + javaInputDevice.processEvent(buttonEventQueue.poll()); + } catch (ButtonException e) {} + } else if (!directionalEventQueue.isEmpty()) { + try { + javaInputDevice.processEvent(directionalEventQueue.poll()); + } catch (ButtonException e) {} + } else { + sleep(); } } - - public void exit() { - run = false; - } } diff --git a/java/src/mimis/device/javainput/extreme3d/Extreme3DDevice.java b/java/src/mimis/device/javainput/extreme3d/Extreme3DDevice.java index 6a58b7d..69ac8ab 100644 --- a/java/src/mimis/device/javainput/extreme3d/Extreme3DDevice.java +++ b/java/src/mimis/device/javainput/extreme3d/Extreme3DDevice.java @@ -23,7 +23,8 @@ public class Extreme3DDevice extends JavaInputDevice { super(NAME); } - public void initialise() { + public void start() { + super.start(); try { add( new Press(Extreme3DButton.TWELVE), @@ -36,9 +37,13 @@ public class Extreme3DDevice extends JavaInputDevice { new Release(Extreme3DButton.ONE)), new Task(Target.MIMIS, Action.EXIT)); } catch (MacroException e) { - e.printStackTrace(); + log.error(e); } } + + public void initialise() { + + } protected Button getButton(JXInputButtonEvent event) throws UnknownButtonException { return Extreme3DButton.create(event); diff --git a/java/src/mimis/device/javainput/rumblepad/RumblepadDevice.java b/java/src/mimis/device/javainput/rumblepad/RumblepadDevice.java index 3d33d17..de9c75e 100644 --- a/java/src/mimis/device/javainput/rumblepad/RumblepadDevice.java +++ b/java/src/mimis/device/javainput/rumblepad/RumblepadDevice.java @@ -22,7 +22,8 @@ public class RumblepadDevice extends JavaInputDevice { super(NAME); } - public void initialise(){ + public void start() { + super.start(); add( new Press(RumblepadButton.ONE), new Task(Target.APPLICATION, Action.PLAY)); diff --git a/java/src/mimis/device/jintellitype/JIntellitypeDevice.java b/java/src/mimis/device/jintellitype/JIntellitypeDevice.java index 757e660..37d8ff5 100644 --- a/java/src/mimis/device/jintellitype/JIntellitypeDevice.java +++ b/java/src/mimis/device/jintellitype/JIntellitypeDevice.java @@ -29,7 +29,8 @@ public class JIntellitypeDevice extends Device implements HotkeyListener, Intell Hotkey.initialise(hotkeyList, jit); } - public void initialise() { + public void start() { + super.start(); jit.addHotKeyListener(this); jit.addIntellitypeListener(this); add( @@ -67,23 +68,27 @@ public class JIntellitypeDevice extends Device implements HotkeyListener, Intell } public void onIntellitype(int command) { - try { + if (active) { + try { CommandButton commandButton = CommandButton.create(command); add(new Press(commandButton)); add(new Release(commandButton)); - } catch (UnknownButtonException e) { - e.printStackTrace(); + } catch (UnknownButtonException e) { + log.error(e); + } } } public void onHotKey(int id) { - Hotkey hotkey = hotkeyList.get(id); - add(new Press(hotkey)); - add(new Release(hotkey)); + if (active) { + Hotkey hotkey = hotkeyList.get(id); + add(new Press(hotkey)); + add(new Release(hotkey)); + } } - public void exit() { - super.exit(); + public void stop() { + super.stop(); jit.removeHotKeyListener(this); jit.removeIntellitypeListener(this); jit.cleanUp(); diff --git a/java/src/mimis/device/lirc/LircDevice.java b/java/src/mimis/device/lirc/LircDevice.java index 1e12f23..b9a1b40 100644 --- a/java/src/mimis/device/lirc/LircDevice.java +++ b/java/src/mimis/device/lirc/LircDevice.java @@ -6,6 +6,8 @@ import mimis.Button; import mimis.Device; import mimis.device.lirc.button.DenonRC176; import mimis.device.lirc.button.PhiliphsRCLE011Button; +import mimis.exception.worker.ActivateException; +import mimis.exception.worker.DeactivateException; import mimis.macro.state.Press; import mimis.macro.state.Release; import mimis.util.Multiplexer; @@ -31,13 +33,13 @@ public class LircDevice extends Device implements LircButtonListener, SignalList lircService.add(this); } - public void activate() { + public void activate() throws ActivateException { multiplexer.start(); lircService.activate(); super.activate(); } - public void deactivate() { + public void deactivate() throws DeactivateException { multiplexer.deactivate(); lircService.deactivate(); super.deactivate(); diff --git a/java/src/mimis/device/lirc/LircService.java b/java/src/mimis/device/lirc/LircService.java index 0f4c4ac..9cfaa64 100644 --- a/java/src/mimis/device/lirc/LircService.java +++ b/java/src/mimis/device/lirc/LircService.java @@ -15,6 +15,8 @@ import java.util.Scanner; import mimis.Worker; import mimis.exception.button.UnknownButtonException; +import mimis.exception.worker.ActivateException; +import mimis.exception.worker.DeactivateException; public class LircService extends Worker { public static final String IP = "127.0.0.1"; @@ -50,7 +52,7 @@ public class LircService extends Worker { lircButtonListenerList.remove(lircButtonListener); } - public void activate() { + public void activate() throws ActivateException { try { socket = new Socket(ip, port); @@ -60,22 +62,25 @@ public class LircService extends Worker { outputStream = socket.getOutputStream(); printWriter = new PrintWriter(outputStream); } catch (UnknownHostException e) { - e.printStackTrace(); + log.info(e); + throw new ActivateException(); } catch (IOException e) { - e.printStackTrace(); + log.info(e); + throw new ActivateException(); } super.activate(); } - public void deactivate() { + public void deactivate() throws DeactivateException { try { inputStream.close(); outputStream.close(); socket.close(); } catch (IOException e) { - //e.printStackTrace(); + log.error(e); + } finally { + super.deactivate(); } - super.deactivate(); } public void work() { @@ -83,13 +88,13 @@ public class LircService extends Worker { String string = bufferedReader.readLine(); try { LircButton lircButton = parseButton(new Scanner(string)); - //log.debug(String.format("Lirc button: %s", lircButton)); + log.trace("LircButton: " + lircButton); for (LircButtonListener lircbuttonListener : lircButtonListenerList) { lircbuttonListener.add(lircButton); } } catch (UnknownButtonException e) {} } catch (IOException e) { - e.printStackTrace(); + log.error(e); } } @@ -99,7 +104,7 @@ public class LircService extends Worker { scanner.next(); String code = scanner.next(); String remote = scanner.next(); - //log.debug(String.format("%s: %s", remote, code)); + //log.debug(String.format("%s: %s", remote, code)); LircButton[] buttonArray = buttonMap.get(remote); if (buttonArray != null) { for (LircButton button : buttonArray) { @@ -108,12 +113,9 @@ public class LircService extends Worker { } } } - } catch (InputMismatchException e) {} + } catch (InputMismatchException e) { + log.error(e); + } throw new UnknownButtonException(); } - - public static void main(String[] args) { - new LircDevice().activate(); - while (true); - } } diff --git a/java/src/mimis/device/network/NetworkDevice.java b/java/src/mimis/device/network/NetworkDevice.java index 6210678..e4433e5 100644 --- a/java/src/mimis/device/network/NetworkDevice.java +++ b/java/src/mimis/device/network/NetworkDevice.java @@ -11,11 +11,11 @@ import mimis.Device; import mimis.Event; import mimis.Worker; import mimis.event.Feedback; +import mimis.exception.worker.ActivateException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - public class NetworkDevice extends Device { protected static final String TITLE = "Network"; public static final int PORT = 6789; @@ -34,12 +34,12 @@ public class NetworkDevice extends Device { this(PORT); } - public void activate() { + public void activate() throws ActivateException { try { server = new Server(port); server.start(); } catch (IOException e) { - //throw new DeviceInitialiseException(); + throw new ActivateException(); } } @@ -63,16 +63,16 @@ public class NetworkDevice extends Device { public Server(int port) throws IOException { serverSocket = new ServerSocket(port); clientList = new ArrayList(); - System.out.println("Server started"); + log.trace("Server started"); } public void work() { - System.out.println("Server is waiting for clients"); + log.trace("Server is waiting for clients"); try { Socket socket = serverSocket.accept(); Client client = new Client(socket); client.start(); - System.out.println("Client connected"); + log.trace("Client connected"); } catch (IOException e) {} } @@ -102,10 +102,9 @@ public class NetworkDevice extends Device { do { object = objectInputStream.readObject(); if (object instanceof Event) { - log.debug("event binnen!"); + log.trace(object); eventRouter.add((Event) object); } - log.debug("iets te lezen!"); } while (object != null); } catch (IOException e) { e.printStackTrace(); @@ -115,10 +114,10 @@ public class NetworkDevice extends Device { } public void stop() { - System.out.println("stoppen"); try { disconnect(); } catch (IOException e) { + log.error(e); } finally { clientList.remove(this); } diff --git a/java/src/mimis/device/player/PlayerDevice.java b/java/src/mimis/device/player/PlayerDevice.java deleted file mode 100644 index 5b34224..0000000 --- a/java/src/mimis/device/player/PlayerDevice.java +++ /dev/null @@ -1,23 +0,0 @@ -package mimis.device.player; - -import mimis.Device; -import javazoom.jlgui.player.amp.StandalonePlayer; - -public class PlayerDevice extends Device { - protected static final String TITLE = "Player"; - - StandalonePlayer standalonePlayer; - - public PlayerDevice() { - super(TITLE); - } - - public void initialise() { - standalonePlayer = new StandalonePlayer(); - standalonePlayer.loadUI(); - //standalonePlayer.loadJS(); - //standalonePlayer.loadPlaylist(); - //standalonePlayer. - System.out.println("niets!"); - } -} diff --git a/java/src/mimis/device/wiimote/WiimoteDevice.java b/java/src/mimis/device/wiimote/WiimoteDevice.java index cf17974..15f8565 100644 --- a/java/src/mimis/device/wiimote/WiimoteDevice.java +++ b/java/src/mimis/device/wiimote/WiimoteDevice.java @@ -181,8 +181,8 @@ public class WiimoteDevice extends Device implements GestureListener { wiimote.deactivateMotionSensing(); } - public void exit() { + public void stop() { wiimoteService.exit(); - super.exit(); + super.stop(); } } diff --git a/java/src/mimis/exception/ExitException.java b/java/src/mimis/exception/ExitException.java new file mode 100644 index 0000000..e371fd0 --- /dev/null +++ b/java/src/mimis/exception/ExitException.java @@ -0,0 +1,5 @@ +package mimis.exception; + +public class ExitException extends Exception { + protected static final long serialVersionUID = 1L; +} diff --git a/java/src/mimis/exception/worker/ActivateException.java b/java/src/mimis/exception/worker/ActivateException.java new file mode 100644 index 0000000..dbee795 --- /dev/null +++ b/java/src/mimis/exception/worker/ActivateException.java @@ -0,0 +1,7 @@ +package mimis.exception.worker; + +import mimis.exception.WorkerException; + +public class ActivateException extends WorkerException { + protected static final long serialVersionUID = 1L; +} diff --git a/java/src/mimis/exception/worker/DeactivateException.java b/java/src/mimis/exception/worker/DeactivateException.java new file mode 100644 index 0000000..883cca1 --- /dev/null +++ b/java/src/mimis/exception/worker/DeactivateException.java @@ -0,0 +1,7 @@ +package mimis.exception.worker; + +import mimis.exception.WorkerException; + +public class DeactivateException extends WorkerException { + protected static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/java/src/mimis/manager/SelectButton.java b/java/src/mimis/manager/SelectButton.java index 3ce8601..e149e70 100644 --- a/java/src/mimis/manager/SelectButton.java +++ b/java/src/mimis/manager/SelectButton.java @@ -6,11 +6,13 @@ import javax.swing.Action; import javax.swing.JToggleButton; import mimis.Worker; +import mimis.exception.worker.ActivateException; +import mimis.exception.worker.DeactivateException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - +// Eventueel handigere knoppen gebruiken ivm terugtogglen public class SelectButton extends JToggleButton implements ItemListener { protected Log log = LogFactory.getLog(getClass()); @@ -32,10 +34,20 @@ public class SelectButton extends JToggleButton imple int state = itemEvent.getStateChange(); if (state == ItemEvent.SELECTED) { System.out.println("Selected"); - activatable.activate(); + try { + activatable.activate(); + } catch (ActivateException e) { + // Het knopje moet worden terug getoggled + log.error(e); + } } else { System.out.println("Deselected"); - activatable.deactivate(); + try { + activatable.deactivate(); + } catch (DeactivateException e) { + // Het knopje moet worden terug getoggled + log.error(e); + } } } diff --git a/java/src/mimis/util/Multiplexer.java b/java/src/mimis/util/Multiplexer.java index f850cfa..5cd92ed 100644 --- a/java/src/mimis/util/Multiplexer.java +++ b/java/src/mimis/util/Multiplexer.java @@ -1,6 +1,8 @@ package mimis.util; import mimis.Worker; +import mimis.exception.worker.ActivateException; +import mimis.exception.worker.DeactivateException; import mimis.util.multiplexer.SignalListener; import mimis.value.Signal; @@ -25,7 +27,11 @@ public class Multiplexer extends Worker { signalListener.add(Signal.BEGIN, object); this.object = object; end = true; - activate(); + try { + activate(); + } catch (ActivateException e) { + log.error(e); + } } else if (this.object.equals(object)) { end = false; synchronized (this) { @@ -49,7 +55,11 @@ public class Multiplexer extends Worker { if (end) { signalListener.add(Signal.END, object); object = null; - deactivate(); + try { + deactivate(); + } catch (DeactivateException e) { + log.error(e); + } } end = !end; }