📄 playlistmodel.java
字号:
/*******************************************************************************
* Copyright (c) 2004 Berthold Daum. All rights reserved. This program and the
* accompanying materials are made available under the terms of the Common
* Public License v1.0 which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors: Berthold Daum
******************************************************************************/
package com.bdaum.jukebox;
import java.io.*;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import org.apache.crimson.jaxp.DocumentBuilderFactoryImpl;
import org.apache.xalan.serialize.SerializerToXML;
import org.eclipse.jface.util.ListenerList;
import org.eclipse.jface.viewers.*;
import org.w3c.dom.*;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* This class implements the playlist domain model. XML is used as
* file format to make the model data persistent. Access to the XML
* data is organized via the JAXP DOM.
*/
public class PlaylistModel implements IPlaylist {
// Name of INI file
private final static String INIFILE = "jukebox.ini";
// XML prolog
private final static String XMLPROLOG = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
// Empty playlist
private final static String XMLROOT = XMLPROLOG
+ "<playlist></playlist>";
// Tag for playlist entries
public final static String RECORD = "record";
// INI file
private File iniFile;
// current playlist file name
private String currentPlaylistFile;
// current playlist DOM
private Document playlistDoc;
// current playlist entry DOM node
private Node currentElement;
// Listeners to be informed about changes
private ListenerList selectionChangedListeners = new ListenerList();
/**
* Constructor for PlaylistModel.
*/
public PlaylistModel() {
super();
try {
// Try to read the INI file
iniFile = new File(INIFILE);
InputStream stream = new FileInputStream(iniFile);
byte[] buffer = new byte[1024];
int l = stream.read(buffer);
// If it exists, read the name of the most recent
// playlist and open this playlist
openPlaylist(new String(buffer, 0, l));
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
/**
* Opens the playlist file
*
* @param name
* Name of playlist file
*/
private void openPlaylist(
String name) {
if (name == null) return;
currentPlaylistFile = name;
File playlistFile = new File(name);
// Input stream of playlist file
InputStream stream;
try {
stream = new FileInputStream(playlistFile);
} catch (FileNotFoundException e) {
// File does not exist
// We create an empty playlist document
stream = makeStream(XMLROOT);
}
if (stream != null) try {
// We parse the file content, creating a DOM
playlistDoc = parseStream(stream, false);
} catch (Throwable e) {
playlistDoc = null;
System.err.println("XML parsing error: " + e);
}
if (playlistDoc != null) {
// We look for <record>-elements and set the first one
// as current song
NodeList nl = playlistDoc.getElementsByTagName(RECORD);
if (nl.getLength() > 0) currentElement = nl.item(0);
}
}
/**
* Convert string into InputStream
*
* @param input -
* Input string
* @return InputStream - resulting InputStream instance
*/
public static InputStream makeStream(
String input) {
try {
return new ByteArrayInputStream(input.getBytes("UTF8"));
} catch (UnsupportedEncodingException x) {
// should never happen
return null;
}
}
/**
* Convert serialized XML stream into DOM tree.
*
* @param stream -
* input stream
* @param silent -
* don't show error messages on the console if set to true
* @return Document - the resulting DOM document
* @throws Throwable -
* various Throwables from Parser
*/
private static Document parseStream(
InputStream stream, boolean silent) throws Throwable {
// Create InputSource from stream
InputSource source = new InputSource(stream);
// Create a document builder factory
DocumentBuilderFactory factory = new DocumentBuilderFactoryImpl();
// Create a document builder
DocumentBuilder builder = factory.newDocumentBuilder();
// When "silent" is set we override the SAX error handler and
// suppress the output of error message to the Java console.
if (silent) {
builder.setErrorHandler(new ErrorHandler() {
public void error(
SAXParseException exception) throws SAXException {
throw exception;
}
public void fatalError(
SAXParseException exception) throws SAXException {
throw exception;
}
public void warning(
SAXParseException exception) throws SAXException {
throw exception;
}
});
}
// Everything is configured - let's parse.
return builder.parse(source);
}
/**
* Save current playlist to file.
*/
private void savePlaylist() {
if (playlistDoc == null || currentPlaylistFile == null)
return;
File playlistFile = new File(currentPlaylistFile);
try {
// Create new file and set output stream to this file.
playlistFile.createNewFile();
OutputStream stream = new FileOutputStream(playlistFile);
// Serialize DOM and write to output stream
stream.write(serializeNode(playlistDoc, true)
.toByteArray());
} catch (IOException e) {
System.err.println("IO-exception during save: " + e);
}
}
/**
* Convert whole DOM document or subtree into XML stream.
*
* @param nod -
* DOM document or DOM node
* @param prolog -
* "true" if an XML prolog is required
* @return ByteArrayOutputStream - serialized XML text
*/
public static ByteArrayOutputStream serializeNode(
Node nod, boolean prolog) {
// Set output formats
// (no identation, XML prolog depending on option)
SerializerToXML serializer = new SerializerToXML();
Properties props = new Properties();
props.setProperty(OutputKeys.METHOD, "xml");
props.setProperty(OutputKeys.INDENT, "no");
props.setProperty(OutputKeys.OMIT_XML_DECLARATION,
(prolog) ? "no" : "yes");
serializer.setOutputFormat(props);
// Create OutputStream and Serializer instances.
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
serializer.setOutputStream(outstream);
try {
// Serialize.
serializer.serialize(nod);
} catch (IOException e) { // should never happen
}
return outstream;
}
/** *** IPlayList methods **** */
/**
* @see IPlayList#getPlaylistName()
*/
public String getPlaylistName() {
return currentPlaylistFile;
}
/**
* @see IPlayList#next()
*/
public boolean next() {
// fetch next entry
Node nod = getNext();
if (nod == null) return false;
// in case of success set current entry to this value
setCurrent(nod);
return true;
}
/**
* Searches from current entry onwards for next entry.
*
* @return Node - the next entry
*/
private Node getNext() {
Node nod = currentElement;
// search next element with tag <record>
while (nod != null) {
nod = nod.getNextSibling();
if (nod instanceof Element
&& ((Element) nod).getTagName().equals(RECORD))
return nod;
}
return null;
}
/**
* @see IPlayList#previous()
*/
public boolean previous() {
// fetch previous entry
Node nod = getPrevious();
if (nod == null) return false;
// in case of success set current entry to this value
setCurrent(nod);
return true;
}
/**
* Searches from current entry onwards for previous entry.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -