// Near Infinity - An Infinity Engine Browser and Editor
// Copyright (C) 2001 - 2005 Jon Olav Hauglid
// See LICENSE.txt for license information
package org.infinity.resource.mus;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import org.infinity.gui.BrowserMenuBar;
import org.infinity.icon.Icons;
import org.infinity.resource.sound.AudioPlayer;
import org.infinity.util.SimpleListModel;
public class Viewer extends JPanel implements Runnable, ActionListener
{
private final SimpleListModel<Entry> listModel = new SimpleListModel<Entry>();
private final JList<Entry> list = new JList<>(listModel);
private final AudioPlayer player = new AudioPlayer();
private final List<Entry> entryList = new Vector<Entry>();
private JLabel playList;
private JButton bPlay, bEnd, bStop;
private boolean play, end, closed = false;
public Viewer(MusResource mus)
{
initGUI();
loadMusResource(mus);
}
//--------------------- Begin Interface ActionListener ---------------------
@Override
public void actionPerformed(ActionEvent event)
{
if (event.getSource() == bPlay) {
new Thread(this).start();
} else if (event.getSource() == bStop) {
bStop.setEnabled(false);
bEnd.setEnabled(false);
play = false;
player.stopPlay();
} else if (event.getSource() == bEnd) {
bEnd.setEnabled(false);
end = true;
}
}
//--------------------- End Interface ActionListener ---------------------
//--------------------- Begin Interface Runnable ---------------------
@Override
public void run()
{
bPlay.setEnabled(false);
bStop.setEnabled(true);
bEnd.setEnabled(true);
list.setEnabled(false);
int nextnr = list.getSelectedIndex();
if (nextnr == -1)
nextnr = 0;
play = true;
end = false;
try {
while (play) {
if (!end) {
list.setSelectedIndex(nextnr);
list.ensureIndexIsVisible(nextnr);
list.repaint();
player.play(entryList.get(nextnr).getAudioBuffer());
} else if (entryList.get(nextnr).getEndBuffer() != null) {
player.play(entryList.get(nextnr).getEndBuffer());
play = false;
}
if (!end) {
nextnr = entryList.get(nextnr).getNextNr();
if (nextnr == -1 || nextnr == entryList.size()) {
play = false;
}
}
}
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "Error during playback", "Error", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
}
bPlay.setEnabled(true);
bStop.setEnabled(false);
bEnd.setEnabled(false);
list.setEnabled(true);
list.setSelectedIndex(0);
list.ensureIndexIsVisible(0);
}
//--------------------- End Interface Runnable ---------------------
public void close()
{
setClosed(true);
stopPlay();
for (final Entry entry: entryList) {
entry.close();
}
entryList.clear();
}
// Creates a new music list and loads all associated soundtracks
public void loadMusResource(final MusResource mus)
{
if (mus != null) {
// Parse and load soundtracks in a separate thread
(new SwingWorker<Boolean, Void>() {
@Override
public Boolean doInBackground()
{
return parseMusFile(mus);
}
}).execute();
}
}
private boolean parseMusFile(MusResource mus)
{
if (!isClosed()) {
stopPlay();
bPlay.setEnabled(false);
list.setEnabled(false);
StringTokenizer tokenizer = new StringTokenizer(mus.getText(), "\r\n");
String dir = tokenizer.nextToken().trim();
listModel.clear();
entryList.clear();
int count = Integer.valueOf(tokenizer.nextToken().trim()).intValue();
for (int i = 0; i < count; i++) {
if (isClosed()) return false;
Entry entry = new Entry(mus.getResourceEntry(), dir, entryList, tokenizer.nextToken().trim(), i);
entryList.add(entry);
listModel.addElement(entry);
}
list.setSelectedIndex(0);
validate();
for (final Entry entry: entryList) {
if (isClosed()) return false;
try {
entry.init();
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(getTopLevelAncestor(), "Error loading " + entry.toString() + '\n' +
e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
boolean enable = (!entryList.isEmpty() && entryList.get(0).getAudioBuffer() != null);
bPlay.setEnabled(enable);
list.setEnabled(enable);
return true;
}
return false;
}
private void initGUI()
{
bPlay = new JButton("Play", Icons.getIcon(Icons.ICON_PLAY_16));
bPlay.addActionListener(this);
bEnd = new JButton("Finish", Icons.getIcon(Icons.ICON_END_16));
bEnd.setEnabled(false);
bEnd.addActionListener(this);
bStop = new JButton("Stop", Icons.getIcon(Icons.ICON_STOP_16));
bStop.setEnabled(false);
bStop.addActionListener(this);
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 6, 0));
buttonPanel.add(bPlay);
buttonPanel.add(bEnd);
buttonPanel.add(bStop);
list.setEnabled(false);
list.setBorder(BorderFactory.createLineBorder(UIManager.getColor("controlShadow")));
list.setFont(BrowserMenuBar.getInstance().getScriptFont());
playList = new JLabel("Playlist:");
JScrollPane scroll = new JScrollPane(list);
JPanel centerPanel = new JPanel();
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
centerPanel.setLayout(gbl);
gbc.insets = new Insets(3, 3, 3, 3);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbl.setConstraints(playList, gbc);
centerPanel.add(playList);
gbl.setConstraints(scroll, gbc);
centerPanel.add(scroll);
gbl.setConstraints(buttonPanel, gbc);
centerPanel.add(buttonPanel);
setLayout(new BorderLayout());
add(centerPanel, BorderLayout.CENTER);
}
public void stopPlay()
{
if (player != null) {
play = false;
player.stopPlay();
}
}
private synchronized void setClosed(boolean b)
{
if (b != closed) {
closed = b;
}
}
private synchronized boolean isClosed()
{
return closed;
}
}