/* * Copyright (c) 2008, 2009, 2010, 2011 Denis Tulskiy * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see <http://www.gnu.org/licenses/>. */ package com.tulskiy.musique.gui; import java.awt.BorderLayout; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.Timer; import com.tulskiy.musique.audio.player.Player; import com.tulskiy.musique.audio.player.PlayerEvent; import com.tulskiy.musique.audio.player.PlayerListener; import com.tulskiy.musique.playlist.Track; import com.tulskiy.musique.playlist.formatting.Parser; import com.tulskiy.musique.playlist.formatting.tokens.Expression; import com.tulskiy.musique.system.Application; import com.tulskiy.musique.system.configuration.AlbumArtConfiguration; import com.tulskiy.musique.system.configuration.Configuration; /** * Author: Denis Tulskiy * Date: Jul 19, 2010 */ public class AlbumArtPanel extends JPanel { private Logger logger = Logger.getLogger(getClass().getName()); private Application app = Application.getInstance(); private Configuration config = app.getConfiguration(); private final ArrayList<String> stubDefaults = new ArrayList<String>(Arrays.asList( "front.jpg", "cover.jpg", "%fileName%.jpg", "%album%.jpg", "folder.jpg")); private ImageIcon image; private Track track; private LinkedHashMap<File, ImageIcon> cache = new LinkedHashMap<File, ImageIcon>(1, 0.7f, true) { @Override protected boolean removeEldestEntry(Map.Entry<File, ImageIcon> eldest) { return size() > 1; } }; private ArrayList<Expression> stubs = new ArrayList<Expression>(); private Timer timer; private boolean nowPlayingOnly; private final int MAX_SIZE = 300; public AlbumArtPanel() { setLayout(new BorderLayout()); final JLabel canvas = new JLabel() { @Override protected void paintComponent(Graphics g) { if (image == null) { setText("[no image]"); super.paintComponent(g); } else { Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); double scaleW = (double) getWidth() / image.getIconWidth(); double scaleH = (double) getHeight() / image.getIconHeight(); double scale = Math.min(scaleW, scaleH); int height = (int) (image.getIconHeight() * scale); int width = (int) (image.getIconWidth() * scale); g2d.drawImage(image.getImage(), (getWidth() - width) / 2, (getHeight() - height) / 2, width, height, getBackground(), image.getImageObserver()); } } }; canvas.setHorizontalAlignment(JLabel.CENTER); canvas.setVerticalAlignment(JLabel.CENTER); timer = new Timer(100, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { image = null; if (track != null && track.getTrackData().isFile()) { for (Expression stub : stubs) { try { String path = stub.eval(track).toString(); File file = new File(path); if (!file.isAbsolute()) { String parentFile = track.getTrackData().getFile().getParentFile().getAbsolutePath(); file = new File(parentFile, path); } if (!file.exists()) continue; image = cache.get(file); if (image == null) { if (file.length() > 102400) //100 Kb continue; logger.fine("Loading Album Art from file: " + file); final ImageIcon newImage = new ImageIcon(file.getAbsolutePath()); double iconHeight = newImage.getIconHeight(); double iconWidth = newImage.getIconWidth(); if (iconHeight > MAX_SIZE) { double dt = MAX_SIZE / iconHeight; Image instance = newImage.getImage().getScaledInstance( (int) (iconWidth * dt), (int) (iconHeight * dt), Image.SCALE_SMOOTH ); image = new ImageIcon(instance); } else { image = newImage; } cache.put(file, image); } else { logger.fine("Loading Album Art from cache for file: " + file); } break; } catch (Exception ignored) { } } } canvas.repaint(); timer.stop(); } }); config.addPropertyChangeListener("albumart.nowPlayingOnly", true, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { nowPlayingOnly = config.getBoolean(evt.getPropertyName(), false); } }); config.addPropertyChangeListener("playlist.selectedTrack", true, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (!nowPlayingOnly && evt.getNewValue() instanceof Track) { track = (Track) evt.getNewValue(); timer.restart(); } } }); final Player player = app.getPlayer(); player.addListener(new PlayerListener() { @Override public void onEvent(PlayerEvent e) { if (nowPlayingOnly && e.getEventCode() == PlayerEvent.PlayerEventCode.FILE_OPENED) { track = player.getTrack(); timer.restart(); } } }); config.addPropertyChangeListener(AlbumArtConfiguration.getStubKey(), true, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { stubs.clear(); List<String> list = AlbumArtConfiguration.getStubs(stubDefaults); for (String s : list) { stubs.add(Parser.parse(s)); } } }); add(canvas, BorderLayout.CENTER); } }