/*
* Copyright (c) 2008, 2009, 2010, 2011 Denis Tulskiy
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @Author: Denis Tulskiy
* @Date: Oct 30, 2009
*/
package com.tulskiy.musique.system;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Mixer;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.metal.MetalFileChooserUI;
import javax.swing.plaf.metal.MetalIconFactory;
import com.tulskiy.musique.audio.AudioFileReader;
import com.tulskiy.musique.audio.Scrobbler;
import com.tulskiy.musique.audio.player.Player;
import com.tulskiy.musique.audio.player.io.AudioOutput;
import com.tulskiy.musique.gui.MainWindow;
import com.tulskiy.musique.playlist.PlaybackOrder;
import com.tulskiy.musique.playlist.PlaylistManager;
import com.tulskiy.musique.spi.PluginLoader;
import com.tulskiy.musique.system.configuration.Configuration;
import com.tulskiy.musique.util.Util;
public class Application {
private static Application ourInstance = new Application();
private final Logger logger = Logger.getLogger("com.tulskiy");
private Player player;
private Configuration configuration;
private PlaylistManager playlistManager;
private MainWindow mainWindow;
public final String VERSION = "Musique 0.3-SNAPSHOT";
public File CONFIG_HOME;
private File configFile;
private PluginLoader pluginLoader;
public static Application getInstance() {
return ourInstance;
}
private Application() {
initHome();
initLoggers();
logger.fine("Using '" + CONFIG_HOME + "' as a home directory");
}
private void initLoggers() {
LogManager.getLogManager().reset();
logger.setLevel(Level.FINE);
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINE);
Formatter formatter = new DefaultLogFormatter();
consoleHandler.setFormatter(formatter);
logger.addHandler(consoleHandler);
try {
FileHandler fileHandler = new FileHandler(new File(CONFIG_HOME, "musique.log").getAbsolutePath(), 10000, 1, true);
fileHandler.setFormatter(formatter);
logger.addHandler(fileHandler);
} catch (IOException e) {
logger.log(Level.WARNING, "Could not open file for logging", e);
}
}
private void initHome() {
String home = System.getenv("APPDATA");
if (Util.isEmpty(home)) {
home = System.getProperty("user.home");
}
CONFIG_HOME = new File(home, ".musique").getAbsoluteFile();
//noinspection ResultOfMethodCallIgnored
CONFIG_HOME.mkdirs();
configFile = new File(CONFIG_HOME, "config");
}
public void load() {
configuration = new Configuration();
try {
configuration.load(new FileReader(configFile));
} catch (FileNotFoundException ignored) {
}
if (configuration.getBoolean("system.oneInstance", false)
&& !tryLock()) {
JOptionPane.showMessageDialog(null, "Only one instance of Musique can be run at a time", VERSION, JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
player = new Player();
Scrobbler scrobbler = new Scrobbler();
scrobbler.start();
playlistManager = new PlaylistManager();
playlistManager.loadPlaylists();
pluginLoader = new PluginLoader();
pluginLoader.load();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
playlistManager.saveSettings();
try {
configuration.save(new FileWriter(configFile));
} catch (IOException e) {
logger.severe("Could not save configuration to " + configFile);
}
}
});
loadSettings();
}
private boolean tryLock() {
try {
RandomAccessFile randomFile = new RandomAccessFile(new File(CONFIG_HOME, "lock"), "rw");
FileChannel channel = randomFile.getChannel();
//we couldn't acquire lock as it is already locked by another program instance)
if (channel.tryLock() == null)
return false;
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
private void loadSettings() {
// System.setProperty("http.agent", "Mozilla/5.001 (windows; U; NT4.0; en-US; rv:1.0) Gecko/25250101");
AudioOutput audioOutput = player.getAudioOutput();
audioOutput.setVolume(configuration.getFloat("player.volume", 1));
String mixer = configuration.getString("player.mixer", null);
if (mixer != null) {
Mixer.Info[] infos = AudioSystem.getMixerInfo();
for (Mixer.Info info : infos) {
if (info.getName().equals(mixer)) {
audioOutput.setMixer(info);
break;
}
}
}
if (configuration.getBoolean("proxy.enabled", false)) {
System.setProperty("http.proxyHost", configuration.getString("proxy.host", null));
System.setProperty("http.proxyPort", configuration.getString("proxy.port", null));
}
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
String user = configuration.getString("proxy.user", null);
String password = configuration.getString("proxy.password", null);
if (user != null && password != null)
return new PasswordAuthentication(user, password.toCharArray());
else
return null;
}
});
configuration.addPropertyChangeListener("player.playbackOrder", true, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
int index = configuration.getInt(evt.getPropertyName(), 0);
player.getPlaybackOrder().setOrder(PlaybackOrder.Order.values()[index]);
}
});
UIManager.put("Slider.paintValue", Boolean.FALSE);
UIManager.put("FileChooser.readOnly", Boolean.TRUE);
UIManager.put("swing.boldMetal", Boolean.FALSE);
Object thumbWidth = configuration.get("gui.thumbWidth");
if (thumbWidth != null) {
try {
UIManager.put("Slider.thumbWidth", Integer.valueOf(thumbWidth.toString()));
} catch (NumberFormatException ignored) {
}
}
Charset charset = Charset.forName(configuration.getString("tag.defaultEncoding", "windows-1251"));
AudioFileReader.setDefaultCharset(charset);
try {
String laf = configuration.getString("gui.LAF", "");
if (laf.isEmpty()) {
laf = "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel";
}
UIManager.setLookAndFeel(laf);
} catch (Exception e) {
System.err.println("Could not load LaF: " + e.getCause());
}
configuration.addPropertyChangeListener("gui.LAF", true, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String laf = configuration.getString(evt.getPropertyName(), "");
if (laf.endsWith("GTKLookAndFeel")) {
UIManager.put("FileChooserUI", MetalFileChooserUI.class.getName());
UIManager.put("FileChooser.newFolderIcon", MetalIconFactory.getFileChooserNewFolderIcon());
UIManager.put("FileChooser.upFolderIcon", MetalIconFactory.getFileChooserUpFolderIcon());
UIManager.put("FileChooser.homeFolderIcon", MetalIconFactory.getFileChooserHomeFolderIcon());
UIManager.put("FileChooser.detailsViewIcon", MetalIconFactory.getFileChooserDetailViewIcon());
UIManager.put("FileChooser.listViewIcon", MetalIconFactory.getFileChooserListViewIcon());
} else {
UIManager.put("FileChooserUI", null);
}
// Font defaultFont = new Font("Sans Serif", 0, 11);
// UIManager.put("defaultFont", defaultFont);
// UIManager.put("Table.font", defaultFont);
// UIManager.put("Menu.font", defaultFont);
// UIManager.put("Button.font", defaultFont);
// UIManager.put("ComboBox.font", defaultFont);
// UIManager.put("Tree.font", defaultFont);
// UIManager.put("CheckBox.font", defaultFont);
// UIManager.put("TableHeader.font", defaultFont);
// UIManager.put("PopupMenu.font", defaultFont);
// UIManager.put("RadioButtonMenuItem.font", defaultFont);
// UIManager.put("RadioButton.font", defaultFont);
// UIManager.put("CheckBoxMenuItem.font", defaultFont);
// UIManager.put("TextField.font", defaultFont);
// UIManager.put("MenuItem.font", defaultFont);
// UIManager.put("Label.font", defaultFont);
// UIManager.put("TitledBorder.font", defaultFont.deriveFont(Font.BOLD));
// UIManager.put("TabbedPane.font", defaultFont);
// UIManager.put("TextArea.font", defaultFont);
}
});
}
public void start() {
try {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (mainWindow != null) {
mainWindow.shutdown();
mainWindow = null;
}
mainWindow = new MainWindow();
mainWindow.setVisible(true);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public void exit() {
player.stop();
if (mainWindow != null) {
mainWindow.shutdown();
}
pluginLoader.shutdown();
System.exit(0);
}
public Player getPlayer() {
return player;
}
public Configuration getConfiguration() {
return configuration;
}
public PlaylistManager getPlaylistManager() {
return playlistManager;
}
public PluginLoader getPluginLoader() {
return pluginLoader;
}
}