Revamped preferences handling; added support for voting for songs you
like. Eventually we'll actually make use of the voting information. git-svn-id: https://samskivert.googlecode.com/svn/trunk@1116 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
//
|
||||
// $Id: BrowsePanel.java,v 1.3 2002/11/11 17:04:12 mdb Exp $
|
||||
// $Id: BrowsePanel.java,v 1.4 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import robodj.repository.*;
|
||||
|
||||
public class BrowsePanel extends JTabbedPane
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
//
|
||||
// $Id: CategoryEntryList.java,v 1.1 2002/02/22 07:06:33 mdb Exp $
|
||||
// $Id: CategoryEntryList.java,v 1.2 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.swing.Controller;
|
||||
|
||||
import robodj.repository.Entry;
|
||||
|
||||
@@ -17,13 +18,14 @@ public class CategoryEntryList extends EntryList
|
||||
_categoryId = categoryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in the entries for this category.
|
||||
*/
|
||||
public Entry[] readEntries ()
|
||||
throws PersistenceException
|
||||
// documentation inherited
|
||||
protected Controller createController ()
|
||||
{
|
||||
return Chooser.model.getEntries(_categoryId);
|
||||
return new EntryController(this) {
|
||||
public Entry[] readEntries () throws PersistenceException {
|
||||
return Chooser.model.getEntries(_categoryId);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected String getEmptyString ()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: Chooser.java,v 1.10 2002/11/11 17:04:26 mdb Exp $
|
||||
// $Id: Chooser.java,v 1.11 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
@@ -12,6 +12,7 @@ import javax.swing.JOptionPane;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.jdbc.StaticConnectionProvider;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.samskivert.swing.util.SwingUtil;
|
||||
import com.samskivert.util.ConfigUtil;
|
||||
@@ -20,6 +21,8 @@ import com.samskivert.util.PropertiesUtil;
|
||||
import robodj.Log;
|
||||
import robodj.repository.Model;
|
||||
import robodj.repository.Repository;
|
||||
import robodj.util.RDJPrefs;
|
||||
import robodj.util.RDJPrefsPanel;
|
||||
import robodj.util.ServerControl;
|
||||
|
||||
/**
|
||||
@@ -28,82 +31,86 @@ import robodj.util.ServerControl;
|
||||
*/
|
||||
public class Chooser
|
||||
{
|
||||
public static Properties config;
|
||||
|
||||
public static Repository repository;
|
||||
|
||||
public static Model model;
|
||||
|
||||
public static ServerControl scontrol;
|
||||
|
||||
public static ChooserFrame frame;
|
||||
|
||||
public static void main (String[] args)
|
||||
{
|
||||
// load our main configuration
|
||||
String cpath = "conf/chooser.properties";
|
||||
try {
|
||||
config = ConfigUtil.loadProperties(cpath);
|
||||
} catch (IOException ioe) {
|
||||
String err = "Unable to load configuration " +
|
||||
"[path=" + cpath + "]:\n" + ioe.getMessage();
|
||||
reportError(err);
|
||||
System.exit(-1);
|
||||
}
|
||||
boolean error = false;
|
||||
|
||||
// create an interface to the database repository
|
||||
try {
|
||||
StaticConnectionProvider scp =
|
||||
new StaticConnectionProvider("conf/repository.properties");
|
||||
repository = new Repository(scp);
|
||||
model = new Model(repository);
|
||||
// loop until the user provides us with a configuration that works
|
||||
// or requests to exit
|
||||
for (int ii = 0; ii < 100; ii++) {
|
||||
String repodir = RDJPrefs.getRepositoryDirectory();
|
||||
if (StringUtil.blank(repodir) || ii > 0) {
|
||||
// display the initial configuration wizard if we are not
|
||||
// yet properly configured
|
||||
RDJPrefsPanel.display(true);
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
Log.logStackTrace(ioe);
|
||||
reportError("Error loading repository config:\n" +
|
||||
ioe.getMessage());
|
||||
System.exit(-1);
|
||||
// create an interface to the database repository
|
||||
try {
|
||||
StaticConnectionProvider scp =
|
||||
new StaticConnectionProvider(RDJPrefs.getJDBCConfig());
|
||||
repository = new Repository(scp);
|
||||
model = new Model(repository);
|
||||
|
||||
} catch (PersistenceException pe) {
|
||||
Log.logStackTrace(pe);
|
||||
pe.printStackTrace();
|
||||
reportError("Unable to establish communication " +
|
||||
"with database:\n" + pe.getMessage());
|
||||
System.exit(-1);
|
||||
}
|
||||
} catch (PersistenceException pe) {
|
||||
if (reportError("Unable to establish communication " +
|
||||
"with database:", pe)) {
|
||||
System.exit(-1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
String mhost = System.getProperty("musicd_host", "localhost");
|
||||
String mportstr = System.getProperty("musicd_port", "2500");
|
||||
int mport = 2500;
|
||||
try {
|
||||
mport = Integer.parseInt(mportstr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
Log.warning("Invalid musicd_port value. Using default " +
|
||||
"(" + mport + ").");
|
||||
}
|
||||
try {
|
||||
String host = RDJPrefs.getMusicDaemonHost();
|
||||
if (StringUtil.blank(host)) {
|
||||
throw new IOException(
|
||||
"No music server host specified in configuration.");
|
||||
}
|
||||
// establish a connection with the music server
|
||||
scontrol = new ServerControl(
|
||||
host, RDJPrefs.getMusicDaemonPort());
|
||||
} catch (IOException ioe) {
|
||||
if (reportError("Unable to establish communication with " +
|
||||
"music server on host '" +
|
||||
RDJPrefs.getMusicDaemonHost() + "' ", ioe)) {
|
||||
System.exit(-1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
// establish a connection with the music server
|
||||
scontrol = new ServerControl(mhost, 2500);
|
||||
} catch (IOException ioe) {
|
||||
Log.logStackTrace(ioe);
|
||||
reportError("Unable to establish communication with music " +
|
||||
"server:\n" + ioe.getMessage());
|
||||
System.exit(-1);
|
||||
break;
|
||||
}
|
||||
|
||||
// create our primary user interface frame, center the frame in
|
||||
// the screen and show it
|
||||
ChooserFrame frame = new ChooserFrame();
|
||||
frame.setSize(650, 665);
|
||||
SwingUtil.centerWindow(frame);
|
||||
frame.setVisible(true);
|
||||
frame = new ChooserFrame();
|
||||
frame.setSize(650, 665);
|
||||
SwingUtil.centerWindow(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
protected static void reportError (String error)
|
||||
protected static boolean reportError (String error, Exception e)
|
||||
{
|
||||
Object[] options = { "OK" };
|
||||
JOptionPane.showOptionDialog(null, error, "Error",
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.ERROR_MESSAGE,
|
||||
null, options, options[0]);
|
||||
String text = error;
|
||||
if (e != null) {
|
||||
text = text + "\n\n" + e.getMessage();
|
||||
if (e.getCause() != null) {
|
||||
text = text + "\n" + e.getCause().getMessage();
|
||||
}
|
||||
}
|
||||
Object[] options = { "Edit configuration", "Exit" };
|
||||
int choice = JOptionPane.showOptionDialog(
|
||||
null, text, "Error", JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.ERROR_MESSAGE, null, options, options[0]);
|
||||
System.out.println("Chose " + choice + ".");
|
||||
return (choice == 1 || choice == JOptionPane.CLOSED_OPTION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// $Id: ChooserController.java,v 1.1 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import com.samskivert.swing.Controller;
|
||||
import com.samskivert.swing.util.TaskMaster;
|
||||
import com.samskivert.swing.util.TaskObserver;
|
||||
|
||||
import robodj.Log;
|
||||
|
||||
/**
|
||||
* Handles top-level chooser UI commands.
|
||||
*/
|
||||
public class ChooserController extends Controller
|
||||
implements TaskObserver
|
||||
{
|
||||
public ChooserController ()
|
||||
{
|
||||
// read our playing state
|
||||
TaskMaster.invokeMethodTask("refreshPlaying", Chooser.scontrol, this);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean handleAction (ActionEvent event)
|
||||
{
|
||||
String cmd = event.getActionCommand();
|
||||
if (cmd.equals("exit")) {
|
||||
System.exit(0);
|
||||
|
||||
} else if (cmd.equals("skip")) {
|
||||
TaskMaster.invokeMethodTask("skip", Chooser.scontrol, this);
|
||||
|
||||
} else if (cmd.equals("back")) {
|
||||
TaskMaster.invokeMethodTask("back", Chooser.scontrol, this);
|
||||
|
||||
} else if (cmd.equals("pause")) {
|
||||
TaskMaster.invokeMethodTask("pause", Chooser.scontrol, this);
|
||||
|
||||
} else if (cmd.equals("play")) {
|
||||
TaskMaster.invokeMethodTask("play", Chooser.scontrol, this);
|
||||
|
||||
} else if (cmd.equals("stop")) {
|
||||
TaskMaster.invokeMethodTask("stop", Chooser.scontrol, this);
|
||||
|
||||
} else {
|
||||
System.out.println("Unknown action event: " + cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void taskCompleted (String name, Object result)
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void taskFailed (String name, Throwable exception)
|
||||
{
|
||||
String msg;
|
||||
if (Exception.class.equals(exception.getClass())) {
|
||||
msg = exception.getMessage();
|
||||
} else {
|
||||
msg = exception.toString();
|
||||
}
|
||||
JOptionPane.showMessageDialog(Chooser.frame, msg, "Error",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
Log.logStackTrace(exception);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: ChooserFrame.java,v 1.10 2002/11/11 17:04:41 mdb Exp $
|
||||
// $Id: ChooserFrame.java,v 1.11 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
@@ -10,18 +10,18 @@ import java.awt.event.ActionListener;
|
||||
import javax.swing.*;
|
||||
|
||||
import com.samskivert.swing.*;
|
||||
import com.samskivert.swing.util.TaskAdapter;
|
||||
import com.samskivert.swing.util.TaskObserver;
|
||||
import com.samskivert.swing.util.TaskMaster;
|
||||
import com.samskivert.swing.util.*;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import robodj.Log;
|
||||
import robodj.Version;
|
||||
import robodj.repository.*;
|
||||
import robodj.util.ButtonUtil;
|
||||
import robodj.util.RDJPrefs;
|
||||
import robodj.util.ServerControl.PlayingListener;
|
||||
|
||||
public class ChooserFrame extends JFrame
|
||||
implements ActionListener, TaskObserver, PlayingListener
|
||||
implements PlayingListener, ControllerProvider
|
||||
{
|
||||
public ChooserFrame ()
|
||||
{
|
||||
@@ -59,22 +59,42 @@ public class ChooserFrame extends JFrame
|
||||
bgl.setJustification(GroupLayout.RIGHT);
|
||||
JPanel cbar = new JPanel(bgl);
|
||||
|
||||
// create a label and text field where the chooser user can
|
||||
// identify themselves
|
||||
cbar.add(new JLabel("Initials:"));
|
||||
cbar.add(_userField = new JTextField());
|
||||
Dimension ups = _userField.getPreferredSize();
|
||||
ups.width = 35;
|
||||
_userField.setPreferredSize(ups);
|
||||
cbar.add(new Spacer(100, 10));
|
||||
|
||||
// enforce a maximum of 3 letters in initials
|
||||
SwingUtil.setDocumentHelpers(
|
||||
_userField, new SwingUtil.DocumentValidator() {
|
||||
public boolean isValid (String text) {
|
||||
return (text.length() <= 3);
|
||||
}
|
||||
}, null);
|
||||
|
||||
// display any previously configured initials
|
||||
_userField.setText(RDJPrefs.getUser());
|
||||
|
||||
// add some fake control buttons for now
|
||||
cbar.add(ButtonUtil.createControlButton(
|
||||
BACK_TIP, "back", BACK_ICON_PATH, this, true));
|
||||
BACK_TIP, "back", BACK_ICON_PATH, true));
|
||||
_stop = ButtonUtil.createControlButton(
|
||||
STOP_TIP, "stop", STOP_ICON_PATH, this, true);
|
||||
STOP_TIP, "stop", STOP_ICON_PATH, true);
|
||||
cbar.add(_stop);
|
||||
_pauseIcon = ButtonUtil.getIcon(PAUSE_ICON_PATH);
|
||||
_playIcon = ButtonUtil.getIcon(PLAY_ICON_PATH);
|
||||
_pause = ButtonUtil.createControlButton(
|
||||
"", "pause", _pauseIcon, this, true);
|
||||
"", "pause", _pauseIcon, true);
|
||||
cbar.add(_pause);
|
||||
cbar.add(ButtonUtil.createControlButton(
|
||||
SKIP_TIP, "skip", SKIP_ICON_PATH, this, true));
|
||||
SKIP_TIP, "skip", SKIP_ICON_PATH, true));
|
||||
cbar.add(new Spacer(50, 10));
|
||||
cbar.add(ButtonUtil.createControlButton(
|
||||
EXIT_TIP, "exit", EXIT_ICON_PATH, this, true));
|
||||
EXIT_TIP, "exit", EXIT_ICON_PATH, true));
|
||||
|
||||
// stick it into the frame
|
||||
top.add(cbar, GroupLayout.FIXED);
|
||||
@@ -86,52 +106,44 @@ public class ChooserFrame extends JFrame
|
||||
// add ourselves as a playing listener
|
||||
Chooser.scontrol.addPlayingListener(this);
|
||||
|
||||
// read our playing state
|
||||
TaskMaster.invokeMethodTask("refreshPlaying", Chooser.scontrol, this);
|
||||
// create our controller
|
||||
_controller = new ChooserController();
|
||||
}
|
||||
|
||||
public void actionPerformed (ActionEvent e)
|
||||
// documentation inherited from interface
|
||||
public Controller getController ()
|
||||
{
|
||||
String cmd = e.getActionCommand();
|
||||
if (cmd.equals("exit")) {
|
||||
System.exit(0);
|
||||
|
||||
} else if (cmd.equals("skip")) {
|
||||
TaskMaster.invokeMethodTask("skip", Chooser.scontrol, this);
|
||||
|
||||
} else if (cmd.equals("back")) {
|
||||
TaskMaster.invokeMethodTask("back", Chooser.scontrol, this);
|
||||
|
||||
} else if (cmd.equals("pause")) {
|
||||
TaskMaster.invokeMethodTask("pause", Chooser.scontrol, this);
|
||||
|
||||
} else if (cmd.equals("play")) {
|
||||
TaskMaster.invokeMethodTask("play", Chooser.scontrol, this);
|
||||
|
||||
} else if (cmd.equals("stop")) {
|
||||
TaskMaster.invokeMethodTask("stop", Chooser.scontrol, this);
|
||||
|
||||
} else {
|
||||
System.out.println("Unknown action event: " + cmd);
|
||||
}
|
||||
return _controller;
|
||||
}
|
||||
|
||||
public void taskCompleted (String name, Object result)
|
||||
/**
|
||||
* Returns the string currently entered into the "user" field.
|
||||
*/
|
||||
public String getUser (boolean showError)
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
public void taskFailed (String name, Throwable exception)
|
||||
{
|
||||
String msg;
|
||||
if (Exception.class.equals(exception.getClass())) {
|
||||
msg = exception.getMessage();
|
||||
} else {
|
||||
msg = exception.toString();
|
||||
String user = _userField.getText();
|
||||
// if they haven't supplied a user, complain
|
||||
if (StringUtil.blank(user)) {
|
||||
if (!showError) {
|
||||
return null;
|
||||
}
|
||||
String errmsg = "The feature you have requested requires " +
|
||||
"that you identify yourself by entering your initials in " +
|
||||
"the 'Initials' box at the bottom of the window.";
|
||||
JOptionPane.showMessageDialog(this, errmsg, "Initials required",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
return null;
|
||||
}
|
||||
JOptionPane.showMessageDialog(this, msg, "Error",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
Log.logStackTrace(exception);
|
||||
|
||||
// if they typed in mixed or upper case, lower it for them
|
||||
user = user.toLowerCase();
|
||||
if (!user.equals(_userField.getText())) {
|
||||
_userField.setText(user);
|
||||
}
|
||||
|
||||
// make sure we've saved these initials values
|
||||
RDJPrefs.config.setValue(RDJPrefs.USER_KEY, user);
|
||||
return user;
|
||||
}
|
||||
|
||||
public void playingUpdated (int songid, boolean paused)
|
||||
@@ -150,6 +162,12 @@ public class ChooserFrame extends JFrame
|
||||
_stop.setEnabled(songid != -1);
|
||||
}
|
||||
|
||||
/** Our top-level controller. */
|
||||
protected Controller _controller;
|
||||
|
||||
/** A field where the user can identify themselves. */
|
||||
protected JTextField _userField;
|
||||
|
||||
/** A reference to the play/pause button. */
|
||||
protected JButton _pause;
|
||||
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
//
|
||||
// $Id: EntryController.java,v 1.1 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import javax.swing.event.AncestorEvent;
|
||||
import javax.swing.event.AncestorListener;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.swing.util.SwingUtil;
|
||||
import com.samskivert.swing.util.TaskMaster;
|
||||
|
||||
import robodj.Log;
|
||||
import robodj.repository.Entry;
|
||||
import robodj.repository.Song;
|
||||
|
||||
/**
|
||||
* Handles default entry list behavior.
|
||||
*/
|
||||
public abstract class EntryController extends ItemController
|
||||
implements AncestorListener
|
||||
{
|
||||
public EntryController (EntryList list)
|
||||
{
|
||||
super(list);
|
||||
_list = list;
|
||||
_list.addAncestorListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the entries from the database.
|
||||
*/
|
||||
public void readSongs ()
|
||||
throws PersistenceException
|
||||
{
|
||||
Chooser.repository.populateSongs(_entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the entries from the database and plays them all.
|
||||
*/
|
||||
public void readAndPlay ()
|
||||
throws PersistenceException
|
||||
{
|
||||
Chooser.repository.populateSongs(_entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the category for the displayed entry.
|
||||
*/
|
||||
public void recategorizeEntry ()
|
||||
throws PersistenceException
|
||||
{
|
||||
Chooser.model.recategorize(_entry, _newcatid);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void taskCompleted (String name, Object result)
|
||||
{
|
||||
if (name.equals("readEntries")) {
|
||||
// the result should be an array of entry objects with which
|
||||
// we can populate our button list
|
||||
_entries = (Entry[])result;
|
||||
_list.populateEntries(_entries);
|
||||
|
||||
} else if (name.equals("readAndPlay")) {
|
||||
for (int i = 0; i < _entry.songs.length; i++) {
|
||||
Chooser.scontrol.append(_entry.songs[i].entryid,
|
||||
_entry.songs[i].songid,
|
||||
_entry.songs[i].location);
|
||||
}
|
||||
|
||||
} else if (name.equals("readSongs")) {
|
||||
_list.populateSong(_entry);
|
||||
|
||||
} else {
|
||||
super.taskCompleted(name, result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 abstract Entry[] readEntries ()
|
||||
throws PersistenceException;
|
||||
|
||||
// documentation inherited from interface
|
||||
public boolean handleAction (ActionEvent e)
|
||||
{
|
||||
String cmd = e.getActionCommand();
|
||||
if (cmd.equals(EntryItem.BROWSE)) {
|
||||
_entry = EntryItem.getEntry(e.getSource());
|
||||
// start up the task that reads this CDs songs from the database
|
||||
TaskMaster.invokeMethodTask("readSongs", this, this);
|
||||
|
||||
} else if (cmd.equals("playall")) {
|
||||
_entry = EntryItem.getEntry(e.getSource());
|
||||
// start up the task that reads this CDs songs from the database
|
||||
TaskMaster.invokeMethodTask("readAndPlay", this, this);
|
||||
|
||||
} else if (cmd.equals("play")) {
|
||||
Song song = SongItem.getSong(e.getSource());
|
||||
Chooser.scontrol.append(song.entryid, song.songid, song.location);
|
||||
|
||||
} else if (cmd.equals("up")) {
|
||||
// re-read the category beacuse this entry may have been
|
||||
// recategorized
|
||||
TaskMaster.invokeMethodTask("readEntries", this, this);
|
||||
|
||||
} else if (cmd.equals("edit")) {
|
||||
EditDialog dialog = new EditDialog(_entry);
|
||||
dialog.setSize(400, 400);
|
||||
SwingUtil.centerWindow(dialog);
|
||||
dialog.show();
|
||||
|
||||
} else if (cmd.equals("categorize")) {
|
||||
JComboBox cb = (JComboBox)e.getSource();
|
||||
String catname = (String)cb.getSelectedItem();
|
||||
_newcatid = Chooser.model.getCategoryId(catname);
|
||||
// do the recategorization in a separate task
|
||||
TaskMaster.invokeMethodTask("recategorizeEntry", this, this);
|
||||
|
||||
} else {
|
||||
return super.handleAction(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void ancestorAdded (AncestorEvent e)
|
||||
{
|
||||
// stick a "loading" label in the list to let the user know
|
||||
// what's up
|
||||
_list._bpanel.add(new JLabel("Loading..."));
|
||||
|
||||
// we need to revalidate the component because we added a child
|
||||
_list.revalidate();
|
||||
_list.repaint();
|
||||
|
||||
// start up the task that reads the CD info from the database
|
||||
TaskMaster.invokeMethodTask("readEntries", this, this);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void ancestorRemoved (AncestorEvent e)
|
||||
{
|
||||
// clear out our entry ui elements
|
||||
_list._bpanel.removeAll();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void ancestorMoved (AncestorEvent e)
|
||||
{
|
||||
// nothing doing
|
||||
}
|
||||
|
||||
protected EntryList _list;
|
||||
protected Entry[] _entries;
|
||||
protected Entry _entry;
|
||||
protected int _newcatid;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// $Id: EntryItem.java,v 1.1 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
|
||||
import com.samskivert.swing.HGroupLayout;
|
||||
|
||||
import robodj.repository.Entry;
|
||||
import robodj.util.ButtonUtil;
|
||||
|
||||
/**
|
||||
* Displays an entry in the browser.
|
||||
*/
|
||||
public class EntryItem extends Item
|
||||
{
|
||||
public static final String BROWSE = "entry:browse";
|
||||
|
||||
public static final String PLAY = "entry:play";
|
||||
|
||||
public EntryItem (Entry entry)
|
||||
{
|
||||
_entry = entry;
|
||||
|
||||
// set up our layout manager
|
||||
HGroupLayout gl = new HGroupLayout(HGroupLayout.NONE);
|
||||
gl.setOffAxisPolicy(HGroupLayout.STRETCH);
|
||||
gl.setJustification(HGroupLayout.LEFT);
|
||||
setLayout(gl);
|
||||
|
||||
// create a browse and a play button
|
||||
JButton button;
|
||||
|
||||
// add a browse button
|
||||
button = ButtonUtil.createControlButton(
|
||||
BROWSE_ENTRY_TIP, BROWSE, _browseIcon, true);
|
||||
button.putClientProperty(ENTRY_PROP, entry);
|
||||
add(button, HGroupLayout.FIXED);
|
||||
|
||||
// add a play all button
|
||||
button = ButtonUtil.createControlButton(
|
||||
PLAY_ENTRY_TIP, PLAY, _playIcon, true);
|
||||
button.putClientProperty(ENTRY_PROP, entry);
|
||||
add(button, HGroupLayout.FIXED);
|
||||
|
||||
// add the entry title
|
||||
JLabel entryLabel = new JLabel(entry.title);
|
||||
entryLabel.setFont(_nameFont);
|
||||
entryLabel.setToolTipText(entry.title + " (" + entry.entryid + ")");
|
||||
add(entryLabel);
|
||||
}
|
||||
|
||||
public static Entry getEntry (Object source)
|
||||
{
|
||||
return (Entry)((JButton)source).getClientProperty(ENTRY_PROP);
|
||||
}
|
||||
|
||||
protected Entry _entry;
|
||||
|
||||
protected static final String ENTRY_PROP = "entry";
|
||||
|
||||
protected static final String BROWSE_ENTRY_TIP =
|
||||
"Browse the songs in this album";
|
||||
protected static final String PLAY_ENTRY_TIP =
|
||||
"Append this album to the playlist";
|
||||
|
||||
protected static ImageIcon _browseIcon =
|
||||
ButtonUtil.getIcon(ICON_ROOT + "browse.png");
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
//
|
||||
// $Id: EntryList.java,v 1.12 2002/03/03 20:56:12 mdb Exp $
|
||||
// $Id: EntryList.java,v 1.13 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -21,7 +19,7 @@ import robodj.repository.*;
|
||||
import robodj.util.ButtonUtil;
|
||||
|
||||
public abstract class EntryList extends JScrollPane
|
||||
implements TaskObserver, ActionListener, AncestorListener
|
||||
implements ControllerProvider
|
||||
{
|
||||
public EntryList ()
|
||||
{
|
||||
@@ -46,88 +44,22 @@ public abstract class EntryList extends JScrollPane
|
||||
|
||||
// use a special font for our name buttons
|
||||
_titleFont = new Font("Helvetica", Font.BOLD, 14);
|
||||
_nameFont = new Font("Helvetica", Font.PLAIN, 12);
|
||||
|
||||
// create our icons
|
||||
_browseIcon = ButtonUtil.getIcon(BROWSE_ICON_PATH);
|
||||
_playIcon = ButtonUtil.getIcon(PLAY_ICON_PATH);
|
||||
|
||||
// listen to ancestor events
|
||||
addAncestorListener(this);
|
||||
// create our controller
|
||||
_controller = createController();
|
||||
}
|
||||
|
||||
public void taskCompleted (String name, Object result)
|
||||
public Controller getController ()
|
||||
{
|
||||
if (name.equals("readEntries")) {
|
||||
// the result should be an array of entry objects with which
|
||||
// we can populate our button list
|
||||
_entries = (Entry[])result;
|
||||
populateEntries(_entries);
|
||||
|
||||
} else if (name.equals("readAndPlay")) {
|
||||
for (int i = 0; i < _entry.songs.length; i++) {
|
||||
Chooser.scontrol.append(_entry.songs[i].entryid,
|
||||
_entry.songs[i].songid,
|
||||
_entry.songs[i].location);
|
||||
}
|
||||
|
||||
} else if (name.equals("readSongs")) {
|
||||
populateSong(_entry);
|
||||
}
|
||||
return _controller;
|
||||
}
|
||||
|
||||
public void taskFailed (String name, Throwable exception)
|
||||
{
|
||||
String msg;
|
||||
if (Exception.class.equals(exception.getClass())) {
|
||||
msg = exception.getMessage();
|
||||
} else {
|
||||
msg = exception.toString();
|
||||
}
|
||||
JOptionPane.showMessageDialog(this, msg, "Error",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
Log.logStackTrace(exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 abstract Entry[] readEntries ()
|
||||
throws PersistenceException;
|
||||
/** Creates the controller for this entry list. */
|
||||
protected abstract Controller createController ();
|
||||
|
||||
/** The string to display when there are no matching results. */
|
||||
protected abstract String getEmptyString ();
|
||||
|
||||
/**
|
||||
* Reads the entries from the database.
|
||||
*/
|
||||
public void readSongs ()
|
||||
throws PersistenceException
|
||||
{
|
||||
Chooser.repository.populateSongs(_entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the entries from the database and plays them all.
|
||||
*/
|
||||
public void readAndPlay ()
|
||||
throws PersistenceException
|
||||
{
|
||||
Chooser.repository.populateSongs(_entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the category for the displayed entry.
|
||||
*/
|
||||
public void recategorizeEntry ()
|
||||
throws PersistenceException
|
||||
{
|
||||
Chooser.model.recategorize(_entry, _newcatid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the proper buttons, etc. for each entry.
|
||||
*/
|
||||
@@ -158,37 +90,12 @@ public abstract class EntryList extends JScrollPane
|
||||
_bpanel.add(label);
|
||||
}
|
||||
|
||||
// create a browse and a play button
|
||||
GroupLayout gl = new HGroupLayout(GroupLayout.NONE);
|
||||
gl.setOffAxisPolicy(GroupLayout.STRETCH);
|
||||
gl.setJustification(GroupLayout.LEFT);
|
||||
JPanel hpanel = new JPanel(gl);
|
||||
JButton button;
|
||||
|
||||
// add a browse button
|
||||
button = ButtonUtil.createControlButton(
|
||||
BROWSE_ENTRY_TIP, "browse", _browseIcon, this, true);
|
||||
button.putClientProperty("entry", entries[i]);
|
||||
hpanel.add(button, GroupLayout.FIXED);
|
||||
|
||||
// add a play all button
|
||||
button = ButtonUtil.createControlButton(
|
||||
PLAY_ENTRY_TIP, "playall", _playIcon, this, true);
|
||||
button.putClientProperty("entry", entries[i]);
|
||||
hpanel.add(button, GroupLayout.FIXED);
|
||||
|
||||
// add the entry title
|
||||
JLabel entryLabel = new JLabel(entries[i].title);
|
||||
entryLabel.setFont(_nameFont);
|
||||
entryLabel.setToolTipText(entries[i].title +
|
||||
" (" + entries[i].entryid + ")");
|
||||
hpanel.add(entryLabel);
|
||||
|
||||
_bpanel.add(hpanel);
|
||||
// create an entry item for this entry
|
||||
_bpanel.add(new EntryItem(entries[i]));
|
||||
}
|
||||
|
||||
// if there were no entries, stick a label in to that effect
|
||||
if (_entries.length == 0) {
|
||||
if (entries.length == 0) {
|
||||
_bpanel.add(new JLabel(getEmptyString()));
|
||||
}
|
||||
|
||||
@@ -224,12 +131,12 @@ public abstract class EntryList extends JScrollPane
|
||||
|
||||
// add a button for getting the heck out of here
|
||||
JButton upbtn = ButtonUtil.createControlButton(
|
||||
UP_TIP, "up", ButtonUtil.getIcon(UP_ICON_PATH), this, true);
|
||||
UP_TIP, "up", ButtonUtil.getIcon(UP_ICON_PATH), true);
|
||||
header.add(upbtn, GroupLayout.FIXED);
|
||||
|
||||
// create an edit button
|
||||
JButton ebtn = ButtonUtil.createControlButton(
|
||||
EDIT_TIP, "edit", ButtonUtil.getIcon(EDIT_ICON_PATH), this, true);
|
||||
EDIT_TIP, "edit", ButtonUtil.getIcon(EDIT_ICON_PATH), true);
|
||||
header.add(ebtn, GroupLayout.FIXED);
|
||||
|
||||
// add a combo box for categorizing
|
||||
@@ -238,7 +145,7 @@ public abstract class EntryList extends JScrollPane
|
||||
header.add(catcombo, GroupLayout.FIXED);
|
||||
|
||||
// configure the combo box
|
||||
catcombo.addActionListener(this);
|
||||
catcombo.addActionListener(Controller.DISPATCHER);
|
||||
catcombo.setActionCommand("categorize");
|
||||
int catid = Chooser.model.getCategory(entry.entryid);
|
||||
int catidx = ModelUtil.getCategoryIndex(Chooser.model, catid);
|
||||
@@ -260,23 +167,7 @@ public abstract class EntryList extends JScrollPane
|
||||
|
||||
// and add buttons for every song
|
||||
for (int i = 0; i < entry.songs.length; i++) {
|
||||
gl = new HGroupLayout(GroupLayout.NONE);
|
||||
gl.setJustification(GroupLayout.LEFT);
|
||||
JPanel hpanel = new JPanel(gl);
|
||||
|
||||
// add a button for playing the song
|
||||
JButton button = ButtonUtil.createControlButton(
|
||||
PLAY_SONG_TIP, "play", _playIcon, this, true);
|
||||
button.putClientProperty("song", entry.songs[i]);
|
||||
hpanel.add(button, GroupLayout.FIXED);
|
||||
|
||||
// add the song title
|
||||
JLabel trackLabel = new JLabel(entry.songs[i].title);
|
||||
trackLabel.setFont(_nameFont);
|
||||
trackLabel.setToolTipText(entry.songs[i].title);
|
||||
hpanel.add(trackLabel);
|
||||
|
||||
_bpanel.add(hpanel);
|
||||
_bpanel.add(new SongItem(entry.songs[i], SongItem.BROWSER));
|
||||
}
|
||||
|
||||
// reset our scroll position so that we're displaying the top of
|
||||
@@ -294,99 +185,17 @@ public abstract class EntryList extends JScrollPane
|
||||
model.setValue(model.getMinimum());
|
||||
}
|
||||
|
||||
public void actionPerformed (ActionEvent e)
|
||||
{
|
||||
String cmd = e.getActionCommand();
|
||||
if (cmd.equals("browse")) {
|
||||
JButton src = (JButton)e.getSource();
|
||||
_entry = (Entry)src.getClientProperty("entry");
|
||||
// start up the task that reads this CDs songs from the database
|
||||
TaskMaster.invokeMethodTask("readSongs", this, this);
|
||||
|
||||
} else if (cmd.equals("playall")) {
|
||||
JButton src = (JButton)e.getSource();
|
||||
_entry = (Entry)src.getClientProperty("entry");
|
||||
// start up the task that reads this CDs songs from the database
|
||||
TaskMaster.invokeMethodTask("readAndPlay", this, this);
|
||||
|
||||
} else if (cmd.equals("play")) {
|
||||
JButton src = (JButton)e.getSource();
|
||||
Song song = (Song)src.getClientProperty("song");
|
||||
Chooser.scontrol.append(song.entryid, song.songid, song.location);
|
||||
|
||||
} else if (cmd.equals("up")) {
|
||||
// re-read the category beacuse this entry may have been
|
||||
// recategorized
|
||||
TaskMaster.invokeMethodTask("readEntries", this, this);
|
||||
|
||||
} else if (cmd.equals("edit")) {
|
||||
EditDialog dialog = new EditDialog(_entry);
|
||||
dialog.setSize(400, 400);
|
||||
SwingUtil.centerWindow(dialog);
|
||||
dialog.show();
|
||||
|
||||
} else if (cmd.equals("categorize")) {
|
||||
JComboBox cb = (JComboBox)e.getSource();
|
||||
String catname = (String)cb.getSelectedItem();
|
||||
_newcatid = Chooser.model.getCategoryId(catname);
|
||||
// do the recategorization in a separate task
|
||||
TaskMaster.invokeMethodTask("recategorizeEntry", this, this);
|
||||
|
||||
} else {
|
||||
Log.warning("Unknown action event: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
public void ancestorAdded (AncestorEvent e)
|
||||
{
|
||||
// stick a "loading" label in the list to let the user know
|
||||
// what's up
|
||||
_bpanel.add(new JLabel("Loading..."));
|
||||
|
||||
// we need to revalidate the component because we added a child
|
||||
revalidate();
|
||||
repaint();
|
||||
|
||||
// start up the task that reads the CD info from the database
|
||||
TaskMaster.invokeMethodTask("readEntries", this, this);
|
||||
}
|
||||
|
||||
public void ancestorRemoved (AncestorEvent e)
|
||||
{
|
||||
// clear out our entry ui elements
|
||||
_bpanel.removeAll();
|
||||
}
|
||||
|
||||
public void ancestorMoved (AncestorEvent e)
|
||||
{
|
||||
// nothing doing
|
||||
}
|
||||
|
||||
protected Controller _controller;
|
||||
protected JPanel _bpanel;
|
||||
|
||||
protected Entry[] _entries;
|
||||
protected Entry _entry;
|
||||
protected int _newcatid;
|
||||
|
||||
protected Font _titleFont;
|
||||
protected Font _nameFont;
|
||||
protected ImageIcon _playIcon;
|
||||
protected ImageIcon _browseIcon;
|
||||
|
||||
protected static final String PLAY_ENTRY_TIP =
|
||||
"Append this album to the playlist";
|
||||
protected static final String PLAY_SONG_TIP =
|
||||
"Append this song to the playlist";
|
||||
protected static final String BROWSE_ENTRY_TIP =
|
||||
"Browse the songs in this album";
|
||||
protected static final String UP_TIP =
|
||||
"Back up to albums listing";
|
||||
protected static final String EDIT_TIP =
|
||||
"Edit the album information";
|
||||
|
||||
protected static final String ICON_ROOT = "/robodj/chooser/images/";
|
||||
protected static final String PLAY_ICON_PATH = ICON_ROOT + "play.png";
|
||||
protected static final String BROWSE_ICON_PATH = ICON_ROOT + "browse.png";
|
||||
protected static final String UP_ICON_PATH = ICON_ROOT + "up.png";
|
||||
protected static final String EDIT_ICON_PATH = ICON_ROOT + "edit.png";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// $Id: Item.java,v 1.1 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Graphics;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.samskivert.swing.util.SwingUtil;
|
||||
|
||||
import robodj.util.ButtonUtil;
|
||||
|
||||
/**
|
||||
* The base class for items displayed in an entry list or playlist.
|
||||
*/
|
||||
public class Item extends JPanel
|
||||
{
|
||||
// documentation inherited
|
||||
protected void paintChildren (Graphics g)
|
||||
{
|
||||
Graphics2D gfx = (Graphics2D)g;
|
||||
Object key = SwingUtil.activateAntiAliasing(gfx);
|
||||
super.paintChildren(g);
|
||||
SwingUtil.restoreAntiAliasing(gfx, key);
|
||||
}
|
||||
|
||||
protected static Font _nameFont = new Font("Dialog", Font.PLAIN, 12);
|
||||
protected static Font _hasVotesFont =
|
||||
new Font("Dialog", Font.ITALIC, 12);
|
||||
|
||||
protected static final String ICON_ROOT = "/robodj/chooser/images/";
|
||||
|
||||
protected static ImageIcon _playIcon =
|
||||
ButtonUtil.getIcon(ICON_ROOT + "play.png");
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// $Id: ItemController.java,v 1.1 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.swing.Controller;
|
||||
import com.samskivert.swing.util.TaskMaster;
|
||||
import com.samskivert.swing.util.TaskObserver;
|
||||
|
||||
import robodj.Log;
|
||||
import robodj.repository.Song;
|
||||
|
||||
/**
|
||||
* Handles standard commands when displaying lists of items.
|
||||
*/
|
||||
public abstract class ItemController extends Controller
|
||||
implements TaskObserver
|
||||
{
|
||||
public ItemController (JComponent panel)
|
||||
{
|
||||
_panel = panel;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public boolean handleAction (ActionEvent e)
|
||||
{
|
||||
String cmd = e.getActionCommand();
|
||||
if (cmd.equals(SongItem.ADD_VOTE)) {
|
||||
JButton button = (JButton)e.getSource();
|
||||
SongItem item = (SongItem)button.getParent();
|
||||
_song = item.getSong();
|
||||
if (_song.addVote(Chooser.frame.getUser(true))) {
|
||||
item.update();
|
||||
TaskMaster.invokeMethodTask("updateSong", this, this);
|
||||
}
|
||||
|
||||
} else if (cmd.equals(SongItem.CLEAR_VOTE)) {
|
||||
JButton button = (JButton)e.getSource();
|
||||
SongItem item = (SongItem)button.getParent();
|
||||
_song = item.getSong();
|
||||
if (_song.clearVote(Chooser.frame.getUser(true))) {
|
||||
item.update();
|
||||
TaskMaster.invokeMethodTask("updateSong", this, this);
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.warning("Unknown action event: " + cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the song referenced by {@link #_song} in the repository.
|
||||
*/
|
||||
public void updateSong ()
|
||||
{
|
||||
if (_song != null) {
|
||||
try {
|
||||
Chooser.repository.updateSong(_song);
|
||||
} catch (PersistenceException pe) {
|
||||
Chooser.reportError(
|
||||
"Failure updating song '" + _song + "'", pe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void taskCompleted (String name, Object result)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void taskFailed (String name, Throwable exception)
|
||||
{
|
||||
String msg;
|
||||
if (Exception.class.equals(exception.getClass())) {
|
||||
msg = exception.getMessage();
|
||||
} else {
|
||||
msg = exception.toString();
|
||||
}
|
||||
JOptionPane.showMessageDialog(_panel, msg, "Error",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
Log.logStackTrace(exception);
|
||||
}
|
||||
|
||||
protected JComponent _panel;
|
||||
protected Song _song;
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
//
|
||||
// $Id: PlaylistController.java,v 1.1 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.samskivert.swing.util.SwingUtil;
|
||||
import com.samskivert.swing.util.TaskAdapter;
|
||||
import com.samskivert.swing.util.TaskMaster;
|
||||
|
||||
import robodj.Log;
|
||||
import robodj.chooser.PlaylistPanel.PlaylistEntry;
|
||||
import robodj.repository.Entry;
|
||||
import robodj.repository.Song;
|
||||
import robodj.util.ServerControl.PlayingListener;
|
||||
|
||||
/**
|
||||
* Handles playlist UI commands.
|
||||
*/
|
||||
public class PlaylistController extends ItemController
|
||||
implements PlayingListener
|
||||
{
|
||||
public PlaylistController (PlaylistPanel panel)
|
||||
{
|
||||
super(panel);
|
||||
_panel = panel;
|
||||
|
||||
// add ourselves as a playing listener
|
||||
Chooser.scontrol.addPlayingListener(this);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean handleAction (ActionEvent e)
|
||||
{
|
||||
String cmd = e.getActionCommand();
|
||||
if (cmd.equals(PlaylistPanel.CLEAR)) {
|
||||
TaskMaster.invokeMethodTask("clear", Chooser.scontrol, this);
|
||||
|
||||
} else if (cmd.equals(PlaylistPanel.REFRESH)) {
|
||||
_panel.prepareForRefresh();
|
||||
|
||||
// start up the task that reads the CD info from the database
|
||||
TaskMaster.invokeMethodTask("readPlaylist", this, this);
|
||||
|
||||
} else if (cmd.equals(SongItem.SKIP_TO)) {
|
||||
JButton button = (JButton)e.getSource();
|
||||
SongItem item = (SongItem)button.getParent();
|
||||
|
||||
// fire up a task to talk to the music daemon
|
||||
final int songid = item.getSong().songid;
|
||||
TaskMaster.invokeTask("noop", new TaskAdapter() {
|
||||
public Object invoke () throws Exception {
|
||||
Chooser.scontrol.skipto(songid);
|
||||
return null;
|
||||
}
|
||||
}, this);
|
||||
|
||||
} else if (cmd.equals(SongItem.REMOVE)) {
|
||||
JButton button = (JButton)e.getSource();
|
||||
SongItem item = (SongItem)button.getParent();
|
||||
|
||||
// remove the entry UI elements
|
||||
item.getParent().remove(item);
|
||||
SwingUtil.refresh(_panel); // relayout
|
||||
|
||||
// remove the entry from the playlist
|
||||
_panel.plist.remove((PlaylistEntry)item.extra);
|
||||
|
||||
// fire up a task to talk to the music daemon
|
||||
final int songid = item.getSong().songid;
|
||||
TaskMaster.invokeTask("noop", new TaskAdapter() {
|
||||
public Object invoke () throws Exception {
|
||||
Chooser.scontrol.remove(songid);
|
||||
return null;
|
||||
}
|
||||
}, this);
|
||||
|
||||
} else if (cmd.equals(PlaylistPanel.REMOVE_ALL)) {
|
||||
JButton src = (JButton)e.getSource();
|
||||
PlaylistEntry entry =
|
||||
(PlaylistEntry)src.getClientProperty("entry");
|
||||
|
||||
// remove all entries starting with this one until we get to
|
||||
// one that has a different entryid
|
||||
int count = 0;
|
||||
Iterator iter = _panel.plist.iterator();
|
||||
while (iter.hasNext()) {
|
||||
PlaylistEntry pe = (PlaylistEntry)iter.next();
|
||||
if (entry == pe) {
|
||||
count++;
|
||||
// remove the entry UI elements
|
||||
pe.item.getParent().remove(pe.item);
|
||||
// remove the entry
|
||||
iter.remove();
|
||||
|
||||
} else if (count > 0) {
|
||||
if (pe.entry.entryid == entry.entry.entryid) {
|
||||
count++;
|
||||
// remove the entry UI elements
|
||||
pe.item.getParent().remove(pe.item);
|
||||
// remove the entry
|
||||
iter.remove();
|
||||
|
||||
} else {
|
||||
// we hit an entry that doesn't match, bail
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove the title and stuff
|
||||
JPanel tpanel = (JPanel)src.getParent();
|
||||
tpanel.getParent().remove(tpanel);
|
||||
|
||||
_panel.revalidate(); // relayout
|
||||
|
||||
// fire up a task to talk to the music daemon, telling it to
|
||||
// remove those entries
|
||||
final int songid = entry.song.songid;
|
||||
final int fcount = count;
|
||||
TaskMaster.invokeTask("noop", new TaskAdapter() {
|
||||
public Object invoke () throws Exception {
|
||||
Chooser.scontrol.removeGroup(songid, fcount);
|
||||
return null;
|
||||
}
|
||||
}, this);
|
||||
|
||||
} else {
|
||||
return super.handleAction(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void readPlaylist ()
|
||||
throws PersistenceException
|
||||
{
|
||||
// clear out any previous playlist
|
||||
_panel.plist.clear();
|
||||
|
||||
// get the playlist from the music daemon
|
||||
String[] plist = Chooser.scontrol.getPlaylist();
|
||||
|
||||
// parse it into playlist entries
|
||||
for (int i = 0; i < plist.length; i++) {
|
||||
String[] toks = StringUtil.split(plist[i], "\t");
|
||||
int eid, sid;
|
||||
try {
|
||||
eid = Integer.parseInt(toks[0]);
|
||||
sid = Integer.parseInt(toks[1]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
Log.warning("Bogus playlist record: '" + plist[i] + "'.");
|
||||
continue;
|
||||
}
|
||||
Entry entry = Chooser.model.getEntry(eid);
|
||||
if (entry != null) {
|
||||
Song song = entry.getSong(sid);
|
||||
_panel.plist.add(new PlaylistEntry(entry, song));
|
||||
} else {
|
||||
Log.warning("Unable to load entry [eid=" + eid + "].");
|
||||
}
|
||||
}
|
||||
|
||||
// now find out what's currently playing
|
||||
Chooser.scontrol.refreshPlaying();
|
||||
}
|
||||
|
||||
public void playingUpdated (int songid, boolean paused)
|
||||
{
|
||||
// unhighlight whoever is playing now
|
||||
PlaylistEntry pentry = getPlayingEntry();
|
||||
if (pentry != null && pentry.item != null) {
|
||||
pentry.item.setIsPlaying(false);
|
||||
}
|
||||
|
||||
// grab the new playing song id
|
||||
_playid = songid;
|
||||
|
||||
// highlight the playing song
|
||||
for (int i = 0; i < _panel.plist.size(); i++) {
|
||||
PlaylistEntry entry = (PlaylistEntry)_panel.plist.get(i);
|
||||
if (entry.song.songid == _playid && entry.item != null) {
|
||||
entry.item.setIsPlaying(true);
|
||||
}
|
||||
}
|
||||
_panel.repaint();
|
||||
}
|
||||
|
||||
protected PlaylistEntry getPlayingEntry ()
|
||||
{
|
||||
for (int i = 0; i < _panel.plist.size(); i++) {
|
||||
PlaylistEntry entry = (PlaylistEntry)_panel.plist.get(i);
|
||||
if (entry.song.songid == _playid) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void taskCompleted (String name, Object result)
|
||||
{
|
||||
if (name.equals("readPlaylist")) {
|
||||
_panel.populatePlaylist(_panel.plist, _playid);
|
||||
} else {
|
||||
super.taskCompleted(name, result);
|
||||
}
|
||||
}
|
||||
|
||||
protected PlaylistPanel _panel;
|
||||
|
||||
protected int _playid;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: PlaylistPanel.java,v 1.13 2002/03/03 20:56:12 mdb Exp $
|
||||
// $Id: PlaylistPanel.java,v 1.14 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
@@ -19,11 +19,32 @@ import com.samskivert.util.StringUtil;
|
||||
import robodj.Log;
|
||||
import robodj.repository.*;
|
||||
import robodj.util.ButtonUtil;
|
||||
import robodj.util.ServerControl.PlayingListener;
|
||||
|
||||
public class PlaylistPanel extends JPanel
|
||||
implements TaskObserver, ActionListener, PlayingListener
|
||||
public class PlaylistPanel extends ControlledPanel
|
||||
{
|
||||
public static class PlaylistEntry
|
||||
{
|
||||
public Entry entry;
|
||||
|
||||
public Song song;
|
||||
|
||||
public SongItem item;
|
||||
|
||||
public PlaylistEntry (Entry entry, Song song)
|
||||
{
|
||||
this.entry = entry;
|
||||
this.song = song;
|
||||
}
|
||||
}
|
||||
|
||||
public static final String REFRESH = "refresh";
|
||||
|
||||
public static final String CLEAR = "clear";
|
||||
|
||||
public static final String REMOVE_ALL = "remove_all";
|
||||
|
||||
public ArrayList plist = new ArrayList();
|
||||
|
||||
public PlaylistPanel ()
|
||||
{
|
||||
GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH);
|
||||
@@ -50,127 +71,34 @@ public class PlaylistPanel extends JPanel
|
||||
|
||||
// add our control buttons
|
||||
_clearbut = ButtonUtil.createControlButton(
|
||||
CLEAR_TIP, "clear", CLEAR_ICON_PATH, this);
|
||||
CLEAR_TIP, "clear", CLEAR_ICON_PATH);
|
||||
cbar.add(_clearbut);
|
||||
cbar.add(ButtonUtil.createControlButton(
|
||||
REFRESH_TIP, "refresh", REFRESH_ICON_PATH, this));
|
||||
REFRESH_TIP, "refresh", REFRESH_ICON_PATH));
|
||||
add(cbar, GroupLayout.FIXED);
|
||||
|
||||
// use a special font for our name buttons
|
||||
_nameFont = new Font("Helvetica", Font.PLAIN, 12);
|
||||
|
||||
// create our icons
|
||||
_skiptoIcon = ButtonUtil.getIcon(SKIPTO_ICON_PATH);
|
||||
_removeSongIcon = ButtonUtil.getIcon(REMOVE_SONG_ICON_PATH);
|
||||
_removeEntryIcon = ButtonUtil.getIcon(REMOVE_ENTRY_ICON_PATH);
|
||||
|
||||
// add ourselves as a playing listener
|
||||
Chooser.scontrol.addPlayingListener(this);
|
||||
|
||||
// load up the playlist
|
||||
refreshPlaylist();
|
||||
}
|
||||
|
||||
public void actionPerformed (ActionEvent e)
|
||||
// documentation inherited
|
||||
public void addNotify ()
|
||||
{
|
||||
String cmd = e.getActionCommand();
|
||||
if (cmd.equals("clear")) {
|
||||
TaskMaster.invokeMethodTask("clear", Chooser.scontrol, this);
|
||||
|
||||
} else if (cmd.equals("refresh")) {
|
||||
refreshPlaylist();
|
||||
|
||||
} else if (cmd.equals("skipto")) {
|
||||
JButton src = (JButton)e.getSource();
|
||||
PlaylistEntry entry =
|
||||
(PlaylistEntry)src.getClientProperty("entry");
|
||||
|
||||
// fire up a task to talk to the music daemon
|
||||
final int songid = entry.song.songid;
|
||||
TaskMaster.invokeTask("noop", new TaskAdapter() {
|
||||
public Object invoke () throws Exception {
|
||||
Chooser.scontrol.skipto(songid);
|
||||
return null;
|
||||
}
|
||||
}, this);
|
||||
|
||||
} else if (cmd.equals("remove")) {
|
||||
JButton src = (JButton)e.getSource();
|
||||
PlaylistEntry entry =
|
||||
(PlaylistEntry)src.getClientProperty("entry");
|
||||
|
||||
// remove the entry UI elements
|
||||
JPanel epanel = (JPanel)entry.label.getParent();
|
||||
epanel.getParent().remove(epanel);
|
||||
revalidate(); // relayout
|
||||
|
||||
// remove the entry from the playlist
|
||||
_plist.remove(entry);
|
||||
|
||||
// fire up a task to talk to the music daemon
|
||||
final int songid = entry.song.songid;
|
||||
TaskMaster.invokeTask("noop", new TaskAdapter() {
|
||||
public Object invoke () throws Exception {
|
||||
Chooser.scontrol.remove(songid);
|
||||
return null;
|
||||
}
|
||||
}, this);
|
||||
|
||||
} else if (cmd.equals("remove_all")) {
|
||||
JButton src = (JButton)e.getSource();
|
||||
PlaylistEntry entry =
|
||||
(PlaylistEntry)src.getClientProperty("entry");
|
||||
|
||||
// remove all entries starting with this one until we get to
|
||||
// one that has a different entryid
|
||||
int count = 0;
|
||||
Iterator iter = _plist.iterator();
|
||||
while (iter.hasNext()) {
|
||||
PlaylistEntry pe = (PlaylistEntry)iter.next();
|
||||
if (entry == pe) {
|
||||
count++;
|
||||
// remove the entry UI elements
|
||||
JPanel epanel = (JPanel)pe.label.getParent();
|
||||
epanel.getParent().remove(epanel);
|
||||
// remove the entry
|
||||
iter.remove();
|
||||
|
||||
} else if (count > 0) {
|
||||
if (pe.entry.entryid == entry.entry.entryid) {
|
||||
count++;
|
||||
// remove the entry UI elements
|
||||
JPanel epanel = (JPanel)pe.label.getParent();
|
||||
epanel.getParent().remove(epanel);
|
||||
// remove the entry
|
||||
iter.remove();
|
||||
|
||||
} else {
|
||||
// we hit an entry that doesn't match, bail
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove the title and stuff
|
||||
JPanel tpanel = (JPanel)src.getParent();
|
||||
tpanel.getParent().remove(tpanel);
|
||||
|
||||
revalidate(); // relayout
|
||||
|
||||
// fire up a task to talk to the music daemon, telling it to
|
||||
// remove those entries
|
||||
final int songid = entry.song.songid;
|
||||
final int fcount = count;
|
||||
TaskMaster.invokeTask("noop", new TaskAdapter() {
|
||||
public Object invoke () throws Exception {
|
||||
Chooser.scontrol.removeGroup(songid, fcount);
|
||||
return null;
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
super.addNotify();
|
||||
// load up the playlist
|
||||
_controller.postAction(this, REFRESH);
|
||||
}
|
||||
|
||||
protected void refreshPlaylist ()
|
||||
// documentation inherited
|
||||
protected Controller createController ()
|
||||
{
|
||||
return new PlaylistController(this);
|
||||
}
|
||||
|
||||
protected void prepareForRefresh ()
|
||||
{
|
||||
// stick a "loading" label in the list to let the user know
|
||||
// what's up
|
||||
@@ -179,65 +107,9 @@ public class PlaylistPanel extends JPanel
|
||||
// swing doesn't automatically validate after adding/removing
|
||||
// children
|
||||
_bpanel.revalidate();
|
||||
|
||||
// start up the task that reads the CD info from the database
|
||||
TaskMaster.invokeMethodTask("readPlaylist", this, this);
|
||||
}
|
||||
|
||||
public void readPlaylist ()
|
||||
throws PersistenceException
|
||||
{
|
||||
// clear out any previous playlist
|
||||
_plist.clear();
|
||||
|
||||
// get the playlist from the music daemon
|
||||
String[] plist = Chooser.scontrol.getPlaylist();
|
||||
|
||||
// parse it into playlist entries
|
||||
for (int i = 0; i < plist.length; i++) {
|
||||
String[] toks = StringUtil.split(plist[i], "\t");
|
||||
int eid, sid;
|
||||
try {
|
||||
eid = Integer.parseInt(toks[0]);
|
||||
sid = Integer.parseInt(toks[1]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
Log.warning("Bogus playlist record: '" + plist[i] + "'.");
|
||||
continue;
|
||||
}
|
||||
Entry entry = Chooser.model.getEntry(eid);
|
||||
if (entry != null) {
|
||||
Song song = entry.getSong(sid);
|
||||
_plist.add(new PlaylistEntry(entry, song));
|
||||
} else {
|
||||
Log.warning("Unable to load entry [eid=" + eid + "].");
|
||||
}
|
||||
}
|
||||
|
||||
// now find out what's currently playing
|
||||
Chooser.scontrol.refreshPlaying();
|
||||
}
|
||||
|
||||
public void taskCompleted (String name, Object result)
|
||||
{
|
||||
if (name.equals("readPlaylist")) {
|
||||
populatePlaylist();
|
||||
}
|
||||
}
|
||||
|
||||
public void taskFailed (String name, Throwable exception)
|
||||
{
|
||||
String msg;
|
||||
if (Exception.class.equals(exception.getClass())) {
|
||||
msg = exception.getMessage();
|
||||
} else {
|
||||
msg = exception.toString();
|
||||
}
|
||||
JOptionPane.showMessageDialog(this, msg, "Error",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
Log.logStackTrace(exception);
|
||||
}
|
||||
|
||||
protected void populatePlaylist ()
|
||||
protected void populatePlaylist (ArrayList plist, int playid)
|
||||
{
|
||||
// clear out any existing children
|
||||
_bpanel.removeAll();
|
||||
@@ -249,8 +121,8 @@ public class PlaylistPanel extends JPanel
|
||||
|
||||
// add buttons for every entry
|
||||
String title = null;
|
||||
for (int i = 0; i < _plist.size(); i++) {
|
||||
PlaylistEntry entry = (PlaylistEntry)_plist.get(i);
|
||||
for (int i = 0; i < plist.size(); i++) {
|
||||
PlaylistEntry entry = (PlaylistEntry)plist.get(i);
|
||||
JButton button;
|
||||
|
||||
// add record/artist indicators when the record and artist
|
||||
@@ -266,41 +138,27 @@ public class PlaylistPanel extends JPanel
|
||||
JLabel label = new JLabel(entry.entry.title + " - " +
|
||||
entry.entry.artist);
|
||||
tpanel.add(label);
|
||||
tpanel.add(newButton(REMOVE_ENTRY_TIP, "remove_all",
|
||||
tpanel.add(newButton(REMOVE_ENTRY_TIP, REMOVE_ALL,
|
||||
_removeEntryIcon, entry));
|
||||
|
||||
_bpanel.add(tpanel);
|
||||
}
|
||||
|
||||
// create a browse and a play button
|
||||
JPanel hpanel = new JPanel();
|
||||
gl = new HGroupLayout(GroupLayout.NONE);
|
||||
gl.setOffAxisPolicy(GroupLayout.STRETCH);
|
||||
gl.setJustification(GroupLayout.LEFT);
|
||||
hpanel.setLayout(gl);
|
||||
|
||||
hpanel.add(newButton(SKIPTO_TIP, "skipto", _skiptoIcon, entry));
|
||||
hpanel.add(newButton(REMOVE_SONG_TIP, "remove",
|
||||
_removeSongIcon, entry));
|
||||
|
||||
entry.label = new JLabel(entry.song.title);
|
||||
entry.label.setForeground((entry.song.songid == _playid) ?
|
||||
Color.red : Color.black);
|
||||
entry.label.setFont(_nameFont);
|
||||
entry.label.setToolTipText(entry.song.title);
|
||||
hpanel.add(entry.label);
|
||||
// create a song item to display this playlist entry
|
||||
entry.item = new SongItem(entry.song, SongItem.PLAYLIST);
|
||||
entry.item.setIsPlaying(entry.song.songid == playid);
|
||||
entry.item.extra = entry;
|
||||
_bpanel.add(entry.item);
|
||||
|
||||
// let the bpanel know that we want to scroll the active track
|
||||
// label into place once we're all laid out
|
||||
if (entry.song.songid == _playid) {
|
||||
_bpanel.setScrollTarget(hpanel);
|
||||
if (entry.song.songid == playid) {
|
||||
_bpanel.setScrollTarget(entry.item);
|
||||
}
|
||||
|
||||
_bpanel.add(hpanel);
|
||||
}
|
||||
|
||||
// if there were no entries, stick a label in to that effect
|
||||
if (_plist.size() == 0) {
|
||||
if (plist.size() == 0) {
|
||||
_bpanel.add(new JLabel("Nothing playing."));
|
||||
}
|
||||
|
||||
@@ -313,59 +171,11 @@ public class PlaylistPanel extends JPanel
|
||||
ImageIcon icon, Object clientProperty)
|
||||
{
|
||||
JButton button = ButtonUtil.createControlButton(
|
||||
tooltip, command, icon, this, true);
|
||||
tooltip, command, icon, true);
|
||||
button.putClientProperty("entry", clientProperty);
|
||||
return button;
|
||||
}
|
||||
|
||||
public void playingUpdated (int songid, boolean paused)
|
||||
{
|
||||
// unhighlight whoever is playing now
|
||||
PlaylistEntry pentry = getPlayingEntry();
|
||||
if (pentry != null && pentry.label != null) {
|
||||
pentry.label.setForeground(Color.black);
|
||||
}
|
||||
|
||||
// grab the new playing song id
|
||||
_playid = songid;
|
||||
|
||||
// highlight the playing song
|
||||
for (int i = 0; i < _plist.size(); i++) {
|
||||
PlaylistEntry entry = (PlaylistEntry)_plist.get(i);
|
||||
if (entry.song.songid == _playid &&
|
||||
entry.label != null) {
|
||||
entry.label.setForeground(Color.red);
|
||||
}
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
protected PlaylistEntry getPlayingEntry ()
|
||||
{
|
||||
for (int i = 0; i < _plist.size(); i++) {
|
||||
PlaylistEntry entry = (PlaylistEntry)_plist.get(i);
|
||||
if (entry.song.songid == _playid) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static class PlaylistEntry
|
||||
{
|
||||
public Entry entry;
|
||||
|
||||
public Song song;
|
||||
|
||||
public JLabel label;
|
||||
|
||||
public PlaylistEntry (Entry entry, Song song)
|
||||
{
|
||||
this.entry = entry;
|
||||
this.song = song;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A panel that can be made to scroll a particular child into view
|
||||
* when it becomes visible.
|
||||
@@ -402,10 +212,6 @@ public class PlaylistPanel extends JPanel
|
||||
protected SmartPanel _bpanel;
|
||||
protected JButton _clearbut;
|
||||
|
||||
protected ArrayList _plist = new ArrayList();
|
||||
protected int _playid;
|
||||
protected int _oldid = -1;
|
||||
|
||||
protected Font _nameFont;
|
||||
|
||||
protected ImageIcon _skiptoIcon;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
//
|
||||
// $Id: QueryEntryList.java,v 1.1 2002/02/22 07:06:33 mdb Exp $
|
||||
// $Id: QueryEntryList.java,v 1.2 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.swing.Controller;
|
||||
|
||||
import robodj.repository.Entry;
|
||||
|
||||
@@ -17,16 +18,17 @@ public class QueryEntryList extends EntryList
|
||||
_query = query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in the entries for this query.
|
||||
*/
|
||||
public Entry[] readEntries ()
|
||||
throws PersistenceException
|
||||
// documentation inherited
|
||||
protected Controller createController ()
|
||||
{
|
||||
if (_entries == null) {
|
||||
_entries = Chooser.repository.matchEntries(_query);
|
||||
}
|
||||
return _entries;
|
||||
return new EntryController(this) {
|
||||
public Entry[] readEntries () throws PersistenceException {
|
||||
if (_entries == null) {
|
||||
_entries = Chooser.repository.matchEntries(_query);
|
||||
}
|
||||
return _entries;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected String getEmptyString ()
|
||||
@@ -36,7 +38,4 @@ public class QueryEntryList extends EntryList
|
||||
|
||||
/** 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,166 @@
|
||||
//
|
||||
// $Id: SongItem.java,v 1.1 2003/05/04 18:16:06 mdb Exp $
|
||||
|
||||
package robodj.chooser;
|
||||
|
||||
import java.awt.Color;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
|
||||
import com.samskivert.swing.HGroupLayout;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import robodj.repository.Song;
|
||||
import robodj.util.ButtonUtil;
|
||||
|
||||
/**
|
||||
* Displays a particular song (used by the playlist and the entry list).
|
||||
*/
|
||||
public class SongItem extends Item
|
||||
{
|
||||
/** Configures this song item for playlist mode. */
|
||||
public static final int PLAYLIST = 0;
|
||||
|
||||
/** Configures this song item for browser mode. */
|
||||
public static final int BROWSER = 1;
|
||||
|
||||
// playlist mode actions
|
||||
public static final String SKIP_TO = "song:skip_to";
|
||||
public static final String REMOVE = "song:remove";
|
||||
|
||||
// browser mode actions
|
||||
public static final String PLAY = "song:play";
|
||||
|
||||
// ubiquitous actions
|
||||
public static final String ADD_VOTE = "song:add_vote";
|
||||
public static final String CLEAR_VOTE = "song:clear_vote";
|
||||
|
||||
/** Used depending on where this song is being displayed. */
|
||||
public Object extra;
|
||||
|
||||
/**
|
||||
* Creates a song item configured with the supplied song and specified
|
||||
* mode.
|
||||
*/
|
||||
public SongItem (Song song, int mode)
|
||||
{
|
||||
_song = song;
|
||||
|
||||
// configure our layout manager
|
||||
HGroupLayout gl = new HGroupLayout(HGroupLayout.NONE);
|
||||
gl.setJustification(HGroupLayout.LEFT);
|
||||
setLayout(gl);
|
||||
|
||||
// create our control buttons
|
||||
JButton button;
|
||||
switch (mode) {
|
||||
case PLAYLIST:
|
||||
// add a button for skipping to this song
|
||||
button = ButtonUtil.createControlButton(
|
||||
SKIP_TO_TIP, SKIP_TO, _skipToIcon, true);
|
||||
button.putClientProperty("song", _song);
|
||||
add(button, HGroupLayout.FIXED);
|
||||
|
||||
// add a button for removing this song
|
||||
button = ButtonUtil.createControlButton(
|
||||
REMOVE_TIP, REMOVE, _removeIcon, true);
|
||||
button.putClientProperty("song", _song);
|
||||
add(button, HGroupLayout.FIXED);
|
||||
|
||||
break;
|
||||
|
||||
case BROWSER:
|
||||
// add a button for playing the song
|
||||
button = ButtonUtil.createControlButton(
|
||||
PLAY_SONG_TIP, PLAY, _playIcon, true);
|
||||
button.putClientProperty(SONG_PROP, _song);
|
||||
add(button, HGroupLayout.FIXED);
|
||||
break;
|
||||
|
||||
default:
|
||||
System.err.println("Unknown song mode: " + mode);
|
||||
break;
|
||||
}
|
||||
|
||||
// add a vote button
|
||||
_voteButton = ButtonUtil.createControlButton(
|
||||
ADD_VOTE_TIP, ADD_VOTE, _addVoteIcon, true);
|
||||
_voteButton.putClientProperty(SONG_PROP, song);
|
||||
add(_voteButton, HGroupLayout.FIXED);
|
||||
|
||||
// add the song title
|
||||
_trackLabel = new JLabel(_song.title);
|
||||
add(_trackLabel);
|
||||
|
||||
// update our display based on our votes
|
||||
update();
|
||||
}
|
||||
|
||||
public void setIsPlaying (boolean isPlaying)
|
||||
{
|
||||
_trackLabel.setForeground(isPlaying ? Color.red : Color.black);
|
||||
}
|
||||
|
||||
public void update ()
|
||||
{
|
||||
if (!StringUtil.blank(_song.votes)) {
|
||||
_trackLabel.setFont(_hasVotesFont);
|
||||
_trackLabel.setToolTipText("<html>" + _song.title +
|
||||
"<br>Votes: " + _song.votes);
|
||||
} else {
|
||||
_trackLabel.setFont(_nameFont);
|
||||
_trackLabel.setToolTipText(_song.title);
|
||||
}
|
||||
|
||||
if (_song.hasVoted(Chooser.frame.getUser(false))) {
|
||||
_voteButton.setIcon(_clearVoteIcon);
|
||||
_voteButton.setActionCommand(CLEAR_VOTE);
|
||||
_voteButton.setToolTipText(CLEAR_VOTE_TIP);
|
||||
} else {
|
||||
_voteButton.setIcon(_addVoteIcon);
|
||||
_voteButton.setActionCommand(ADD_VOTE);
|
||||
_voteButton.setToolTipText(ADD_VOTE_TIP);
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
public Song getSong ()
|
||||
{
|
||||
return _song;
|
||||
}
|
||||
|
||||
public static Song getSong (Object source)
|
||||
{
|
||||
return (Song)((JButton)source).getClientProperty(SONG_PROP);
|
||||
}
|
||||
|
||||
protected Song _song;
|
||||
protected JButton _voteButton;
|
||||
protected JLabel _trackLabel;
|
||||
|
||||
protected static final String SONG_PROP = "song";
|
||||
|
||||
protected static final String SKIP_TO_TIP =
|
||||
"Skip to this song";
|
||||
protected static final String REMOVE_TIP =
|
||||
"Remove this song from the playlist";
|
||||
|
||||
protected static final String PLAY_SONG_TIP =
|
||||
"Append this song to the playlist";
|
||||
|
||||
protected static final String ADD_VOTE_TIP =
|
||||
"Add your vote for this song";
|
||||
protected static final String CLEAR_VOTE_TIP =
|
||||
"Remove your vote for this song";
|
||||
|
||||
protected static ImageIcon _skipToIcon =
|
||||
ButtonUtil.getIcon(ICON_ROOT + "skip.png");
|
||||
protected static ImageIcon _removeIcon =
|
||||
ButtonUtil.getIcon(ICON_ROOT + "remove_song.png");
|
||||
|
||||
protected static ImageIcon _addVoteIcon =
|
||||
ButtonUtil.getIcon(ICON_ROOT + "add_vote.png");
|
||||
protected static ImageIcon _clearVoteIcon =
|
||||
ButtonUtil.getIcon(ICON_ROOT + "clear_vote.png");
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 792 B |
Binary file not shown.
|
After Width: | Height: | Size: 797 B |
@@ -0,0 +1,33 @@
|
||||
#
|
||||
# $Id: config.properties,v 1.1 2003/05/04 18:16:06 mdb Exp $
|
||||
#
|
||||
# Default RoboDJ configuration properties
|
||||
|
||||
#
|
||||
# The directory in which RoboDJ will store its ripped music
|
||||
|
||||
# repository.basedir = /export/robodj/repository
|
||||
|
||||
#
|
||||
# The directory in which the importer will store temp files while ripping
|
||||
|
||||
# repository.tmpdir = /export/robodj/tmp
|
||||
|
||||
#
|
||||
# The JDBC configuration for accessing the music database
|
||||
|
||||
jdbc.default.driver = org.gjt.mm.mysql.Driver
|
||||
jdbc.default.username = _USERNAME_
|
||||
jdbc.default.password = _PASSWORD_
|
||||
jdbc.default.url = jdbc:mysql://_DBHOST_:3306/_DBNAME_
|
||||
|
||||
#
|
||||
# The CDDB host to which to connect
|
||||
|
||||
cddb.host = freedb.freedb.org
|
||||
|
||||
#
|
||||
# The music server host and port information
|
||||
|
||||
# musicd.host = hostname
|
||||
musicd.port = 2500
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: CDDBLookupPanel.java,v 1.6 2002/11/11 17:05:20 mdb Exp $
|
||||
// $Id: CDDBLookupPanel.java,v 1.7 2003/05/04 18:16:07 mdb Exp $
|
||||
|
||||
package robodj.importer;
|
||||
|
||||
@@ -171,6 +171,7 @@ public class CDDBLookupPanel
|
||||
Song song = (entry.songs[i] = new Song());
|
||||
song.title = names[i];
|
||||
song.position = i+1;
|
||||
song.votes = "";
|
||||
}
|
||||
|
||||
// create the rip panel and pass the entry and info along
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: RipPanel.java,v 1.8 2002/11/11 17:05:37 mdb Exp $
|
||||
// $Id: RipPanel.java,v 1.9 2003/05/04 18:16:07 mdb Exp $
|
||||
|
||||
package robodj.importer;
|
||||
|
||||
@@ -430,8 +430,8 @@ public class RipPanel
|
||||
protected Entry _entry;
|
||||
|
||||
protected static final String DB_FAILURE_MSG =
|
||||
"An error occurred while communicating with the database. You " +
|
||||
"may wish to examine the following error message, remedy the " +
|
||||
"problem with the database and retry the operation. Or you can " +
|
||||
"An error occurred while communicating with the database.\n" +
|
||||
"You may wish to examine the following error message, remedy the\n" +
|
||||
"problem with the database and retry the operation. Or you can\n" +
|
||||
"abort the operation and cancel the import process entirely.";
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
//
|
||||
// $Id: Song.java,v 1.1 2000/11/08 06:42:57 mdb Exp $
|
||||
// $Id: Song.java,v 1.2 2003/05/04 18:16:07 mdb Exp $
|
||||
|
||||
package robodj.repository;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
/**
|
||||
* A song maps approximately to an individual piece of music. In most
|
||||
* cases repository entries are created from albums which contain some
|
||||
@@ -38,10 +40,103 @@ public class Song
|
||||
*/
|
||||
public int duration;
|
||||
|
||||
/** A comma separated list of the "users" that have voted for this
|
||||
* song where "users" is the short string (initials) provided by a
|
||||
* client when voting for a song. */
|
||||
public String votes;
|
||||
|
||||
/**
|
||||
* Adds a voter to the votes string for this entry, not including a
|
||||
* voter that already exists in the voter set.
|
||||
*
|
||||
* @return true if the voter set was changed as a result of this
|
||||
* addition, false if not.
|
||||
*/
|
||||
public boolean addVote (String voter)
|
||||
{
|
||||
// handle our first vote separately
|
||||
if (StringUtil.blank(votes)) {
|
||||
votes = voter;
|
||||
_votes = null; // clear our cached votes
|
||||
return true;
|
||||
}
|
||||
|
||||
// make sure this voter has not already cast their ballot
|
||||
if (hasVoted(voter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
votes = (votes + "," + voter);
|
||||
_votes = null; // clear our cached votes
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a voter from the votes string for this song.
|
||||
*
|
||||
* @return true if the voter set was changed as a result of this
|
||||
* addition, false if not.
|
||||
*/
|
||||
public boolean clearVote (String voter)
|
||||
{
|
||||
String[] votes = getVotes();
|
||||
StringBuffer nvotes = new StringBuffer();
|
||||
boolean saw = false;
|
||||
for (int ii = 0; ii < votes.length; ii++) {
|
||||
if (votes[ii].equalsIgnoreCase(voter)) {
|
||||
saw = true;
|
||||
} else {
|
||||
if (nvotes.length() > 0) {
|
||||
nvotes.append(",");
|
||||
}
|
||||
nvotes.append(votes[ii]);
|
||||
}
|
||||
}
|
||||
if (saw) {
|
||||
this.votes = nvotes.toString();
|
||||
_votes = null;
|
||||
}
|
||||
return saw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link #votes} field broken up into an array of strings
|
||||
* with one for each "vote".
|
||||
*/
|
||||
public String[] getVotes ()
|
||||
{
|
||||
if (_votes == null) {
|
||||
if (StringUtil.blank(votes)) {
|
||||
_votes = new String[0];
|
||||
} else {
|
||||
_votes = StringUtil.split(votes, ",");
|
||||
}
|
||||
}
|
||||
return _votes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified user has voted.
|
||||
*/
|
||||
public boolean hasVoted (String voter)
|
||||
{
|
||||
String[] votes = getVotes();
|
||||
for (int ii = 0; ii < votes.length; ii++) {
|
||||
if (votes[ii].equalsIgnoreCase(voter)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this instance.
|
||||
*/
|
||||
public String toString ()
|
||||
{
|
||||
return "[songid=" + songid + ", entryid=" + entryid +
|
||||
", position=" + position + ", title=" + title +
|
||||
", location=" + location + ", duration=" + duration + "]";
|
||||
return StringUtil.fieldsToString(this);
|
||||
}
|
||||
|
||||
/** The decoded voter array for this song. */
|
||||
protected transient String[] _votes;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
//
|
||||
// $Id: ButtonUtil.java,v 1.1 2002/03/03 20:56:12 mdb Exp $
|
||||
// $Id: ButtonUtil.java,v 1.2 2003/05/04 18:16:07 mdb Exp $
|
||||
|
||||
package robodj.util;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -15,6 +14,8 @@ import javax.swing.BorderFactory;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
|
||||
import com.samskivert.swing.Controller;
|
||||
|
||||
import robodj.Log;
|
||||
|
||||
/**
|
||||
@@ -43,32 +44,30 @@ public class ButtonUtil
|
||||
}
|
||||
|
||||
public static JButton createControlButton (
|
||||
String tooltip, String action, String iconPath, ActionListener al)
|
||||
String tooltip, String action, String iconPath)
|
||||
{
|
||||
return createControlButton(tooltip, action, iconPath, al, false);
|
||||
return createControlButton(tooltip, action, iconPath, false);
|
||||
}
|
||||
|
||||
public static JButton createControlButton (
|
||||
String tooltip, String action, String iconPath,
|
||||
ActionListener al, boolean borderless)
|
||||
String tooltip, String action, String iconPath, boolean borderless)
|
||||
{
|
||||
return createControlButton(
|
||||
tooltip, action, getIcon(iconPath), al, borderless);
|
||||
tooltip, action, getIcon(iconPath), borderless);
|
||||
}
|
||||
|
||||
public static JButton createControlButton (
|
||||
String tooltip, String action, ImageIcon icon, ActionListener al)
|
||||
String tooltip, String action, ImageIcon icon)
|
||||
{
|
||||
return createControlButton(tooltip, action, icon, al, false);
|
||||
return createControlButton(tooltip, action, icon, false);
|
||||
}
|
||||
|
||||
public static JButton createControlButton (
|
||||
String tooltip, String action, ImageIcon icon,
|
||||
ActionListener al, boolean borderless)
|
||||
String tooltip, String action, ImageIcon icon, boolean borderless)
|
||||
{
|
||||
JButton cbut = new JButton(icon);
|
||||
cbut.setActionCommand(action);
|
||||
cbut.addActionListener(al);
|
||||
cbut.addActionListener(Controller.DISPATCHER);
|
||||
cbut.setToolTipText(tooltip);
|
||||
// clear out that annoying fat border that swing uses
|
||||
cbut.setBorder(borderless ? BorderFactory.createEmptyBorder() :
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// $Id: RDJPrefs.java,v 1.1 2003/05/04 18:16:07 mdb Exp $
|
||||
|
||||
package robodj.util;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import com.samskivert.util.Config;
|
||||
|
||||
/**
|
||||
* Contains settings and preferences for this RoboDJ installation.
|
||||
*/
|
||||
public class RDJPrefs
|
||||
{
|
||||
/** Configuration key for {@link #getRepositoryDirectory}. */
|
||||
public static final String REPO_DIR_KEY = "repository.basedir";
|
||||
|
||||
/** Configuration key for {@link #getJDBCConfig}. */
|
||||
public static final String JDBC_DRIVER_KEY = "jdbc.default.driver";
|
||||
|
||||
/** Configuration key for {@link #getJDBCConfig}. */
|
||||
public static final String JDBC_USERNAME_KEY = "jdbc.default.username";
|
||||
|
||||
/** Configuration key for {@link #getJDBCConfig}. */
|
||||
public static final String JDBC_PASSWORD_KEY = "jdbc.default.password";
|
||||
|
||||
/** Configuration key for {@link #getJDBCConfig}. */
|
||||
public static final String JDBC_URL_KEY = "jdbc.default.url";
|
||||
|
||||
/** Configuration key for {@link #getMusicDaemonHost}. */
|
||||
public static final String MUSICD_HOST_KEY = "musicd.host";
|
||||
|
||||
/** Configuration key for {@link #getMusicDaemonPort}. */
|
||||
public static final String MUSICD_PORT_KEY = "musicd.port";
|
||||
|
||||
/** Configuration key for {@link #getCDDBHost}. */
|
||||
public static final String CDDB_HOST_KEY = "cddb.host";
|
||||
|
||||
/** Configuration key for {@link #getUser}. */
|
||||
public static final String USER_KEY = "user";
|
||||
|
||||
/** Provides access to configuration data. */
|
||||
public static Config config = new Config("robodj/config");
|
||||
|
||||
/**
|
||||
* Returns the repository directory name.
|
||||
*/
|
||||
public static String getRepositoryDirectory ()
|
||||
{
|
||||
return config.getValue(REPO_DIR_KEY, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JDBC configuration for this RoboDJ installation.
|
||||
*/
|
||||
public static Properties getJDBCConfig ()
|
||||
{
|
||||
return config.getSubProperties("jdbc");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the host by which we connect to the music daemon.
|
||||
*/
|
||||
public static String getMusicDaemonHost ()
|
||||
{
|
||||
return config.getValue(MUSICD_HOST_KEY, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port by which we connect to the music daemon.
|
||||
*/
|
||||
public static int getMusicDaemonPort ()
|
||||
{
|
||||
return config.getValue(MUSICD_PORT_KEY, 2500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hostname of the CDDB server we use to look up album and
|
||||
* track names.
|
||||
*/
|
||||
public static String getCDDBHost ()
|
||||
{
|
||||
return config.getValue(CDDB_HOST_KEY, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns our locally configured username.
|
||||
*/
|
||||
public static String getUser ()
|
||||
{
|
||||
return config.getValue(USER_KEY, "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
//
|
||||
// $Id: RDJPrefsPanel.java,v 1.1 2003/05/04 18:16:07 mdb Exp $
|
||||
|
||||
package robodj.util;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import com.samskivert.swing.Spacer;
|
||||
import com.samskivert.swing.util.SwingUtil;
|
||||
|
||||
/**
|
||||
* Displays an interface for editing our RoboDJ preferences.
|
||||
*/
|
||||
public class RDJPrefsPanel extends JPanel
|
||||
{
|
||||
/**
|
||||
* Displays a frame containing a panel for editing our preferences.
|
||||
*
|
||||
* @param blockCaller if true the caller will be blocked until the
|
||||
* user dismisses the preferences panel.
|
||||
*/
|
||||
public static void display (boolean blockCaller)
|
||||
{
|
||||
JFrame frame = new JFrame("RoboDJ Configuration");
|
||||
RDJPrefsPanel panel = new RDJPrefsPanel(frame);
|
||||
frame.setContentPane(panel);
|
||||
frame.pack();
|
||||
SwingUtil.centerWindow(frame);
|
||||
frame.show();
|
||||
|
||||
if (blockCaller) {
|
||||
panel.awaitDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
protected RDJPrefsPanel (JFrame frame)
|
||||
{
|
||||
super(new GridBagLayout());
|
||||
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||
|
||||
_frame = frame;
|
||||
_frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||
_frame.addWindowListener(new WindowAdapter() {
|
||||
public void windowClosed (WindowEvent event) {
|
||||
dismissed();
|
||||
}
|
||||
});
|
||||
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.anchor = GridBagConstraints.WEST;
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.weighty = 1;
|
||||
|
||||
c.gridwidth = GridBagConstraints.REMAINDER;
|
||||
JLabel title = new JLabel("RoboDJ Preferences");
|
||||
title.setHorizontalAlignment(JLabel.CENTER);
|
||||
title.setFont(title.getFont().deriveFont(16f));
|
||||
add(title, c);
|
||||
add(new Spacer(10, 10), c);
|
||||
|
||||
for (int ii = 0; ii < PREFS.length; ii += 2) {
|
||||
if (PREFS[ii].equals("")) {
|
||||
c.gridwidth = GridBagConstraints.REMAINDER;
|
||||
add(new Spacer(10, 10), c);
|
||||
|
||||
} else {
|
||||
JLabel label = new JLabel(PREFS[ii]);
|
||||
c.gridwidth = GridBagConstraints.RELATIVE;
|
||||
c.ipadx = 5;
|
||||
c.ipady = 8;
|
||||
c.weightx = 1;
|
||||
add(label, c);
|
||||
|
||||
JTextField value = new JTextField(
|
||||
RDJPrefs.config.getValue(PREFS[ii+1], "")) {
|
||||
public Dimension getPreferredSize () {
|
||||
Dimension d = super.getPreferredSize();
|
||||
d.width = Math.min(250, d.width);
|
||||
return d;
|
||||
}
|
||||
};
|
||||
PrefListener plist = new PrefListener(value, PREFS[ii+1]);
|
||||
value.addFocusListener(plist);
|
||||
value.addActionListener(plist);
|
||||
c.ipadx = 0;
|
||||
c.ipady = 2;
|
||||
c.weightx = 2;
|
||||
c.gridwidth = GridBagConstraints.REMAINDER;
|
||||
add(value, c);
|
||||
}
|
||||
}
|
||||
|
||||
// add a dismiss button
|
||||
JButton dismiss = new JButton("Dismiss");
|
||||
dismiss.addActionListener(new ActionListener() {
|
||||
public void actionPerformed (ActionEvent event) {
|
||||
_frame.dispose();
|
||||
}
|
||||
});
|
||||
c.fill = GridBagConstraints.NONE;
|
||||
c.anchor = GridBagConstraints.EAST;
|
||||
c.ipadx = c.ipady = 0;
|
||||
add(new Spacer(10, 10), c);
|
||||
add(dismiss, c);
|
||||
}
|
||||
|
||||
protected synchronized void awaitDismiss ()
|
||||
{
|
||||
while (_frame.isShowing()) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void dismissed ()
|
||||
{
|
||||
notify();
|
||||
}
|
||||
|
||||
protected static class PrefListener
|
||||
implements ActionListener, FocusListener
|
||||
{
|
||||
public PrefListener (JTextField text, String prefKey)
|
||||
{
|
||||
_text = text;
|
||||
_prefKey = prefKey;
|
||||
}
|
||||
|
||||
// documentation inherited from interface FocusListener
|
||||
public void focusGained (FocusEvent e)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
// documentation inherited from interface FocusListener
|
||||
public void focusLost (FocusEvent e)
|
||||
{
|
||||
actionPerformed(new ActionEvent(_text, 0, "focusLost"));
|
||||
}
|
||||
|
||||
// documentation inherited from interface ActionListener
|
||||
public void actionPerformed (ActionEvent e)
|
||||
{
|
||||
RDJPrefs.config.setValue(_prefKey, _text.getText());
|
||||
System.out.println("Updated " + _prefKey + " -> " +
|
||||
_text.getText());
|
||||
}
|
||||
|
||||
protected JTextField _text;
|
||||
protected String _prefKey;
|
||||
}
|
||||
|
||||
protected JFrame _frame;
|
||||
|
||||
/** Defines our configurable preferences. */
|
||||
protected static final String[] PREFS = {
|
||||
"Music repository directory", RDJPrefs.REPO_DIR_KEY,
|
||||
"", "",
|
||||
"Music database JDBC driver", RDJPrefs.JDBC_DRIVER_KEY,
|
||||
"Music database JDBC url", RDJPrefs.JDBC_URL_KEY,
|
||||
"Music database JDBC username", RDJPrefs.JDBC_USERNAME_KEY,
|
||||
"Music database JDBC password", RDJPrefs.JDBC_PASSWORD_KEY,
|
||||
"", "",
|
||||
"Music server hostname", RDJPrefs.MUSICD_HOST_KEY,
|
||||
"Music server port", RDJPrefs.MUSICD_PORT_KEY,
|
||||
"", "",
|
||||
"CDDB server hostname", RDJPrefs.CDDB_HOST_KEY,
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* $Id: create_repository.mysql,v 1.1 2000/12/10 07:00:47 mdb Exp $
|
||||
* $Id: create_repository.mysql,v 1.2 2003/05/04 18:16:07 mdb Exp $
|
||||
*
|
||||
* Creates the necessary database tables in MySQL for the music repository.
|
||||
*/
|
||||
@@ -27,6 +27,7 @@ CREATE TABLE songs (
|
||||
title VARCHAR(200) NOT NULL,
|
||||
location VARCHAR(200) NOT NULL,
|
||||
duration INTEGER(10) NOT NULL,
|
||||
votes VARCHAR(255) NOT NULL,
|
||||
|
||||
CONSTRAINT fk_songs_entries FOREIGN KEY (entryid)
|
||||
REFERENCES entries (entryid) ON DELETE CASCADE
|
||||
|
||||
Reference in New Issue
Block a user