diff --git a/projects/robodj/src/java/robodj/chooser/BrowsePanel.java b/projects/robodj/src/java/robodj/chooser/BrowsePanel.java index e130cc64..3c8cc110 100644 --- a/projects/robodj/src/java/robodj/chooser/BrowsePanel.java +++ b/projects/robodj/src/java/robodj/chooser/BrowsePanel.java @@ -1,34 +1,48 @@ // -// $Id: BrowsePanel.java,v 1.4 2003/05/04 18:16:06 mdb Exp $ +// $Id: BrowsePanel.java,v 1.5 2004/01/26 16:10:55 mdb Exp $ package robodj.chooser; +import java.awt.BorderLayout; +import java.util.ArrayList; + import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import com.samskivert.util.CollectionUtil; + import robodj.repository.*; -public class BrowsePanel extends JTabbedPane +public class BrowsePanel extends JPanel { public BrowsePanel () { - EntryList elist; - Category[] cats = Chooser.model.getCategories(); + setLayout(new BorderLayout(5, 5)); - // stick our tabs along the side and scroll if they don't fit - setTabPlacement(LEFT); - setTabLayoutPolicy(SCROLL_TAB_LAYOUT); + // obtain our categories + ArrayList cats = new ArrayList(); + CollectionUtil.addAll(cats, Chooser.model.getCategories()); + // add an "Uncategorized" category + cats.add(new Category(-1, "Uncategorized")); - // create a tab for each category - for (int i = 0; i < cats.length; i++) { - elist = new CategoryEntryList(cats[i].categoryid); - String tip = "Browse entries in '" + cats[i].name + "' category."; - addTab(cats[i].name, null, elist, tip); - } + final JList clist = new JList(cats.toArray()); + clist.getSelectionModel().setSelectionMode( + ListSelectionModel.SINGLE_SELECTION); + ListSelectionListener lsl = new ListSelectionListener() { + public void valueChanged (ListSelectionEvent lse) { + Category cat = (Category)clist.getSelectedValue(); + if (cat != null) { + _category.setCategory(cat.categoryid); + } + } + }; + clist.getSelectionModel().addListSelectionListener(lsl); + add(new JScrollPane(clist), BorderLayout.WEST); - // and add one for uncategorized entries - elist = new CategoryEntryList(-1); - addTab("Uncategorized", null, elist, - "Browse uncategorized entries."); - - setSelectedIndex(0); + add(_category = new CategoryEntryList(-1), BorderLayout.CENTER); + clist.setSelectedIndex(cats.size()-1); } + + protected CategoryEntryList _category; } diff --git a/projects/robodj/src/java/robodj/chooser/CategoryEntryList.java b/projects/robodj/src/java/robodj/chooser/CategoryEntryList.java index 8333549e..d812e7f0 100644 --- a/projects/robodj/src/java/robodj/chooser/CategoryEntryList.java +++ b/projects/robodj/src/java/robodj/chooser/CategoryEntryList.java @@ -1,5 +1,5 @@ // -// $Id: CategoryEntryList.java,v 1.2 2003/05/04 18:16:06 mdb Exp $ +// $Id: CategoryEntryList.java,v 1.3 2004/01/26 16:10:55 mdb Exp $ package robodj.chooser; @@ -15,7 +15,18 @@ public class CategoryEntryList extends EntryList */ public CategoryEntryList (int categoryId) { - _categoryId = categoryId; + setCategory(categoryId); + } + + /** + * Updates our category. + */ + public void setCategory (int categoryId) + { + if (categoryId != _categoryId) { + _categoryId = categoryId; + Controller.postAction(this, "refresh"); + } } // documentation inherited diff --git a/projects/robodj/src/java/robodj/chooser/Chooser.java b/projects/robodj/src/java/robodj/chooser/Chooser.java index b6737027..a6a7dc97 100644 --- a/projects/robodj/src/java/robodj/chooser/Chooser.java +++ b/projects/robodj/src/java/robodj/chooser/Chooser.java @@ -1,5 +1,5 @@ // -// $Id: Chooser.java,v 1.12 2003/05/07 17:27:12 mdb Exp $ +// $Id: Chooser.java,v 1.13 2004/01/26 16:10:55 mdb Exp $ package robodj.chooser; @@ -9,6 +9,7 @@ import java.io.IOException; import java.util.Properties; import javax.swing.JOptionPane; +import javax.swing.UIManager; import com.samskivert.io.PersistenceException; import com.samskivert.jdbc.StaticConnectionProvider; @@ -17,6 +18,7 @@ import com.samskivert.util.StringUtil; import com.samskivert.swing.util.SwingUtil; import com.samskivert.util.ConfigUtil; import com.samskivert.util.PropertiesUtil; +import com.samskivert.util.RunAnywhere; import robodj.Log; import robodj.repository.Model; @@ -44,6 +46,15 @@ public class Chooser { boolean error = false; +// try { +// UIManager.setLookAndFeel( +// RunAnywhere.isLinux() ? +// "com.sun.java.swing.plaf.gtk.GTKLookAndFeel" : +// UIManager.getSystemLookAndFeelClassName()); +// } catch (Exception e) { +// Log.info("Failed to set GTK look and feel: " + e); +// } + // loop until the user provides us with a configuration that works // or requests to exit for (int ii = 0; ii < 100; ii++) { diff --git a/projects/robodj/src/java/robodj/chooser/ChooserFrame.java b/projects/robodj/src/java/robodj/chooser/ChooserFrame.java index bcc343a6..7393cc50 100644 --- a/projects/robodj/src/java/robodj/chooser/ChooserFrame.java +++ b/projects/robodj/src/java/robodj/chooser/ChooserFrame.java @@ -1,5 +1,5 @@ // -// $Id: ChooserFrame.java,v 1.11 2003/05/04 18:16:06 mdb Exp $ +// $Id: ChooserFrame.java,v 1.12 2004/01/26 16:10:55 mdb Exp $ package robodj.chooser; @@ -17,6 +17,7 @@ import robodj.Log; import robodj.Version; import robodj.repository.*; import robodj.util.ButtonUtil; +import robodj.util.FancyPanel; import robodj.util.RDJPrefs; import robodj.util.ServerControl.PlayingListener; @@ -31,16 +32,14 @@ public class ChooserFrame extends JFrame setDefaultCloseOperation(EXIT_ON_CLOSE); // we create a top-level panel to manage everything - JPanel top = new JPanel(); GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH); gl.setOffAxisPolicy(GroupLayout.STRETCH); - top.setLayout(gl); - - // give ourselves a wee bit of a border + JPanel top = new FancyPanel(gl, ButtonUtil.getImage(BACKGROUND_PATH)); top.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); // the top of the UI is the browser and the playlist manager JTabbedPane tpane = new JTabbedPane(); + tpane.setBackground(BGCOLOR); PlaylistPanel ppanel = new PlaylistPanel(); String tip = "View and manipulate the playlist."; tpane.addTab("Playlist", null, ppanel, tip); @@ -102,6 +101,13 @@ public class ChooserFrame extends JFrame // now add our top-level panel (we'd not use this if we could set // a border on the content pane returned by the frame... alas) getContentPane().add(top, BorderLayout.CENTER); + SwingUtil.applyToHierarchy(top, new SwingUtil.ComponentOp() { + public void apply (Component comp) { + if (comp instanceof JPanel || comp instanceof JButton) { + ((JComponent) comp).setOpaque(false); + } + } + }); // add ourselves as a playing listener Chooser.scontrol.addPlayingListener(this); @@ -187,6 +193,9 @@ public class ChooserFrame extends JFrame protected static final String BACK_ICON_PATH = ICON_ROOT + "back.png"; protected static final String EXIT_ICON_PATH = ICON_ROOT + "exit.png"; + protected static final String BACKGROUND_PATH = + ICON_ROOT + "background.png"; + // button tips protected static final String PLAY_TIP = "Play"; protected static final String PAUSE_TIP = @@ -195,4 +204,7 @@ public class ChooserFrame extends JFrame protected static final String SKIP_TIP = "Skip to the next song"; protected static final String BACK_TIP = "Skip to the previous song"; protected static final String EXIT_TIP = "Exit"; + + // our common background color + protected static final Color BGCOLOR = new Color(0x7A719A); } diff --git a/projects/robodj/src/java/robodj/chooser/EntryController.java b/projects/robodj/src/java/robodj/chooser/EntryController.java index 086436e0..ad21785e 100644 --- a/projects/robodj/src/java/robodj/chooser/EntryController.java +++ b/projects/robodj/src/java/robodj/chooser/EntryController.java @@ -1,5 +1,5 @@ // -// $Id: EntryController.java,v 1.2 2003/05/19 02:53:25 mdb Exp $ +// $Id: EntryController.java,v 1.3 2004/01/26 16:10:55 mdb Exp $ package robodj.chooser; @@ -112,9 +112,8 @@ public abstract class EntryController extends ItemController 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 + } else if (cmd.equals("refresh")) { + // re-read the category TaskMaster.invokeMethodTask("readEntries", this, this); } else if (cmd.equals("edit")) { diff --git a/projects/robodj/src/java/robodj/chooser/EntryList.java b/projects/robodj/src/java/robodj/chooser/EntryList.java index 46efb45c..02391e40 100644 --- a/projects/robodj/src/java/robodj/chooser/EntryList.java +++ b/projects/robodj/src/java/robodj/chooser/EntryList.java @@ -1,5 +1,5 @@ // -// $Id: EntryList.java,v 1.13 2003/05/04 18:16:06 mdb Exp $ +// $Id: EntryList.java,v 1.14 2004/01/26 16:10:55 mdb Exp $ package robodj.chooser; @@ -18,29 +18,17 @@ import robodj.Log; import robodj.repository.*; import robodj.util.ButtonUtil; -public abstract class EntryList extends JScrollPane +public abstract class EntryList extends JSplitPane implements ControllerProvider { public EntryList () { - // create the pane that will hold the buttons - GroupLayout gl = new VGroupLayout(GroupLayout.NONE); - gl.setOffAxisPolicy(GroupLayout.STRETCH); - gl.setJustification(GroupLayout.TOP); - gl.setGap(2); - _bpanel = new ScrollablePanel() { - // make the playlist fit the width of the scrolling viewport - public boolean getScrollableTracksViewportWidth () { - return true; - } - }; - _bpanel.setLayout(gl); + super(JSplitPane.VERTICAL_SPLIT); - // give ourselves a wee bit of a border - _bpanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - - // set our viewport view - setViewportView(_bpanel); + setOpaque(false); + setDividerLocation(200); + setLeftComponent(new JScrollPane(_bpanel = createPanel())); + setRightComponent(new JScrollPane(_epanel = createPanel())); // use a special font for our name buttons _titleFont = new Font("Helvetica", Font.BOLD, 14); @@ -49,6 +37,27 @@ public abstract class EntryList extends JScrollPane _controller = createController(); } + /** + * Creates a panel configured for displaying entries or songs. + */ + protected JPanel createPanel () + { + GroupLayout gl = new VGroupLayout(GroupLayout.NONE); + gl.setOffAxisPolicy(GroupLayout.STRETCH); + gl.setJustification(GroupLayout.TOP); + gl.setGap(2); + JPanel panel = new ScrollablePanel() { + // make the playlist fit the width of the scrolling viewport + public boolean getScrollableTracksViewportWidth () { + return true; + } + }; + panel.setLayout(gl); + panel.setOpaque(false); + panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + return panel; + } + public Controller getController () { return _controller; @@ -99,25 +108,18 @@ public abstract class EntryList extends JScrollPane _bpanel.add(new JLabel(getEmptyString())); } - // reset our scroll position so that we're displaying the top of - // the entry list. we'd like to save our scroll position and - // restore it when the user clicks "up", but as we're rebuilding - // the entry display the scroll bar is still configured for the - // old contents and we're not around when it gets configured with - // the new contents, so we can't ensure that the scrollbar has - // been properly configured before we adjust its position back to - // where we were... oh the complication. - clearScrollPosition(); + // reset our scroll position + clearScrollPosition((JScrollPane)getLeftComponent()); // we've removed and added components so we need to revalidate - revalidate(); - repaint(); + SwingUtil.setOpaque(_bpanel, false); + SwingUtil.refresh(_bpanel); } protected void populateSong (Entry entry) { // clear out any existing children - _bpanel.removeAll(); + _epanel.removeAll(); GroupLayout gl = new HGroupLayout(HGroupLayout.STRETCH); gl.setJustification(GroupLayout.LEFT); @@ -129,11 +131,6 @@ public abstract class EntryList extends JScrollPane label.setFont(_titleFont); header.add(label); - // add a button for getting the heck out of here - JButton upbtn = ButtonUtil.createControlButton( - 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), true); @@ -151,7 +148,7 @@ public abstract class EntryList extends JScrollPane int catidx = ModelUtil.getCategoryIndex(Chooser.model, catid); catcombo.setSelectedIndex(catidx+1); - _bpanel.add(header, GroupLayout.FIXED); + _epanel.add(header, GroupLayout.FIXED); // sort the songs by position Comparator scomp = new Comparator() { @@ -167,26 +164,23 @@ public abstract class EntryList extends JScrollPane // and add buttons for every song for (int i = 0; i < entry.songs.length; i++) { - _bpanel.add(new SongItem(entry.songs[i], SongItem.BROWSER)); + _epanel.add(new SongItem(entry.songs[i], SongItem.BROWSER)); } - // reset our scroll position so that we're displaying the top of - // the song list - clearScrollPosition(); - // we've removed and added components so we need to revalidate - revalidate(); - repaint(); + SwingUtil.setOpaque(_epanel, false); + SwingUtil.refresh(_epanel); } - protected void clearScrollPosition () + protected void clearScrollPosition (JScrollPane pane) { - BoundedRangeModel model = getVerticalScrollBar().getModel(); + BoundedRangeModel model = pane.getVerticalScrollBar().getModel(); model.setValue(model.getMinimum()); } protected Controller _controller; protected JPanel _bpanel; + protected JPanel _epanel; protected Font _titleFont; diff --git a/projects/robodj/src/java/robodj/chooser/PlaylistPanel.java b/projects/robodj/src/java/robodj/chooser/PlaylistPanel.java index 360cc2a0..d1349797 100644 --- a/projects/robodj/src/java/robodj/chooser/PlaylistPanel.java +++ b/projects/robodj/src/java/robodj/chooser/PlaylistPanel.java @@ -1,5 +1,5 @@ // -// $Id: PlaylistPanel.java,v 1.14 2003/05/04 18:16:06 mdb Exp $ +// $Id: PlaylistPanel.java,v 1.15 2004/01/26 16:10:55 mdb Exp $ package robodj.chooser; @@ -68,6 +68,7 @@ public class PlaylistPanel extends ControlledPanel GroupLayout bgl = new HGroupLayout(GroupLayout.NONE); bgl.setJustification(GroupLayout.RIGHT); JPanel cbar = new JPanel(bgl); + cbar.setOpaque(false); // add our control buttons _clearbut = ButtonUtil.createControlButton( diff --git a/projects/robodj/src/java/robodj/chooser/images/back.png b/projects/robodj/src/java/robodj/chooser/images/back.png index 5f563a51..2271a614 100644 Binary files a/projects/robodj/src/java/robodj/chooser/images/back.png and b/projects/robodj/src/java/robodj/chooser/images/back.png differ diff --git a/projects/robodj/src/java/robodj/chooser/images/background.png b/projects/robodj/src/java/robodj/chooser/images/background.png new file mode 100644 index 00000000..3e5f6e30 Binary files /dev/null and b/projects/robodj/src/java/robodj/chooser/images/background.png differ diff --git a/projects/robodj/src/java/robodj/chooser/images/browse.png b/projects/robodj/src/java/robodj/chooser/images/browse.png index 622b95a4..00795879 100644 Binary files a/projects/robodj/src/java/robodj/chooser/images/browse.png and b/projects/robodj/src/java/robodj/chooser/images/browse.png differ diff --git a/projects/robodj/src/java/robodj/chooser/images/edit.png b/projects/robodj/src/java/robodj/chooser/images/edit.png index b72489fe..2d4641d5 100644 Binary files a/projects/robodj/src/java/robodj/chooser/images/edit.png and b/projects/robodj/src/java/robodj/chooser/images/edit.png differ diff --git a/projects/robodj/src/java/robodj/chooser/images/pause.png b/projects/robodj/src/java/robodj/chooser/images/pause.png index 4b132c04..1e03ef15 100644 Binary files a/projects/robodj/src/java/robodj/chooser/images/pause.png and b/projects/robodj/src/java/robodj/chooser/images/pause.png differ diff --git a/projects/robodj/src/java/robodj/chooser/images/play.png b/projects/robodj/src/java/robodj/chooser/images/play.png index 7ebcb184..d252e2de 100644 Binary files a/projects/robodj/src/java/robodj/chooser/images/play.png and b/projects/robodj/src/java/robodj/chooser/images/play.png differ diff --git a/projects/robodj/src/java/robodj/chooser/images/skip.png b/projects/robodj/src/java/robodj/chooser/images/skip.png index 5e3d7959..b1d259a4 100644 Binary files a/projects/robodj/src/java/robodj/chooser/images/skip.png and b/projects/robodj/src/java/robodj/chooser/images/skip.png differ diff --git a/projects/robodj/src/java/robodj/chooser/images/stop.png b/projects/robodj/src/java/robodj/chooser/images/stop.png index 6234e569..e7c84a2b 100644 Binary files a/projects/robodj/src/java/robodj/chooser/images/stop.png and b/projects/robodj/src/java/robodj/chooser/images/stop.png differ diff --git a/projects/robodj/src/java/robodj/chooser/images/up.png b/projects/robodj/src/java/robodj/chooser/images/up.png deleted file mode 100644 index 03033bd4..00000000 Binary files a/projects/robodj/src/java/robodj/chooser/images/up.png and /dev/null differ diff --git a/projects/robodj/src/java/robodj/repository/Category.java b/projects/robodj/src/java/robodj/repository/Category.java index ff2ea8b6..41b90cab 100644 --- a/projects/robodj/src/java/robodj/repository/Category.java +++ b/projects/robodj/src/java/robodj/repository/Category.java @@ -1,5 +1,5 @@ // -// $Id: Category.java,v 1.1 2000/11/08 06:42:57 mdb Exp $ +// $Id: Category.java,v 1.2 2004/01/26 16:10:55 mdb Exp $ package robodj.repository; @@ -14,4 +14,22 @@ public class Category /** The name of this category. */ public String name; + + /** Creates an uninitialized category instance. */ + public Category () + { + } + + /** Creates an initialized category instance. */ + public Category (int categoryid, String name) + { + this.categoryid = categoryid; + this.name = name; + } + + /** Generates a string representation of this instance. */ + public String toString () + { + return name; + } } diff --git a/projects/robodj/src/java/robodj/util/ButtonUtil.java b/projects/robodj/src/java/robodj/util/ButtonUtil.java index be5bfaf1..2c7a4e8e 100644 --- a/projects/robodj/src/java/robodj/util/ButtonUtil.java +++ b/projects/robodj/src/java/robodj/util/ButtonUtil.java @@ -1,5 +1,5 @@ // -// $Id: ButtonUtil.java,v 1.2 2003/05/04 18:16:07 mdb Exp $ +// $Id: ButtonUtil.java,v 1.3 2004/01/26 16:10:55 mdb Exp $ package robodj.util; @@ -23,26 +23,31 @@ import robodj.Log; */ public class ButtonUtil { - public static ImageIcon getIcon (String iconPath) + public static Image getImage (String imagePath) { try { - InputStream imgin = ButtonUtil.class.getResourceAsStream(iconPath); + InputStream imgin = ButtonUtil.class.getResourceAsStream(imagePath); if (imgin != null) { - Image image = ImageIO.read(imgin); - return new ImageIcon(image); + return ImageIO.read(imgin); } } catch (IOException ioe) { - Log.warning("Unable to load icon [path=" + iconPath + + Log.warning("Unable to load image [path=" + imagePath + ", error=" + ioe + "]."); } catch (Exception e) { - Log.warning("Error loading icon [path=" + iconPath + "]."); + Log.warning("Error loading image [path=" + imagePath + "]."); Log.logStackTrace(e); } return null; } + public static ImageIcon getIcon (String iconPath) + { + Image image = getImage(iconPath); + return image == null ? null : new ImageIcon(image); + } + public static JButton createControlButton ( String tooltip, String action, String iconPath) { diff --git a/projects/robodj/src/java/robodj/util/FancyPanel.java b/projects/robodj/src/java/robodj/util/FancyPanel.java new file mode 100644 index 00000000..5823e03e --- /dev/null +++ b/projects/robodj/src/java/robodj/util/FancyPanel.java @@ -0,0 +1,77 @@ +// +// $Id: FancyPanel.java,v 1.1 2004/01/26 16:10:55 mdb Exp $ + +package robodj.util; + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.LayoutManager; +import java.awt.Shape; + +import com.samskivert.swing.ScrollablePanel; + +/** + * A {@link JPanel} that displays an image in its background. + */ +public class FancyPanel extends ScrollablePanel +{ + public FancyPanel (Image image) + { + _image = image; + } + + public FancyPanel (LayoutManager lmgr, Image image) + { + super(lmgr); + _image = image; + } + + public void paintComponent (Graphics gfx) + { + int x = 0, y = 0; + int width = this.getWidth(); + int height = this.getHeight(); + int iwidth = _image.getWidth(null), + iheight = _image.getHeight(null); + int xnum = width / iwidth, xplus = width % iwidth; + int ynum = height / iheight, yplus = height % iheight; + Shape oclip = gfx.getClip(); + + for (int ii=0; ii < ynum; ii++) { + // draw the full copies of the image across + int xx = x; + for (int jj=0; jj < xnum; jj++) { + gfx.drawImage(_image, xx, y, null); + xx += iwidth; + } + + if (xplus > 0) { + gfx.clipRect(xx, y, xplus, iheight); + gfx.drawImage(_image, xx, y, null); + gfx.setClip(oclip); + } + + y += iheight; + } + + if (yplus > 0) { + int xx = x; + for (int jj=0; jj < xnum; jj++) { + gfx.clipRect(xx, y, iwidth, yplus); + gfx.drawImage(_image, xx, y, null); + gfx.setClip(oclip); + xx += iwidth; + } + + if (xplus > 0) { + gfx.clipRect(xx, y, xplus, yplus); + gfx.drawImage(_image, xx, y, null); + gfx.setClip(oclip); + } + } + + super.paintComponent(gfx); + } + + protected Image _image; +}