001: package org.millstone.examples.stoneplayer;
002:
003: import org.millstone.base.ui.*;
004: import org.millstone.base.event.*;
005: import org.millstone.base.terminal.FileResource;
006: import org.millstone.base.terminal.ThemeResource;
007: import org.millstone.base.data.Property;
008: import org.millstone.base.data.util.FilesystemContainer;
009:
010: import java.io.File;
011: import java.util.Collection;
012: import java.util.Iterator;
013:
014: /** Shared MP3 jukebox.
015: *
016: * @author IT Mill Ltd
017: */
018: public class StonePlayer extends org.millstone.base.Application {
019:
020: /** Shared jukebox used for playing. */
021: private static Jukebox sharedJukebox;
022:
023: /** Creates a new instance of Calculator and initialized UI */
024: public StonePlayer() {
025: sharedJukebox = new Jukebox();
026: }
027:
028: /**
029: * @see org.millstone.base.Application#init()
030: */
031: public void init() {
032:
033: // Set the application-wide theme
034: setTheme("stoneplayer");
035:
036: // Create framed main window
037: FrameWindow mainWindow = new FrameWindow("StonePlayer");
038: setMainWindow(mainWindow);
039:
040: // Player window
041: Window playerWin = new Window("Player");
042: playerWin.addComponent(new Player());
043:
044: // Playlist window
045: Window playlistWin = new Window("Playlist");
046: playlistWin.addComponent(new Playlist());
047:
048: // Browser window
049: Window browserWin = new Window("File browser");
050: browserWin.addComponent(new FileBrowser());
051:
052: // Banner window
053: Window bannerWin = new Window("Banner window");
054: Embedded banner = new Embedded();
055: banner.setType(Embedded.TYPE_IMAGE);
056: banner
057: .setSource(new ThemeResource(
058: "images/stoneplayer-1.3.jpg"));
059: bannerWin.addComponent(banner);
060:
061: // Assign frames
062: mainWindow.getFrameset().setVertical(true);
063: mainWindow.getFrameset().newFrame(bannerWin, 0)
064: .setAbsoluteSize(48);
065: FrameWindow.Frameset bodyFrame = mainWindow.getFrameset()
066: .newFrameset(false, 1);
067:
068: FrameWindow.Frameset leftFrame = bodyFrame.newFrameset(true, 0);
069: leftFrame.setAbsoluteSize(300);
070: leftFrame.newFrame(playerWin, 0).setAbsoluteSize(200);
071: leftFrame.newFrame(playlistWin, 1);
072: bodyFrame.newFrame(browserWin, 1);
073:
074: }
075:
076: private class Playlist extends OrderedLayout implements
077: JukeboxListener, Property.ValueChangeListener {
078:
079: private Table playlist;
080:
081: public Playlist() {
082:
083: playlist = new Table();
084:
085: // Playlist
086: playlist.setCaption("Playlist");
087: playlist.setRowHeaderMode(Table.ROW_HEADER_MODE_ID);
088: playlist.setSelectable(true);
089: playlist.setImmediate(true);
090: playlist.addListener(this );
091: playlist.setStyle("list");
092: addComponent(playlist);
093:
094: // Listen julkebox changes
095: sharedJukebox.addListener(this );
096:
097: // Refresh the view to reflect the current jukebox state
098: jukeboxPlaylistChanged(sharedJukebox);
099: }
100:
101: /** Invoked when state of the jukebox has changed. */
102: public void jukeboxStateChanged(Jukebox jukebox) {
103:
104: // select the current song
105: Song song = jukebox.getCurrentSong();
106: if (song != null) {
107: playlist.setValue(song);
108: }
109: }
110:
111: /** Refresh the playlist.
112: * @see org.millstone.examples.stoneplayer.JukeboxListener#jukeboxPlaylistChanged(Jukebox)
113: */
114: public void jukeboxPlaylistChanged(Jukebox jukebox) {
115:
116: // Update the visible playlist
117: Collection pl = jukebox.getPlayList();
118: playlist.removeAllItems();
119: if (pl != null) {
120: for (Iterator i = pl.iterator(); i.hasNext();) {
121: playlist.addItem((Song) i.next());
122: }
123: }
124:
125: // (re)select the current song
126: Song song = jukebox.getCurrentSong();
127: if (song != null) {
128: playlist.setValue(song);
129: }
130: }
131:
132: /** Invoked when the selection in playlist has changed.
133: * @see org.millstone.base.data.Property.ValueChangeListener#valueChange(Property.ValueChangeEvent)
134: */
135: public void valueChange(Property.ValueChangeEvent event) {
136: Song s = (Song) event.getProperty().getValue();
137: if (s != null) {
138: sharedJukebox.setCurrentSong(s);
139: }
140: }
141:
142: }
143:
144: /** Player controls buttons and current song information. */
145: private class Player extends OrderedLayout implements
146: JukeboxListener {
147:
148: private Label currentTitle;
149: private Button playstop;
150:
151: public Player() {
152:
153: setOrientation(OrderedLayout.ORIENTATION_VERTICAL);
154:
155: // Create buttons by connecting them directly to
156: // the jukebox functions. Play/stop button handled separately
157: OrderedLayout hl = new OrderedLayout(
158: OrderedLayout.ORIENTATION_HORIZONTAL);
159:
160: Button b;
161: hl.addComponent(b = new Button("Prev", sharedJukebox,
162: "prev"));
163: b.setStyle("stoneplayer");
164:
165: hl.addComponent(playstop = new Button("Play",
166: sharedJukebox, "play"));
167: playstop.setStyle("stoneplayer");
168:
169: hl.addComponent(b = new Button("Next", sharedJukebox,
170: "next"));
171: b.setStyle("stoneplayer");
172:
173: hl.addComponent(b = new Button("Rand", sharedJukebox,
174: "random"));
175: b.setStyle("stoneplayer");
176:
177: addComponent(hl);
178:
179: // Current song title
180: Panel titlePanel = new Panel("Currently playing");
181:
182: titlePanel.addComponent(currentTitle = new Label(""));
183: addComponent(titlePanel);
184:
185: // Listen julkebox changes
186: sharedJukebox.addListener(this );
187:
188: // Refresh the view to reflect the current jukebox state
189: jukeboxStateChanged(sharedJukebox);
190: }
191:
192: /** Invoked when state of the jukebox has changed. */
193: public void jukeboxStateChanged(Jukebox jukebox) {
194:
195: // update play/stop button state
196: if (jukebox.isPlaying()) {
197: playstop.setCaption("Stop");
198: playstop.removeListener(Button.ClickEvent.class,
199: sharedJukebox);
200: playstop.addListener(Button.ClickEvent.class,
201: sharedJukebox, "stop");
202: } else {
203: playstop.setCaption("Play");
204: playstop.removeListener(Button.ClickEvent.class,
205: sharedJukebox);
206: playstop.addListener(Button.ClickEvent.class,
207: sharedJukebox, "play");
208: }
209: // select the current song
210: Song song = jukebox.getCurrentSong();
211: if (song != null) {
212: currentTitle.setValue(song.getName());
213: }
214:
215: }
216:
217: /** Ignore playlist changed.
218: * @see org.millstone.examples.stoneplayer.JukeboxListener#jukeboxPlaylistChanged(Jukebox)
219: */
220: public void jukeboxPlaylistChanged(Jukebox jukebox) {
221: // Nothing to do here
222: }
223: }
224:
225: /** Music file browser component.
226: *
227: */
228: private class FileBrowser extends OrderedLayout implements
229: Action.Handler {
230:
231: private Table results;
232:
233: public FileBrowser() {
234:
235: // Create file browser tree
236: Tree tree = null;
237: String mp3Path = StonePlayer.this .getProperty("mp3path");
238: if (mp3Path != null && mp3Path.length() > 0) {
239: File path = new File(mp3Path);
240: if (path.exists()) {
241: FilesystemContainer f = new FilesystemContainer(
242: path, "mp3", true);
243: tree = new Tree("MP3 browser", f);
244: } else {
245: addComponent(new Label(
246: "Specified path does not exist: '"
247: + mp3Path
248: + "'. Please check the 'mp3path' parameter in server.xml or in web.xml."));
249: }
250: } else {
251: addComponent(new Label(
252: "<h1>Property 'mp3path' not specified in applicationproperties</h1>"
253: + "MP3-browsing disabled beacause application property named 'mp3path'"
254: + " was not found. Please declare 'mp3path' parameter in server.xml or "
255: + " in web.xml to enable file browsing. <br /><br />",
256: Label.CONTENT_XHTML));
257: }
258:
259: if (tree != null) {
260: tree.setItemCaptionMode(Tree.ITEM_CAPTION_MODE_ITEM);
261: tree.setSelectable(false);
262: tree
263: .setItemIconPropertyId(FilesystemContainer.PROPERTY_ICON);
264: tree.addActionHandler(this );
265: addComponent(tree);
266: }
267: }
268:
269: // Define some actions for files/folders
270: private Action ACT_PLAY = new Action("Play", null);
271: private Action ACT_ENQ = new Action("Enqueue", null);
272: private Action ACT_DL = new Action("Download", null);
273:
274: /** Return the list of available actions per (file or directory) item.
275: * @see org.millstone.base.event.Action.Handler#getActions(Object)
276: */
277: public Action[] getActions(Object target, Object source) {
278:
279: if (((File) target).isDirectory()) {
280:
281: // If directory contains mp3 files enable
282: // play/enqueue actions for this directory
283: boolean containsMp3 = false;
284: String[] list = ((File) target).list();
285: if (list == null)
286: return new Action[] {};
287: for (int i = 0; i < list.length && (!containsMp3); i++) {
288: if (list[i].endsWith(".mp3"))
289: containsMp3 = true;
290: }
291: if (containsMp3)
292: return new Action[] { ACT_PLAY, ACT_ENQ };
293: else
294: return new Action[] {};
295: } else {
296: // MP3 files are always playable/downloadable
297: return new Action[] { ACT_PLAY, ACT_ENQ, ACT_DL };
298: }
299: }
300:
301: /** Handle file actions.
302: * @see org.millstone.base.event.Action.Handler#handleAction(Action, Object, Object)
303: */
304: public void handleAction(Action action, Object sender,
305: Object target) {
306: if (action.equals(ACT_PLAY)) {
307: if (sharedJukebox.isPlaying())
308: sharedJukebox.stop();
309: sharedJukebox.clearPlayList();
310: sharedJukebox.addToPlayList((File) target);
311: sharedJukebox.play();
312: } else if (action.equals(ACT_ENQ)) {
313: sharedJukebox.addToPlayList((File) target);
314: } else if (action.equals(ACT_DL)) {
315: Window w = new Window();
316: w.setBorder(Window.BORDER_MINIMAL);
317: w
318: .open(new FileResource((File) target,
319: StonePlayer.this ));
320: addWindow(w);
321: }
322: }
323:
324: }
325: }
326:
327: /* This Millstone sample code is public domain. *
328: * For more information see www.millstone.org. */
|