All sorts of good new stuff including category support.

git-svn-id: https://samskivert.googlecode.com/svn/trunk@149 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2001-06-07 08:37:47 +00:00
parent d827c97809
commit 567f808c4c
8 changed files with 476 additions and 37 deletions
@@ -1,5 +1,5 @@
// //
// $Id: Chooser.java,v 1.1 2001/06/05 16:42:38 mdb Exp $ // $Id: Chooser.java,v 1.2 2001/06/07 08:37:47 mdb Exp $
package robodj.chooser; package robodj.chooser;
@@ -12,6 +12,7 @@ import java.util.Properties;
import com.samskivert.util.PropertiesUtil; import com.samskivert.util.PropertiesUtil;
import robodj.Log; import robodj.Log;
import robodj.repository.Model;
import robodj.repository.Repository; import robodj.repository.Repository;
import robodj.util.ServerControl; import robodj.util.ServerControl;
@@ -25,6 +26,8 @@ public class Chooser
public static Repository repository; public static Repository repository;
public static Model model;
public static ServerControl scontrol; public static ServerControl scontrol;
public static void main (String[] args) public static void main (String[] args)
@@ -43,6 +46,8 @@ public class Chooser
Properties dbprops = Properties dbprops =
PropertiesUtil.getSubProperties(config, "repository.db"); PropertiesUtil.getSubProperties(config, "repository.db");
repository = new Repository(dbprops); repository = new Repository(dbprops);
model = new Model(repository);
} catch (SQLException sqe) { } catch (SQLException sqe) {
Log.warning("Unable to establish communication with music " + Log.warning("Unable to establish communication with music " +
"database: " + sqe); "database: " + sqe);
@@ -1,5 +1,5 @@
// //
// $Id: ChooserFrame.java,v 1.1 2001/06/05 16:42:38 mdb Exp $ // $Id: ChooserFrame.java,v 1.2 2001/06/07 08:37:47 mdb Exp $
package robodj.chooser; package robodj.chooser;
@@ -9,6 +9,7 @@ import java.awt.event.ActionListener;
import javax.swing.*; import javax.swing.*;
import com.samskivert.swing.*; import com.samskivert.swing.*;
import robodj.repository.*;
public class ChooserFrame public class ChooserFrame
extends JFrame extends JFrame
@@ -29,8 +30,21 @@ public class ChooserFrame
// the top of the UI is the playlist manager section // the top of the UI is the playlist manager section
JTabbedPane tpane = new JTabbedPane(); JTabbedPane tpane = new JTabbedPane();
Component elist = new EntryList(); EntryList elist;
tpane.addTab("Browse", null, elist, "Browse music database."); Category[] cats = Chooser.model.getCategories();
// create a tab for each category
for (int i = 0; i < cats.length; i++) {
elist = new EntryList(cats[i].categoryid);
String tip = "Browse entries in '" + cats[i].name + "' category.";
tpane.addTab(cats[i].name, null, elist, tip);
}
// and add one for uncategorized entries
elist = new EntryList(-1);
tpane.addTab("Uncategorized", null, elist,
"Browse uncategorized entries.");
tpane.setSelectedIndex(0); tpane.setSelectedIndex(0);
top.add(tpane); top.add(tpane);
@@ -1,13 +1,15 @@
// //
// $Id: EntryList.java,v 1.1 2001/06/05 16:42:38 mdb Exp $ // $Id: EntryList.java,v 1.2 2001/06/07 08:37:47 mdb Exp $
package robodj.chooser; package robodj.chooser;
import java.awt.Font;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*; import java.util.*;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.*;
import com.samskivert.swing.*; import com.samskivert.swing.*;
import com.samskivert.swing.util.*; import com.samskivert.swing.util.*;
@@ -17,9 +19,9 @@ import robodj.repository.*;
public class EntryList public class EntryList
extends JPanel extends JPanel
implements TaskObserver, ActionListener implements TaskObserver, ActionListener, AncestorListener
{ {
public EntryList () public EntryList (int categoryid)
{ {
GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH); GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH);
gl.setOffAxisPolicy(GroupLayout.STRETCH); gl.setOffAxisPolicy(GroupLayout.STRETCH);
@@ -27,7 +29,7 @@ public class EntryList
// create the pane that will hold the buttons // create the pane that will hold the buttons
gl = new VGroupLayout(GroupLayout.NONE); gl = new VGroupLayout(GroupLayout.NONE);
gl.setOffAxisPolicy(GroupLayout.EQUALIZE); gl.setJustification(GroupLayout.TOP);
_bpanel = new JPanel(gl); _bpanel = new JPanel(gl);
// give ourselves a wee bit of a border // give ourselves a wee bit of a border
@@ -43,8 +45,15 @@ public class EntryList
_upbut.addActionListener(this); _upbut.addActionListener(this);
add(_upbut, GroupLayout.FIXED); add(_upbut, GroupLayout.FIXED);
// start up the task that reads the CD info from the database // use a special font for our name buttons
TaskMaster.invokeMethodTask("readEntries", this, this); _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);
} }
public void taskCompleted (String name, Object result) public void taskCompleted (String name, Object result)
@@ -84,7 +93,7 @@ public class EntryList
public Entry[] readEntries () public Entry[] readEntries ()
throws SQLException throws SQLException
{ {
return Chooser.repository.getEntries(""); return Chooser.model.getEntries(_catid);
} }
/** /**
@@ -105,6 +114,15 @@ public class EntryList
Chooser.repository.populateSongs(_entry); Chooser.repository.populateSongs(_entry);
} }
/**
* Updates the category for the displayed entry.
*/
public void recategorizeEntry ()
throws SQLException
{
Chooser.model.recategorize(_entry, _newcatid);
}
/** /**
* Creates the proper buttons, etc. for each entry. * Creates the proper buttons, etc. for each entry.
*/ */
@@ -116,6 +134,11 @@ public class EntryList
// clear out any existing children // clear out any existing children
_bpanel.removeAll(); _bpanel.removeAll();
// adjust our layout policy
GroupLayout gl = (GroupLayout)_bpanel.getLayout();
gl.setOffAxisPolicy(GroupLayout.EQUALIZE);
gl.setOffAxisJustification(GroupLayout.LEFT);
// sort our entries // sort our entries
Comparator ecomp = new Comparator() { Comparator ecomp = new Comparator() {
public int compare (Object o1, Object o2) { public int compare (Object o1, Object o2) {
@@ -140,12 +163,18 @@ public class EntryList
// create a browse and a play button // create a browse and a play button
JPanel hpanel = new JPanel(); JPanel hpanel = new JPanel();
GroupLayout gl = new HGroupLayout(GroupLayout.NONE); gl = new HGroupLayout(GroupLayout.NONE);
gl.setOffAxisPolicy(GroupLayout.STRETCH); gl.setOffAxisPolicy(GroupLayout.STRETCH);
gl.setJustification(GroupLayout.LEFT); gl.setJustification(GroupLayout.LEFT);
hpanel.setLayout(gl); hpanel.setLayout(gl);
JButton button; JButton button;
button = new JButton(entries[i].title);
button.setFont(_nameFont);
button.setActionCommand("browse");
button.addActionListener(this);
button.putClientProperty("entry", entries[i]);
hpanel.add(button);
button = new JButton("Play"); button = new JButton("Play");
button.setActionCommand("playall"); button.setActionCommand("playall");
@@ -153,14 +182,13 @@ public class EntryList
button.putClientProperty("entry", entries[i]); button.putClientProperty("entry", entries[i]);
hpanel.add(button); hpanel.add(button);
button = new JButton(entries[i].title);
button.setActionCommand("browse");
button.addActionListener(this);
button.putClientProperty("entry", entries[i]);
hpanel.add(button);
_bpanel.add(hpanel); _bpanel.add(hpanel);
} }
// 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."));
}
} }
protected void populateSong (Entry entry) protected void populateSong (Entry entry)
@@ -171,6 +199,20 @@ public class EntryList
// clear out any existing children // clear out any existing children
_bpanel.removeAll(); _bpanel.removeAll();
// adjust our layout policy
((GroupLayout)_bpanel.getLayout()).setOffAxisPolicy(
GroupLayout.NONE);
// create a combo box for the categories
JComboBox catcombo =
new JComboBox(ModelUtil.catBoxNames(Chooser.model));
catcombo.addActionListener(this);
catcombo.setActionCommand("categorize");
int catid = Chooser.model.getCategory(entry.entryid);
int catidx = ModelUtil.getCategoryIndex(Chooser.model, catid);
catcombo.setSelectedIndex(catidx+1);
_bpanel.add(catcombo);
// add a label for the title // add a label for the title
JLabel label = new JLabel(entry.title); JLabel label = new JLabel(entry.title);
_bpanel.add(label); _bpanel.add(label);
@@ -190,8 +232,10 @@ public class EntryList
// and add buttons for every song // and add buttons for every song
for (int i = 0; i < entry.songs.length; i++) { for (int i = 0; i < entry.songs.length; i++) {
JButton button = new JButton(entry.songs[i].title); JButton button = new JButton(entry.songs[i].title);
button.setFont(_nameFont);
button.setActionCommand("play"); button.setActionCommand("play");
button.addActionListener(this); button.addActionListener(this);
button.setHorizontalAlignment(JButton.LEFT);
button.putClientProperty("song", entry.songs[i]); button.putClientProperty("song", entry.songs[i]);
_bpanel.add(button); _bpanel.add(button);
} }
@@ -218,16 +262,51 @@ public class EntryList
Chooser.scontrol.append(song.location); Chooser.scontrol.append(song.location);
} else if (cmd.equals("up")) { } else if (cmd.equals("up")) {
populateEntries(_entries); // re-read the category beacuse this entry may have been
// recategorized
TaskMaster.invokeMethodTask("readEntries", this, this);
} 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 { } else {
System.out.println("Unknown action event: " + cmd); System.out.println("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..."));
// 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 JPanel _bpanel; protected JPanel _bpanel;
protected JButton _upbut; protected JButton _upbut;
protected int _catid;
protected Entry[] _entries; protected Entry[] _entries;
protected Entry _entry; protected Entry _entry;
protected int _newcatid;
protected Font _nameFont;
} }
@@ -1,5 +1,5 @@
// //
// $Id: FinishedPanel.java,v 1.1 2001/03/21 00:41:03 mdb Exp $ // $Id: FinishedPanel.java,v 1.2 2001/06/07 08:37:47 mdb Exp $
package robodj.importer; package robodj.importer;
@@ -54,6 +54,7 @@ public class FinishedPanel
public void wasAddedToFrame (ImporterFrame frame) public void wasAddedToFrame (ImporterFrame frame)
{ {
frame.addControlButton("Another", "import", this);
frame.addControlButton("Exit", "exit", this); frame.addControlButton("Exit", "exit", this);
// keep a handle on this for later // keep a handle on this for later
@@ -1,5 +1,5 @@
// //
// $Id: Entry.java,v 1.1 2000/11/08 06:42:57 mdb Exp $ // $Id: Entry.java,v 1.2 2001/06/07 08:37:47 mdb Exp $
package robodj.repository; package robodj.repository;
@@ -20,8 +20,8 @@ public class Entry
public String title; public String title;
/** /**
* The artist that created the music for this entry or "Various" if it * The artist that created the music for this entry or "Various
* is not a single-artist work. * Artists" if it is not a single-artist work.
*/ */
public String artist; public String artist;
@@ -0,0 +1,235 @@
//
// $Id: Model.java,v 1.1 2001/06/07 08:37:47 mdb Exp $
package robodj.repository;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import com.samskivert.util.IntMap;
import com.samskivert.util.IntIntMap;
/**
* The model provides an interface to the contents of the repository which
* efficiently accesses the database, caches information and preserves a
* consistent view of the repository in light of modifications made by the
* user (through the model). It is structured so that the client can
* maintain no in-memory state and instead fetch content via the model
* every time it needs to make use of it.
*/
public class Model
{
/**
* Constructs a new model instance from the supplied repository.
*/
public Model (Repository rep)
throws SQLException
{
_rep = rep;
// load up our category information
_cats = _rep.getCategories();
// sort them into alphabetical order
Arrays.sort(_cats, new Comparator() {
public int compare (Object o1, Object o2)
{
return ((Category)o1).name.compareTo(((Category)o2).name);
}
public boolean equals (Object other)
{
return other == this;
}
});
}
/**
* Returns the categories.
*/
public Category[] getCategories ()
{
return _cats;
}
/**
* Looks up the category id of the category with the specified name.
*
* @return category id of the matching category or -1 if no category
* matched.
*/
public int getCategoryId (String catname)
{
for (int i = 0; i < _cats.length; i++) {
if (_cats[i].name.equals(catname)) {
return _cats[i].categoryid;
}
}
return -1;
}
/**
* Returns a reference to the specified entry id. This call blocks
* if database access takes place.
*/
public Entry getEntry (int entryid)
throws SQLException
{
Entry entry = (Entry)_entries.get(entryid);
if (entry == null) {
_entries.put(entryid, entry = _rep.getEntry(entryid));
}
return entry;
}
/**
* Returns an array containing of the entries in the specified
* category. This call blocks if database access takes place.
*/
public Entry[] getEntries (int categoryid)
throws SQLException
{
ArrayList catlist = getCatList(categoryid);
Entry[] ents = new Entry[catlist.size()];
catlist.toArray(ents);
return ents;
}
/**
* Associates the specified entry with the specified category. An
* entry can be mapped into multiple categories.
*/
public void associateEntry (Entry entry, int categoryid)
throws SQLException
{
// keep our category mapping up to date
ArrayList catlist = getCatList(categoryid);
// if the entry's not already in the list, stick it in
if (!catlist.contains(entry)) {
catlist.add(entry);
// update the entry to category map
_entmap.put(entry.entryid, categoryid);
// and update the database
_rep.associateEntry(entry, categoryid);
}
}
/**
* Disassociates the specified entry from the specified category.
*/
public void disassociateEntry (Entry entry, int categoryid)
throws SQLException
{
// keep our category mapping up to date
ArrayList catlist = getCatList(categoryid);
// if the entry's already in the list, take it out
if (catlist.contains(entry)) {
catlist.remove(entry);
// update the entry to category map
_entmap.remove(entry.entryid);
// and update the database
_rep.disassociateEntry(entry, categoryid);
}
}
/**
* Returns the category to which this entry is mapped or -1 if it's
* mapped to no category.
*/
public int getCategory (int entryid)
{
return _entmap.get(entryid);
}
/**
* Removes the entry from whatever category it is currently occupying
* and adds it to the specified category. If the entry is already in
* the specified category, this function does nothing. This is
* temporary until we fully implement multi-category support.
*/
public void recategorize (Entry entry, int categoryid)
throws SQLException
{
// see if we need to change categories
int curcatid = _entmap.get(entry.entryid);
if (curcatid != categoryid) {
disassociateEntry(entry, curcatid);
associateEntry(entry, categoryid);
}
}
/**
* Ensures that the entry's songs array is populated. This call blocks
* if database access takes place.
*/
public void populateSongs (Entry entry)
throws SQLException
{
_rep.populateSongs(entry);
}
protected ArrayList getCatList (int categoryid)
throws SQLException
{
ArrayList catlist = (ArrayList)_catmap.get(categoryid);
if (catlist == null) {
// create a new category list and stick it into the table
catlist = new ArrayList();
_catmap.put(categoryid, catlist);
// figure out which entries are in this category
int[] entids = _rep.getEntryIds(categoryid);
// create a select string with the eids that aren't already
// loaded
StringBuffer query = new StringBuffer();
for (int i = 0; i < entids.length; i++) {
// make sure the entry to category id mapping table
// contains this information
_entmap.put(entids[i], categoryid);
// see if we've cached the entry
Entry entry = (Entry)_entries.get(entids[i]);
if (entry != null) {
// if we have already loaded this entry, stick it into
// the category list
catlist.add(entry);
} else {
// otherwise, append it to the query to be loaded
if (query.length() > 0) {
query.append(", ");
}
query.append(entids[i]);
}
}
// load up these entries if we have any to load
if (query.length() > 0) {
query.insert(0, "where entryid in (");
query.append(")");
// now load up these entries
Entry[] ents = _rep.getEntries(query.toString());
for (int i = 0; i < ents.length; i++) {
// cache 'em
_entries.put(ents[i].entryid, ents[i]);
// and stick 'em in the category list
catlist.add(ents[i]);
}
}
}
return catlist;
}
protected Repository _rep;
protected Category[] _cats;
protected IntMap _entries = new IntMap();
protected IntMap _catmap = new IntMap();
protected IntIntMap _entmap = new IntIntMap();
}
@@ -0,0 +1,45 @@
//
// $Id: ModelUtil.java,v 1.1 2001/06/07 08:37:47 mdb Exp $
package robodj.chooser;
import robodj.repository.*;
/**
* Some utility functions.
*/
public class ModelUtil
{
/**
* Generates a string array suitable for sticking into a combo box
* with the category names.
*/
public static String[] catBoxNames (Model model)
{
Category[] cats = model.getCategories();
String[] names = new String[cats.length+1];
names[0] = "<uncategorized>";
for (int i = 0; i < cats.length; i++) {
names[i+1] = cats[i].name;
}
return names;
}
/**
* Returns the index of the specified category in the category array.
* Useful for activating a particular category in a combo box, for
* example. -1 is returned if no category with the specified id exists
* in the category list (but if that's the case, something really
* wacky is going on).
*/
public static int getCategoryIndex (Model model, int categoryid)
{
Category[] cats = model.getCategories();
for (int i = 0; i < cats.length; i++) {
if (cats[i].categoryid == categoryid) {
return i;
}
}
return -1;
}
}
@@ -1,13 +1,15 @@
// //
// $Id: Repository.java,v 1.4 2001/06/02 02:22:55 mdb Exp $ // $Id: Repository.java,v 1.5 2001/06/07 08:37:47 mdb Exp $
package robodj.repository; package robodj.repository;
import java.sql.*; import java.sql.*;
import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import com.samskivert.jdbc.MySQLRepository; import com.samskivert.jdbc.MySQLRepository;
import com.samskivert.jdbc.JDBCUtil;
import com.samskivert.jdbc.jora.*; import com.samskivert.jdbc.jora.*;
import com.samskivert.util.*; import com.samskivert.util.*;
@@ -50,8 +52,8 @@ public class Repository extends MySQLRepository
"entryid"); "entryid");
_stable = new Table(Song.class.getName(), "songs", _session, _stable = new Table(Song.class.getName(), "songs", _session,
"songid"); "songid");
_ctable = new Table(Category.class.getName(), "categories", _session, _ctable = new Table(Category.class.getName(), "category_names",
"categoryid"); _session, "categoryid");
_cmtable = new Table(CategoryMapping.class.getName(), "category_map", _cmtable = new Table(CategoryMapping.class.getName(), "category_map",
_session, new String[] {"categoryid", "entryid"}); _session, new String[] {"categoryid", "entryid"});
} }
@@ -98,7 +100,7 @@ public class Repository extends MySQLRepository
public Entry[] getEntries (final String query) public Entry[] getEntries (final String query)
throws SQLException throws SQLException
{ {
return (Entry[])execute(new Operation () { return (Entry[])execute(new Operation() {
public Object invoke () throws SQLException public Object invoke () throws SQLException
{ {
// look up the entry // look up the entry
@@ -123,7 +125,7 @@ public class Repository extends MySQLRepository
throws SQLException throws SQLException
{ {
if (entry.songs == null) { if (entry.songs == null) {
execute(new Operation () { execute(new Operation() {
public Object invoke () throws SQLException public Object invoke () throws SQLException
{ {
// load up the songs for this entry // load up the songs for this entry
@@ -149,7 +151,7 @@ public class Repository extends MySQLRepository
public void insertEntry (final Entry entry) public void insertEntry (final Entry entry)
throws SQLException throws SQLException
{ {
execute(new Operation () { execute(new Operation() {
public Object invoke () throws SQLException public Object invoke () throws SQLException
{ {
// insert the entry into the entry table // insert the entry into the entry table
@@ -187,7 +189,7 @@ public class Repository extends MySQLRepository
public void updateEntry (final Entry entry) public void updateEntry (final Entry entry)
throws SQLException throws SQLException
{ {
execute(new Operation () { execute(new Operation() {
public Object invoke () throws SQLException public Object invoke () throws SQLException
{ {
// update the entry // update the entry
@@ -211,7 +213,7 @@ public class Repository extends MySQLRepository
public void deleteEntry (final Entry entry) public void deleteEntry (final Entry entry)
throws SQLException throws SQLException
{ {
execute(new Operation () { execute(new Operation() {
public Object invoke () throws SQLException public Object invoke () throws SQLException
{ {
// remove the entry from the entry table and the foreign // remove the entry from the entry table and the foreign
@@ -238,7 +240,7 @@ public class Repository extends MySQLRepository
public void addSongToEntry (final Entry entry, final Song song) public void addSongToEntry (final Entry entry, final Song song)
throws SQLException throws SQLException
{ {
execute(new Operation () { execute(new Operation() {
public Object invoke () throws SQLException public Object invoke () throws SQLException
{ {
// fill in the appropriate entry id value // fill in the appropriate entry id value
@@ -261,7 +263,7 @@ public class Repository extends MySQLRepository
public void updateSong (final Song song) public void updateSong (final Song song)
throws SQLException throws SQLException
{ {
execute(new Operation () { execute(new Operation() {
public Object invoke () throws SQLException public Object invoke () throws SQLException
{ {
_stable.update(song); _stable.update(song);
@@ -277,7 +279,7 @@ public class Repository extends MySQLRepository
public int createCategory (final String name) public int createCategory (final String name)
throws SQLException throws SQLException
{ {
execute(new Operation () { execute(new Operation() {
public Object invoke () throws SQLException public Object invoke () throws SQLException
{ {
Category cat = new Category(); Category cat = new Category();
@@ -297,7 +299,7 @@ public class Repository extends MySQLRepository
public Category[] getCategories () public Category[] getCategories ()
throws SQLException throws SQLException
{ {
return (Category[])execute(new Operation () { return (Category[])execute(new Operation() {
public Object invoke () throws SQLException public Object invoke () throws SQLException
{ {
Cursor ccur = _ctable.select(""); Cursor ccur = _ctable.select("");
@@ -309,6 +311,64 @@ public class Repository extends MySQLRepository
}); });
} }
/**
* Fetches all of the entry ids that are associated with this category
* and returns them. If <code>categoryid</code> is -1, it instead
* returns all of the entry ids that are not in any category.
*/
public int[] getEntryIds (final int categoryid)
throws SQLException
{
return (int[])execute(new Operation() {
public Object invoke () throws SQLException
{
if (categoryid >= 0) {
String query = "where categoryid=" + categoryid;
Cursor cmcur = _cmtable.select(query);
List cmlist = cmcur.toArrayList();
int[] eids = new int[cmlist.size()];
for (int i = 0; i < cmlist.size(); i++) {
eids[i] = ((CategoryMapping)cmlist.get(i)).entryid;
}
return eids;
} else {
// i wish i knew how to do this sort of jockeying in
// SQL, but I can't be bothered to sort it out for a
// data set that isn't going to be so big that it
// can't be done in Java
IntMap ids = new IntMap();
Statement stmt = _session.connection.createStatement();
try {
// first add all the entryids in the repository
String query = "select entryid from entries";
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
ids.put(rs.getInt(1), "");
}
// now remove those that are mapped to a category
query = "select entryid from category_map";
rs = stmt.executeQuery(query);
while (rs.next()) {
ids.remove(rs.getInt(1));
}
} finally {
JDBCUtil.close(stmt);
}
int[] eids = new int[ids.size()];
Enumeration keys = ids.keys();
for (int i = 0; keys.hasMoreElements(); i++) {
eids[i] = ((Integer)keys.nextElement()).intValue();
}
return eids;
}
}
});
}
/** /**
* Associates the specified entry with the specified category. An * Associates the specified entry with the specified category. An
* entry can be mapped into multiple categories. * entry can be mapped into multiple categories.
@@ -316,7 +376,7 @@ public class Repository extends MySQLRepository
public void associateEntry (final Entry entry, final int categoryid) public void associateEntry (final Entry entry, final int categoryid)
throws SQLException throws SQLException
{ {
execute(new Operation () { execute(new Operation() {
public Object invoke () throws SQLException public Object invoke () throws SQLException
{ {
CategoryMapping map = CategoryMapping map =
@@ -333,7 +393,7 @@ public class Repository extends MySQLRepository
public void disassociateEntry (final Entry entry, final int categoryid) public void disassociateEntry (final Entry entry, final int categoryid)
throws SQLException throws SQLException
{ {
execute(new Operation () { execute(new Operation() {
public Object invoke () throws SQLException public Object invoke () throws SQLException
{ {
CategoryMapping map = CategoryMapping map =