/*
* 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 plugins.audioPlayer.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 plugins.audioPlayer.javazoom.jlgui.player.amp.PlayerUI;
import plugins.audioPlayer.javazoom.jlgui.player.amp.playlist.Playlist;
import plugins.audioPlayer.javazoom.jlgui.player.amp.playlist.PlaylistItem;
import plugins.audioPlayer.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("plugins/audioPlayer/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());
}
}
}