javazoom.jlgui.player.amp.playlist.ui.PlaylistUI.java Source code

Java tutorial

Introduction

Here is the source code for javazoom.jlgui.player.amp.playlist.ui.PlaylistUI.java

Source

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