/*
* (c) Copyright 2009 Tim Jenkins
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* ITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package com.screenrunner;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.sql.Date;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Vector;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import com.screenrunner.data.I18n;
import com.screenrunner.data.Playlist;
import com.screenrunner.data.ScriptureList;
import com.screenrunner.data.SongList;
import com.screenrunner.data.Style;
import com.screenrunner.ui.*;
import cookxml.cookswing.CookSwing;
public class ScreenRunner {
public static final float VERSION = 0.1f;
public static final String VERSION_STRING = "0.1 pre-alpha";
public static Properties config;
private static String configFile = null;
private static boolean createConfig = false;
public static SongList songs = null;
private static String baseDir = null;
public static Style defaultStyle = null;
public static Style currentStyle = null;
public static CookSwing renderer = null;
public static Playlist playlist = null;
public static Logger log = null;
public static BufferedImage logo = null;
public static BufferedImage lockImg = null;
public static Dimension displaySize = new Dimension(1024, 768);
public static Point displayLocation = new Point(0, 0);
public static ScriptureList scriptures = null;
public static Vector<BufferedImage> icons = null;
public static void main(String[] args) {
initLogger();
try {
log.config("Setting System Look and Feel...");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
log.warning(I18n.get("sys/lnferror"));
}
icons = new Vector<BufferedImage>();
try {
icons.add(ImageIO.read(ScreenRunner.class.getClassLoader().getResource("com/screenrunner/ui/images/srlogo-128.png")));
icons.add(ImageIO.read(ScreenRunner.class.getClassLoader().getResource("com/screenrunner/ui/images/srlogo-48.png")));
icons.add(ImageIO.read(ScreenRunner.class.getClassLoader().getResource("com/screenrunner/ui/images/srlogo-32.png")));
icons.add(ImageIO.read(ScreenRunner.class.getClassLoader().getResource("com/screenrunner/ui/images/srlogo-16.png")));
} catch (IOException e) {
log.warning("IOException while reading image file: " + e.getMessage());
}
SplashScreen splash = new SplashScreen("com/screenrunner/ui/images/splash.png", VERSION_STRING, I18n.get("ui/splash/welcome"));
splash.setVisible(true);
splash.setStatusText(I18n.get("ui/splash/loadconfig"));
setDefaultConfig();
splash.setProgress(10);
splash.setStatusText(I18n.get("ui/splash/loadstyles"));
try {
log.config("Loading default style...");
InputStream is = ScreenRunner.class.getClassLoader().getResourceAsStream("com/screenrunner/data/default.srstyle");
defaultStyle = Style.fromXml(is);
currentStyle = Style.createDuplicate(defaultStyle);
} catch (FileNotFoundException e) {
log.severe("Unable to find the file: com/screenrunner/data/default.srstyle");
System.exit(1);
} catch (IOException e) {
log.severe("Unable to read the file: com/screenrunner/data/default.srstyle");
System.exit(1);
} catch (ParserConfigurationException e) {
log.severe("Unable to parse the file: com/screenrunner/data/default.srstyle");
System.exit(1);
} catch (SAXException e) {
log.severe("SAXException while parsing the file: com/screenrunner/data/default.srstyle");
log.severe("Exception Message: " + e.getMessage());
System.exit(1);
}
splash.setProgress(20);
playlist = new Playlist();
splash.setStatusText(I18n.get("ui/splash/loadconfig"));
parseArgs(args);
loadConfig();
splash.setProgress(30);
splash.setStatusText(I18n.get("ui/splash/initmainwindow"));
MainWindow mw = new MainWindow();
renderer = new CookSwing(mw);
renderer.setUserStringHook(I18n.getStringHook());
JFrame f = (JFrame)renderer.render("com/screenrunner/ui/xml/MainWindow.xml");
mw.initWindow();
f.setIconImages(icons);
splash.setProgress(50);
int w = Integer.parseInt(config.getProperty("window-width"));
int h = Integer.parseInt(config.getProperty("window-height"));
f.setSize(w, h);
splash.setProgress(60);
splash.setStatusText(I18n.get("ui/splash/loadsongs"));
try {
log.config("Loading songs...");
songs = SongList.fromSongDirectory(splash, 60, 80);
log.config("Loaded " + Integer.toString(songs.size())+ " songs.");
} catch (Exception e) {
e.printStackTrace();
}
splash.setProgress(80);
splash.setStatusText(I18n.get("ui/splash/loadscriptures"));
scriptures = ScriptureList.FromDirectory(getScriptureDir().getAbsolutePath(), splash, 80, 90);
splash.setStatusText(I18n.get("ui/splash/initdispwindow"));
String tempstr = config.getProperty("display-screen");
int dispnum = Display.getSecondaryScreenIndex();
if(dispnum == -1) dispnum = Display.getPrimaryScreenIndex();
if(tempstr != null && tempstr.trim().length() > 0) {
try {
dispnum = Integer.parseInt(tempstr);
} catch (NumberFormatException e) { }
}
int wmode = Display.getWindowMode();
tempstr = config.getProperty("display-window-mode");
if(tempstr != null && tempstr.trim().length() > 0) {
try {
wmode = Integer.parseInt(tempstr);
} catch (NumberFormatException e) { }
}
Display.setCurrentDisplayScreen(dispnum);
Display.setWindowMode(wmode);
mw.presentationPreviewPanel.add(Display.getDisplay().getPreviewComponent(), BorderLayout.CENTER);
URL lockUrl = ScreenRunner.class.getClassLoader().getResource("com/screenrunner/ui/images/padlock.png");
try {
lockImg = ImageIO.read(lockUrl);
} catch (IOException e) {
e.printStackTrace();
}
BufferedImage tempimg = new BufferedImage(48, 48, BufferedImage.TYPE_INT_ARGB);
while(!tempimg.getGraphics().drawImage(lockImg, 0, 0, 48, 48, null)) continue;
splash.setStatusText(I18n.get("ui/splash/starting"));
log.config("Done with initialization. Starting main window.");
f.setLocationRelativeTo(null);
f.setVisible(true);
splash.setProgress(100);
splash.setVisible(false);
}
private static void parseArgs(String[] args) {
for(int i = 0; i < args.length; i++) {
if(args[i].equalsIgnoreCase("--create-config")) {
createConfig = true;
log.fine("Creating new default configuration...");
}
else if(args[i].startsWith("--config=")) {
String[] s = args[i].split("=", 2);
configFile = s[1];
log.fine("Using config file: " + s[1]);
}
else if(args[i].startsWith("--base=")) {
String[] s = args[i].split("=", 2);
baseDir = s[1];
log.fine("Using base directory: " + s[1]);
}
else if(args[i].startsWith("--lang=")) {
String[] s = args[i].split("=", 2);
I18n.load(s[1]);
log.fine("Using laguage file: " + s[1]);
}
else if(args[i].startsWith("--playlist=")) {
String[] s = args[i].split("=", 2);
playlist.loadFrom(s[1]);
log.fine("Loading playlist file: " + s[1]);
}
else if(args[i].startsWith("--debug=")) {
String[] s = args[i].split("=", 2);
try {
log.setLevel(Level.parse(s[1]));
log.config("Logging level set to: " + log.getLevel().getName());
} catch (Exception e) { }
}
else {
log.warning(I18n.get("sys/cfg/badopt", args[i]));
}
}
if(createConfig) {
saveConfig();
}
}
public static File getBaseDir() {
if(baseDir == null) {
baseDir = System.getProperty("user.home");
if(!baseDir.endsWith(File.separator))
baseDir = baseDir + File.separator;
baseDir = baseDir + "ScreenRunner" + File.separator;
} else {
File f = new File(baseDir);
baseDir = f.getAbsolutePath();
if(!baseDir.endsWith(File.separator))
baseDir = baseDir + File.separator;
}
File baseDirFile = new File(baseDir);
if(!baseDirFile.exists()) {
log.info(I18n.get("sys/dir/creating", baseDir));
if(!baseDirFile.mkdirs()) {
log.severe(I18n.get("sys/dir/createfail", baseDir));
System.exit(1);
}
}
return baseDirFile;
}
public static File getAppDir() {
URL loc = ScreenRunner.class.getProtectionDomain().getCodeSource().getLocation();
try {
return new File(loc.toURI());
} catch (URISyntaxException e) {
e.printStackTrace();
return null;
}
}
public static File getScriptureDir() {
String base = getAppDir().getAbsolutePath();
File scriptures = new File(base + (base.endsWith(File.separator) ? "" : File.separator) + "Scriptures");
if(!scriptures.exists()) {
scriptures.mkdirs();
if(!scriptures.exists()) {
log.severe(I18n.get("song/dircreatefail", scriptures.getAbsolutePath()));
System.exit(1);
}
}
return scriptures;
}
public static File getSongDir() {
String base = getBaseDir().getAbsolutePath();
File songs = new File(base + (base.endsWith(File.separator) ? "" : File.separator) + "Songs");
if(!songs.exists()) {
songs.mkdirs();
if(!songs.exists()) {
log.severe(I18n.get("song/dircreatefail", songs.getAbsolutePath()));
System.exit(1);
}
}
return songs;
}
private static String[] listDirContents(String path, String relativeTo) {
if(!path.endsWith(File.separator)) path += File.separator;
if(!relativeTo.endsWith(File.separator)) relativeTo += File.separator;
ArrayList<String> outFiles = new ArrayList<String>();
File dir = new File(path);
String[] files = dir.list();
for(int i = 0; i < files.length; i++) {
File f = new File(path + files[i]);
if(f.isDirectory()) {
String[] subdir = listDirContents(path + files[i], relativeTo);
for(int j = 0; j < subdir.length; j++) {
outFiles.add(subdir[j]);
}
} else {
String fp = path + files[i];
fp = fp.replace(relativeTo, "");
outFiles.add(fp);
}
}
return outFiles.toArray(new String[outFiles.size()]);
}
public static String[] getSongFileList() {
String dir = getSongDir().getAbsolutePath();
String[] songs = listDirContents(dir, dir);
return songs;
}
public static File getSongIndexFile() {
return new File(getBaseDir().getAbsolutePath() + "/songs.index");
}
private static String getConfigFile() {
String path = getBaseDir().getAbsolutePath();
if(!path.endsWith(File.separator)) path += File.separator;
if(configFile == null || configFile.length() == 0) {
configFile = path + "screenrunner.cfg";
}
return configFile;
}
private static void setDefaultConfig() {
Properties defs = new Properties();
defs.setProperty("window-width", "750");
defs.setProperty("window-height", "500");
config = new Properties(defs);
}
public static void loadConfig() {
try {
config.load(new FileReader(getConfigFile()));
} catch (FileNotFoundException e) {
log.warning(I18n.get("sys/cfg/notfound", getConfigFile()));
return;
} catch (IOException e) {
log.severe(I18n.get("sys/cfg/loaderror", getConfigFile()));
System.exit(1);
}
}
public static void saveConfig() {
try {
config.store(new FileWriter(getConfigFile()), "ScreenRunner " + Float.toString(VERSION));
if(songs.isIndexModified()) {
songs.saveIndex(getSongIndexFile().getAbsolutePath());
}
} catch (IOException e) {
log.severe(I18n.get("sys/cfg/saveerror", getConfigFile()));
e.printStackTrace();
System.exit(1);
}
}
private static void initLogger() {
log = Logger.getLogger("com.screenrunner");
log.setLevel(Level.WARNING);
log.addHandler(new Handler() {
@Override
public void close() throws SecurityException { }
@Override
public void flush() { System.out.flush(); }
@Override
public void publish(LogRecord record) {
System.out.println(buildString(record));
}
private String buildString(LogRecord r) {
StringBuilder sb = new StringBuilder();
Date d = new Date(r.getMillis());
sb.append("[" + d.toString() + " - " + r.getLevel().getName() + "] ");
if(r.getSourceClassName() != null) sb.append(r.getSourceClassName() + ": ");
if(r.getSourceMethodName() != null) {
sb.append(r.getSourceMethodName() + "(");
sb.append("): ");
}
sb.append(r.getMessage());
return sb.toString();
}
});
}
}