Added support for looking up entries by artist/title/song.

git-svn-id: https://samskivert.googlecode.com/svn/trunk@590 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2002-02-22 07:06:34 +00:00
parent 780dbf478f
commit 7c5281188e
8 changed files with 271 additions and 30 deletions
@@ -1,14 +1,10 @@
//
// $Id: BrowsePanel.java,v 1.1 2001/07/12 23:06:55 mdb Exp $
// $Id: BrowsePanel.java,v 1.2 2002/02/22 07:06:33 mdb Exp $
package robodj.chooser;
// import java.awt.*;
// import java.awt.event.ActionEvent;
// import java.awt.event.ActionListener;
import javax.swing.*;
// import com.samskivert.swing.*;
import robodj.repository.*;
public class BrowsePanel extends JTabbedPane
@@ -20,13 +16,13 @@ public class BrowsePanel extends JTabbedPane
// create a tab for each category
for (int i = 0; i < cats.length; i++) {
elist = new EntryList(cats[i].categoryid);
elist = new CategoryEntryList(cats[i].categoryid);
String tip = "Browse entries in '" + cats[i].name + "' category.";
addTab(cats[i].name, null, elist, tip);
}
// and add one for uncategorized entries
elist = new EntryList(-1);
elist = new CategoryEntryList(-1);
addTab("Uncategorized", null, elist,
"Browse uncategorized entries.");
@@ -0,0 +1,36 @@
//
// $Id: CategoryEntryList.java,v 1.1 2002/02/22 07:06:33 mdb Exp $
package robodj.chooser;
import com.samskivert.io.PersistenceException;
import robodj.repository.Entry;
public class CategoryEntryList extends EntryList
{
/**
* Constructs an entry list for entries in a particular category.
*/
public CategoryEntryList (int categoryId)
{
_categoryId = categoryId;
}
/**
* Reads in the entries for this category.
*/
public Entry[] readEntries ()
throws PersistenceException
{
return Chooser.model.getEntries(_categoryId);
}
protected String getEmptyString ()
{
return "No entries in this category.";
}
/** The unique identifier of the category we are displaying. */
protected int _categoryId;
}
@@ -1,5 +1,5 @@
//
// $Id: ChooserFrame.java,v 1.5 2001/07/13 00:11:05 mdb Exp $
// $Id: ChooserFrame.java,v 1.6 2002/02/22 07:06:33 mdb Exp $
package robodj.chooser;
@@ -40,6 +40,10 @@ public class ChooserFrame
BrowsePanel bpanel = new BrowsePanel();
tip = "Browse and select tunes to play.";
tpane.addTab("Browse", null, bpanel, tip);
SearchPanel spanel = new SearchPanel();
tip = "Search titles and artists.";
tpane.addTab("Search", null, spanel, tip);
top.add(tpane);
// the bottom is the control bar
@@ -1,5 +1,5 @@
//
// $Id: EntryList.java,v 1.9 2001/10/12 18:21:27 mdb Exp $
// $Id: EntryList.java,v 1.10 2002/02/22 07:06:33 mdb Exp $
package robodj.chooser;
@@ -17,11 +17,10 @@ import com.samskivert.swing.util.*;
import robodj.Log;
import robodj.repository.*;
public class EntryList
extends JPanel
public abstract class EntryList extends JPanel
implements TaskObserver, ActionListener, AncestorListener
{
public EntryList (int categoryid)
public EntryList ()
{
GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH);
gl.setOffAxisPolicy(GroupLayout.STRETCH);
@@ -48,10 +47,6 @@ public class EntryList
// use a special font for our name buttons
_nameFont = new Font("Helvetica", Font.PLAIN, 10);
// keep track of the query that we'll use to populate our entries
// display
_catid = categoryid;
// listen to ancestor events
addAncestorListener(this);
}
@@ -90,13 +85,16 @@ public class EntryList
}
/**
* Reads the entries from the database.
* Reads the entries from the database. This will be called on a
* separate thread and should be prepared to be called repeatedly
* without undue overhead. When the user browses into a song and back
* up again, this method is called to repopulate the entries.
*/
public Entry[] readEntries ()
throws PersistenceException
{
return Chooser.model.getEntries(_catid);
}
public abstract Entry[] readEntries ()
throws PersistenceException;
/** The string to display when there are no matching results. */
protected abstract String getEmptyString ();
/**
* Reads the entries from the database.
@@ -190,7 +188,7 @@ public class EntryList
// if there were no entries, stick a label in to that effect
if (_entries.length == 0) {
_bpanel.add(new JLabel("No entries in this category."));
_bpanel.add(new JLabel(getEmptyString()));
}
// reset our scroll position so that we're displaying the top of
@@ -205,6 +203,7 @@ public class EntryList
// we've removed and added components so we need to revalidate
revalidate();
repaint();
}
protected void populateSong (Entry entry)
@@ -356,7 +355,6 @@ public class EntryList
protected JPanel _bpanel;
protected JButton _upbut;
protected int _catid;
protected Entry[] _entries;
protected Entry _entry;
@@ -0,0 +1,42 @@
//
// $Id: QueryEntryList.java,v 1.1 2002/02/22 07:06:33 mdb Exp $
package robodj.chooser;
import com.samskivert.io.PersistenceException;
import robodj.repository.Entry;
public class QueryEntryList extends EntryList
{
/**
* Constructs an entry list to display entries that match a query.
*/
public QueryEntryList (String query)
{
_query = query;
}
/**
* Reads in the entries for this query.
*/
public Entry[] readEntries ()
throws PersistenceException
{
if (_entries == null) {
_entries = Chooser.repository.matchEntries(_query);
}
return _entries;
}
protected String getEmptyString ()
{
return "No matches to your query.";
}
/** The query with which we're looking up entries. */
protected String _query;
/** A cached copy of our query results. */
protected Entry[] _entries;
}
@@ -0,0 +1,74 @@
//
// $Id: SearchPanel.java,v 1.1 2002/02/22 07:06:33 mdb Exp $
package robodj.chooser;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import com.samskivert.swing.*;
import com.samskivert.util.StringUtil;
import robodj.repository.*;
public class SearchPanel extends JPanel
implements ActionListener
{
public SearchPanel ()
{
GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH);
gl.setOffAxisPolicy(GroupLayout.STRETCH);
gl.setJustification(GroupLayout.TOP);
setLayout(gl);
add(new JLabel("Enter a word to be matched against the " +
"artists, titles and songs:"), GroupLayout.FIXED);
gl = new HGroupLayout(GroupLayout.STRETCH);
JPanel qpanel = new JPanel(gl);
_qbox = new JTextField();
_qbox.addActionListener(this);
_qbox.setActionCommand("query");
qpanel.add(_qbox);
JButton qbutton = new JButton("Query");
qbutton.addActionListener(this);
qbutton.setActionCommand("query");
qpanel.add(qbutton, GroupLayout.FIXED);
add(qpanel, GroupLayout.FIXED);
}
public void actionPerformed (ActionEvent e)
{
if (e.getActionCommand().equals("query")) {
String text = _qbox.getText();
if (StringUtil.blank(text) || text.equals(_query)) {
// ignore empty text or repeat queries
return;
}
// make a note of the query
_query = text;
// remove any previous query results
if (_qlist != null) {
remove(_qlist);
_qlist = null;
}
// create and add a query entry list for the query
_qlist = new QueryEntryList(_query);
add(_qlist);
}
}
/** The most recent query. */
protected String _query;
/** The query text box. */
protected JTextField _qbox;
/** The entry list that displays the results of our query. */
protected QueryEntryList _qlist;
}
@@ -1,5 +1,5 @@
//
// $Id: Entry.java,v 1.3 2001/07/13 00:10:26 mdb Exp $
// $Id: Entry.java,v 1.4 2002/02/22 07:06:33 mdb Exp $
package robodj.repository;
@@ -33,6 +33,18 @@ public class Entry
/** The songs associated with this entry. */
public transient Song[] songs;
/**
* Entry equality is based on entry id.
*/
public boolean equals (Object other)
{
if (other instanceof Entry) {
return entryid == ((Entry)other).entryid;
} else {
return false;
}
}
/**
* Scans the songs array for the song with the specified id and
* returns it if found. Returns null otherwise.
@@ -1,9 +1,10 @@
//
// $Id: Repository.java,v 1.8 2001/09/21 03:09:01 mdb Exp $
// $Id: Repository.java,v 1.9 2002/02/22 07:06:34 mdb Exp $
package robodj.repository;
import java.sql.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
@@ -99,10 +100,10 @@ public class Repository extends JORARepository
* @param query a WHERE clause describing which entries should be
* selected (ie. 'where title like "%foo%"').
*
* @return all entries in the table matching the query
* parameters. <em>Note</em>: this member function does not populate
* the songs arrays of the returned entries. Call
* <code>populateSongs</code> on an entry by entry basis for that.
* @return all entries in the table matching the query parameters.
* <em>Note</em>: this member function does not populate the songs
* arrays of the returned entries. Call <code>populateSongs</code> on
* an entry by entry basis for that.
*/
public Entry[] getEntries (final String query)
throws PersistenceException
@@ -124,6 +125,84 @@ public class Repository extends JORARepository
});
}
/**
* Returns all entries for whom the supplied word is contained in the
* title or artist text or in the text of any of that entry's songs.
*
* @param match a string to be case-insensitively matched in the title
* or artist text.
*
* @return all entries in the table matching the query parameters.
* <em>Note</em>: this member function does not populate the songs
* arrays of the returned entries. Call <code>populateSongs</code> on
* an entry by entry basis for that.
*/
public Entry[] matchEntries (final String match)
throws PersistenceException
{
return (Entry[])execute(new Operation() {
public Object invoke (Connection conn, DatabaseLiaison liaison)
throws PersistenceException, SQLException
{
System.out.println("looking up '" + match + "'.");
PreparedStatement stmt = null;
String query;
try {
// look up matching entries
query = "select entryid, title, artist, source " +
"from entries where title like ? or artist like ?";
stmt = conn.prepareStatement(query);
stmt.setString(1, "%" + match + "%");
stmt.setString(2, "%" + match + "%");
HashIntMap etable = new HashIntMap();
loadEntries(stmt, etable);
JDBCUtil.close(stmt);
// now look up matching songs
query = "select entries.entryid, entries.title, " +
"entries.artist, entries.source from " +
"songs, entries where " +
"songs.entryid = entries.entryid and " +
"songs.title like ?";
stmt = conn.prepareStatement(query);
stmt.setString(1, "%" + match + "%");
loadEntries(stmt, etable);
Entry[] entries = new Entry[etable.size()];
Iterator iter = etable.values().iterator();
for (int i = 0; iter.hasNext(); i++) {
entries[i] = (Entry)iter.next();
}
return entries;
} finally {
JDBCUtil.close(stmt);
}
}
});
}
/**
* Loads entries from the supplied query and inserts them into the
* supplied hash map.
*/
protected void loadEntries (PreparedStatement stmt, HashIntMap entries)
throws SQLException
{
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
Entry entry = new Entry();
entry.entryid = rs.getInt(1);
entry.title = rs.getString(2);
entry.artist = rs.getString(3);
entry.source = rs.getString(4);
entries.put(entry.entryid, entry);
}
}
/**
* Loads the songs for this entry from the database and inserts them
* into its songs array. If the songs are already loaded, this