Startup cleanup. Moved the entire swing application startup into a

single class.  Created BasicApplication as a simple way to initialize
little applications.  Pulled the dependency on WatcherService out from
DecalImage.
This commit is contained in:
kruland2607 2013-05-12 20:26:22 -05:00
parent d1ea73a455
commit ae7b2b3af1
41 changed files with 1146 additions and 1343 deletions

View File

@ -27,7 +27,7 @@
<property name="dist.src" value="${jar.dir}/${pkgname}-src.zip"/>
<!-- The main class of the application -->
<property name="main-class" value="net.sf.openrocket.startup.Startup"/>
<property name="main-class" value="net.sf.openrocket.startup.JiJStartup"/>
<property name="expanded-libs" value="${lib.dir}/miglayout15-swing.jar"/>

View File

@ -1,8 +0,0 @@
<configuration debug="false">
<appender name="buffer"
class="net.sf.openrocket.logging.LogbackBufferLoggerAdaptor">
</appender>
<root level="TRACE">
<appender-ref ref="buffer" />
</root>
</configuration>

View File

@ -13,6 +13,7 @@ public interface DecalImage extends ChangeSource, Comparable<DecalImage> {
public InputStream getBytes() throws FileNotFoundException, IOException;
public void exportImage(File file, boolean watchForChanges) throws IOException;
public void exportImage(File file) throws IOException;
public void fireChangeEvent(Object source);
}

View File

@ -33,8 +33,11 @@ class ResourceDecalImage implements DecalImage {
}
@Override
public void exportImage(File file, boolean watchForChanges) throws IOException {
public void exportImage(File file) throws IOException {
}
@Override
public void fireChangeEvent(Object source) {
}
@Override

View File

@ -11,30 +11,16 @@ import org.slf4j.LoggerFactory;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.startup.Application;
public abstract class ComponentPresetDatabase extends Database<ComponentPreset> implements ComponentPresetDao {
public class ComponentPresetDatabase extends Database<ComponentPreset> implements ComponentPresetDao {
private static final Logger logger = LoggerFactory.getLogger(ComponentPresetDatabase.class);
private volatile boolean startedLoading = false;
private volatile boolean endedLoading = false;
private final boolean asynchronous;
/** Set to true the first time {@link #blockUntilLoaded()} is called. */
protected volatile boolean inUse = false;
public ComponentPresetDatabase() {
super();
this.asynchronous = false;
}
public ComponentPresetDatabase(boolean asynchronous ) {
super();
this.asynchronous = asynchronous;
}
@Override
public List<ComponentPreset> listAll() {
blockUntilLoaded();
return list;
}
@ -45,7 +31,6 @@ public abstract class ComponentPresetDatabase extends Database<ComponentPreset>
@Override
public List<ComponentPreset> listForType( ComponentPreset.Type type ) {
blockUntilLoaded();
if ( type == null ) {
return Collections.<ComponentPreset>emptyList();
}
@ -71,8 +56,6 @@ public abstract class ComponentPresetDatabase extends Database<ComponentPreset>
*/
@Override
public List<ComponentPreset> listForType( ComponentPreset.Type type, boolean favorite ) {
blockUntilLoaded();
if ( !favorite ) {
return listForType(type);
}
@ -91,8 +74,6 @@ public abstract class ComponentPresetDatabase extends Database<ComponentPreset>
@Override
public List<ComponentPreset> listForTypes( ComponentPreset.Type ... type ) {
blockUntilLoaded();
if( type == null || type.length == 0 ) {
return Collections.<ComponentPreset>emptyList();
}
@ -118,13 +99,11 @@ public abstract class ComponentPresetDatabase extends Database<ComponentPreset>
@Override
public List<ComponentPreset> listForTypes( List<ComponentPreset.Type> types ) {
blockUntilLoaded();
return listForTypes( (ComponentPreset.Type[]) types.toArray() );
}
@Override
public List<ComponentPreset> find(String manufacturer, String partNo) {
blockUntilLoaded();
List<ComponentPreset> presets = new ArrayList<ComponentPreset>();
for( ComponentPreset preset : list ) {
if ( preset.getManufacturer().getSimpleName().equals(manufacturer) && preset.getPartNo().equals(partNo) ) {
@ -136,75 +115,8 @@ public abstract class ComponentPresetDatabase extends Database<ComponentPreset>
@Override
public void setFavorite( ComponentPreset preset, ComponentPreset.Type type, boolean favorite ) {
blockUntilLoaded();
Application.getPreferences().setComponentFavorite( preset, type, favorite );
this.fireAddEvent(preset);
}
/**
* Used for loading the component preset database. This method will be called in a background
* thread to load the presets asynchronously.
*/
protected abstract void load();
/**
* Start loading the presets.
*
* @throws IllegalStateException if this method has already been called.
*/
public void startLoading() {
if (startedLoading) {
throw new IllegalStateException("Already called startLoading");
}
startedLoading = true;
if (asynchronous) {
new LoadingThread().start();
} else {
load();
}
synchronized (this) {
endedLoading = true;
this.notifyAll();
}
}
/**
* Background thread for loading the presets.
*/
private class LoadingThread extends Thread {
private LoadingThread() {
this.setName("PresetLoadingThread");
this.setPriority(MIN_PRIORITY);
}
@Override
public void run() {
load();
}
}
/**
* Block the current thread until loading of the presets has been completed.
*
* @throws IllegalStateException if startLoading() has not been called.
*/
public void blockUntilLoaded() {
inUse = true;
if (!startedLoading) {
throw new IllegalStateException("startLoading() has not been called");
}
if (!endedLoading) {
synchronized (this) {
while (!endedLoading) {
try {
this.wait();
} catch (InterruptedException e) {
logger.warn("InterruptedException occurred, ignoring", e);
}
}
}
}
}
}

View File

@ -35,8 +35,6 @@ import org.slf4j.LoggerFactory;
public class DecalRegistry {
private static Logger log = LoggerFactory.getLogger(DecalRegistry.class);
private WatchService watchService = Application.getWatchService();
DecalRegistry() {
}
@ -121,6 +119,11 @@ public class DecalRegistry {
return name != null ? name : delegate.getName();
}
@Override
public void fireChangeEvent(Object source) {
delegate.fireChangeEvent(source);
}
/**
* This function returns an InputStream backed by a byte[] containing the decal pixels.
* If it reads in the bytes from an actual file, the underlying file is closed.
@ -147,7 +150,7 @@ public class DecalRegistry {
}
@Override
public void exportImage(File file, boolean watchForChanges) throws IOException {
public void exportImage(File file) throws IOException {
try {
InputStream is = getBytes();
OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
@ -159,19 +162,6 @@ public class DecalRegistry {
this.fileSystemLocation = file;
if (watchForChanges) {
watchService.register(new FileWatcher(this.fileSystemLocation) {
@Override
public void handleEvent(WatchEvent evt) {
DecalImageImpl.this.delegate.fireChangeEvent();
//System.out.println(this.getFile() + " has changed");
}
});
}
} catch (IOException iex) {
throw new BugException(iex);
}

View File

@ -100,7 +100,7 @@ public class ExportDecalDialog extends JDialog {
private void export(DecalImage decal, File selectedFile) {
try {
decal.exportImage(selectedFile, false);
decal.exportImage(selectedFile);
} catch (IOException iex) {
String message = MessageFormat.format(trans.get("ExportDecalDialog.exception"), selectedFile.getAbsoluteFile());
JOptionPane.showMessageDialog(this, message, "", JOptionPane.ERROR_MESSAGE);

View File

@ -11,8 +11,7 @@ import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.gui.adaptors.DoubleModel;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.l10n.ResourceBundleTranslator;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.startup.BasicApplication;
import net.sf.openrocket.unit.UnitGroup;
public class Tester {
@ -20,7 +19,8 @@ public class Tester {
public static void main(String[] args) throws InterruptedException, InvocationTargetException {
Application.setBaseTranslator(new ResourceBundleTranslator("l10n.messages"));
BasicApplication baseApp = new BasicApplication();
baseApp.initializeApplication();
GUIUtil.setBestLAF();

View File

@ -52,6 +52,8 @@ import net.sf.openrocket.util.StateChangeListener;
public class AppearancePanel extends JPanel {
private static final Translator trans = Application.getTranslator();
private EditDecalHelper editDecalHelper = Application.getInjector().getInstance(EditDecalHelper.class);
private AppearanceBuilder ab;
// We hang on to the user selected appearance when switching to default appearance.
@ -269,7 +271,7 @@ public class AppearancePanel extends JPanel {
@Override
public void actionPerformed(ActionEvent e) {
try {
EditDecalHelper.editDecal(SwingUtilities.getWindowAncestor(AppearancePanel.this), document, c, ab.getImage());
editDecalHelper.editDecal(SwingUtilities.getWindowAncestor(AppearancePanel.this), document, c, ab.getImage());
} catch (EditDecalHelperException ex) {
JOptionPane.showMessageDialog(AppearancePanel.this, ex.getMessage(), "", JOptionPane.ERROR_MESSAGE);
}

View File

@ -1,19 +1,15 @@
package net.sf.openrocket.gui.preset;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.gui.util.FileHelper;
import net.sf.openrocket.gui.util.Icons;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.ResourceBundleTranslator;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.logging.Markers;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.loader.MaterialHolder;
import net.sf.openrocket.preset.loader.RocksimComponentFileTranslator;
import net.sf.openrocket.preset.xml.OpenRocketComponentDTO;
import net.sf.openrocket.preset.xml.OpenRocketComponentSaver;
import net.sf.openrocket.startup.Application;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
@ -34,20 +30,23 @@ import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.xml.bind.JAXBException;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.gui.util.FileHelper;
import net.sf.openrocket.gui.util.Icons;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.logging.Markers;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.loader.MaterialHolder;
import net.sf.openrocket.preset.loader.RocksimComponentFileTranslator;
import net.sf.openrocket.preset.xml.OpenRocketComponentDTO;
import net.sf.openrocket.preset.xml.OpenRocketComponentSaver;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.startup.BasicApplication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* A UI for editing component presets. Currently this is a standalone application - run the main within this class.
* TODO: Full I18n TODO: Save As .csv
@ -59,11 +58,6 @@ public class ComponentPresetEditor extends JPanel implements PresetResultListene
*/
private static final Logger log = LoggerFactory.getLogger(ComponentPresetEditor.class);
/**
* The I18N translator.
*/
private static Translator trans = null;
/**
* The table of presets.
*/
@ -76,10 +70,6 @@ public class ComponentPresetEditor extends JPanel implements PresetResultListene
private final OpenedFileContext editContext = new OpenedFileContext();
static {
trans = Application.getTranslator();
}
/**
* Create the panel.
*
@ -89,7 +79,7 @@ public class ComponentPresetEditor extends JPanel implements PresetResultListene
setLayout(new MigLayout("", "[82.00px, grow][168.00px, grow][84px, grow][117.00px, grow][][222px]",
"[346.00px, grow][29px]"));
model = new DataTableModel(new String[]{"Manufacturer", "Type", "Part No", "Description", ""});
model = new DataTableModel(new String[] { "Manufacturer", "Type", "Part No", "Description", "" });
table = new JTable(model);
table.getTableHeader().setFont(new JLabel().getFont());
@ -155,10 +145,10 @@ public class ComponentPresetEditor extends JPanel implements PresetResultListene
* presets, b) save them before reading in another component file, or c) merge the read component file
* with the current contents of the table model.
*/
Object[] options = {"Save",
Object[] options = { "Save",
"Merge",
"Discard",
"Cancel"};
"Cancel" };
int n = JOptionPane.showOptionDialog(frame,
"The editor contains existing component presets. What would you like to do with them?",
"Existing Component Presets",
@ -239,8 +229,8 @@ public class ComponentPresetEditor extends JPanel implements PresetResultListene
String description = preset.has(ComponentPreset.DESCRIPTION) ? preset.get(ComponentPreset.DESCRIPTION) :
preset.getPartNo();
if (!editContext.isEditingSelected() || table.getSelectedRow() == -1) {
myModel.addRow(new Object[]{preset.getManufacturer().getDisplayName(), preset.getType().name(),
preset.getPartNo(), description, Icons.EDIT_DELETE}, preset);
myModel.addRow(new Object[] { preset.getManufacturer().getDisplayName(), preset.getType().name(),
preset.getPartNo(), description, Icons.EDIT_DELETE }, preset);
}
else {
//This is a modified preset; update all of the columns and the stored associated instance.
@ -259,18 +249,16 @@ public class ComponentPresetEditor extends JPanel implements PresetResultListene
* Launch the test main.
*/
public static void main(String[] args) {
BasicApplication app = new BasicApplication();
app.initializeApplication();
try {
trans = new ResourceBundleTranslator("l10n.messages");
net.sf.openrocket.startup.Application.setBaseTranslator(trans);
Application.setPreferences(new SwingPreferences());
// FIXME - Application.setPreferences(new SwingPreferences());
JFrame dialog = new JFrame();
dialog.getContentPane().add(new ComponentPresetEditor(dialog));
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.pack();
dialog.setVisible(true);
}
catch (Exception e) {
} catch (Exception e) {
e.printStackTrace();
}
}
@ -381,8 +369,7 @@ public class ComponentPresetEditor extends JPanel implements PresetResultListene
}
editContext.setOpenedFile(file);
}
}
catch (Exception e) {
} catch (Exception e) {
String fileName = (file == null) ? "(file is null, can't get name)" : file.getName();
JOptionPane.showMessageDialog(ComponentPresetEditor.this, "Unable to open OpenRocket component file: " +
fileName + " Invalid format. " + e.getMessage());
@ -396,8 +383,7 @@ public class ComponentPresetEditor extends JPanel implements PresetResultListene
private boolean saveAndHandleError() {
try {
return saveAsORC();
}
catch (Exception e1) {
} catch (Exception e1) {
JOptionPane.showMessageDialog(ComponentPresetEditor.this, e1.getLocalizedMessage(),
"Error saving ORC file.", JOptionPane.ERROR_MESSAGE);
return false;

View File

@ -10,12 +10,25 @@ import net.sf.openrocket.appearance.AppearanceBuilder;
import net.sf.openrocket.appearance.DecalImage;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.gui.dialogs.EditDecalDialog;
import net.sf.openrocket.gui.watcher.FileWatcher;
import net.sf.openrocket.gui.watcher.WatchEvent;
import net.sf.openrocket.gui.watcher.WatchService;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
import com.google.inject.Inject;
public class EditDecalHelper {
@Inject
private WatchService watchService;
@Inject
private Translator trans;
@Inject
private SwingPreferences prefs;
public static class EditDecalHelperException extends Exception {
private String extraMessage = "";
@ -43,11 +56,7 @@ public class EditDecalHelper {
}
private static final Translator trans = Application.getTranslator();
private static final SwingPreferences prefs = ((SwingPreferences) Application.getPreferences());
public static void editDecal(Window parent, OpenRocketDocument doc, RocketComponent component, DecalImage decal) throws EditDecalHelperException {
public void editDecal(Window parent, OpenRocketDocument doc, RocketComponent component, DecalImage decal) throws EditDecalHelperException {
boolean sysPrefSet = prefs.isDecalEditorPreferenceSet();
int usageCount = doc.countDecalUsage(decal);
@ -102,7 +111,7 @@ public class EditDecalHelper {
return newImage;
}
private static void launchEditor(boolean useSystemEditor, String commandTemplate, DecalImage decal) throws EditDecalHelperException {
private void launchEditor(boolean useSystemEditor, String commandTemplate, final DecalImage decal) throws EditDecalHelperException {
String decalId = decal.getName();
// Create Temp File.
@ -121,7 +130,18 @@ public class EditDecalHelper {
}
try {
decal.exportImage(tmpFile, true);
decal.exportImage(tmpFile);
watchService.register(new FileWatcher(tmpFile) {
@Override
public void handleEvent(WatchEvent evt) {
decal.fireChangeEvent(evt);
//System.out.println(this.getFile() + " has changed");
}
});
} catch (IOException ioex) {
String message = MessageFormat.format(trans.get("EditDecalHelper.createFileException"), tmpFile.getAbsoluteFile());
throw new EditDecalHelperException(message, ioex);

View File

@ -29,7 +29,7 @@ public class LoggingSystemSetup {
appender.setContext(context);
PatternLayoutEncoder layout = new PatternLayoutEncoder();
layout.setContext(context);
layout.setPattern("%-8relative %-5marker %-5level [%thread] %logger{2} - %message%n%caller{2, BAD}");
layout.setPattern("%-8relative %-5marker %-5level [%thread] %logger{2} - %message%n");
layout.start();
appender.setEncoder(layout);
appender.start();

View File

@ -1,19 +1,17 @@
package net.sf.openrocket.preset.loader;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.xml.OpenRocketComponentSaver;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.startup.GuiceStartup;
import net.sf.openrocket.util.ArrayList;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintStream;
import java.io.StringReader;
import java.util.List;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.xml.OpenRocketComponentSaver;
import net.sf.openrocket.startup.BasicApplication;
import net.sf.openrocket.util.ArrayList;
public class RocksimComponentFileTranslator {
private static PrintStream LOGGER = System.err;
@ -26,6 +24,9 @@ public class RocksimComponentFileTranslator {
public static void main(String[] args) throws Exception {
BasicApplication app = new BasicApplication();
app.initializeApplication();
// How to control logging?
if (args.length < 2 || args.length > 2) {
@ -37,9 +38,6 @@ public class RocksimComponentFileTranslator {
LOGGER.println("Loading csv files from directory " + args[0]);
GuiceStartup.initializeLogging();
Application.setPreferences(new SwingPreferences());
MaterialHolder materialMap = loadAll(allPresets, new File(args[0]));
LOGGER.println("\tMarshalling to XML");
String xml = new OpenRocketComponentSaver().marshalToOpenRocketComponent(new ArrayList<Material>(materialMap.values()), allPresets);

View File

@ -3,9 +3,7 @@ package net.sf.openrocket.startup;
import net.sf.openrocket.database.ComponentPresetDao;
import net.sf.openrocket.database.motor.MotorDatabase;
import net.sf.openrocket.database.motor.ThrustCurveMotorSetDatabase;
import net.sf.openrocket.gui.watcher.WatchService;
import net.sf.openrocket.l10n.ClassBasedTranslator;
import net.sf.openrocket.l10n.DebugTranslator;
import net.sf.openrocket.l10n.ExceptionSuppressingTranslator;
import net.sf.openrocket.l10n.Translator;
@ -18,12 +16,6 @@ import com.google.inject.Injector;
*/
public final class Application {
private static Translator baseTranslator = new DebugTranslator(null);
private static ComponentPresetDao componentPresetDao;
private static Preferences preferences;
private static ExceptionHandler exceptionHandler;
private static Injector injector;
@ -40,44 +32,28 @@ public final class Application {
return false;
}
public static WatchService getWatchService() {
return Application.injector.getInstance(WatchService.class);
private static Translator getBaseTranslator() {
return injector.getInstance(Translator.class);
}
/**
* Return the translator to use for obtaining translated strings.
* @return a translator.
*/
public static Translator getTranslator() {
Translator t = baseTranslator;
Translator t = getBaseTranslator();
t = new ClassBasedTranslator(t, 1);
t = new ExceptionSuppressingTranslator(t);
return t;
}
/**
* Set the translator used in obtaining translated strings.
* @param translator the translator to set.
*/
public static void setBaseTranslator(Translator translator) {
Application.baseTranslator = translator;
}
/**
* @return the preferences
*/
public static Preferences getPreferences() {
return preferences;
return injector.getInstance(Preferences.class);
}
/**
* @param preferences the preferences to set
*/
public static void setPreferences(Preferences preferences) {
Application.preferences = preferences;
}
/**
* @return the exceptionHandler
@ -114,15 +90,12 @@ public final class Application {
}
@Deprecated
public static ComponentPresetDao getComponentPresetDao() {
return componentPresetDao;
return injector.getInstance(ComponentPresetDao.class);
}
public static void setComponentPresetDao(ComponentPresetDao componentPresetDao) {
Application.componentPresetDao = componentPresetDao;
}
public static Injector getInjector() {
return injector;
}

View File

@ -1,21 +0,0 @@
package net.sf.openrocket.startup;
import net.sf.openrocket.formatting.RocketDescriptor;
import net.sf.openrocket.formatting.RocketDescriptorImpl;
import net.sf.openrocket.gui.watcher.WatchService;
import net.sf.openrocket.gui.watcher.WatchServiceImpl;
import net.sf.openrocket.l10n.Translator;
import com.google.inject.AbstractModule;
public class ApplicationModule extends AbstractModule {
@Override
protected void configure() {
bind(Preferences.class).toInstance(Application.getPreferences());
bind(Translator.class).toInstance(Application.getTranslator());
bind(WatchService.class).to(WatchServiceImpl.class);
bind(RocketDescriptor.class).to(RocketDescriptorImpl.class);
}
}

View File

@ -1,25 +0,0 @@
package net.sf.openrocket.startup;
import net.sf.openrocket.database.motor.MotorDatabase;
import net.sf.openrocket.database.motor.ThrustCurveMotorSetDatabase;
import com.google.inject.AbstractModule;
import com.google.inject.Provider;
public class ApplicationModule2 extends AbstractModule {
private final Provider<ThrustCurveMotorSetDatabase> motorDatabaseProvider;
public ApplicationModule2(Provider<ThrustCurveMotorSetDatabase> motorDatabaseProvider) {
this.motorDatabaseProvider = motorDatabaseProvider;
}
@Override
protected void configure() {
bind(ThrustCurveMotorSetDatabase.class).toProvider(motorDatabaseProvider);
bind(MotorDatabase.class).toProvider(motorDatabaseProvider);
}
}

View File

@ -0,0 +1,28 @@
package net.sf.openrocket.startup;
import net.sf.openrocket.plugin.PluginModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* Simple class which can be used to build basic applications.
*
* It initializes the Application object with a Guice Injector configured with
* the CoreServicesModule and PluginModule.
*
* @author kruland
*
*/
public class BasicApplication {
public final void initializeApplication() {
Module applicationModule = new CoreServicesModule();
Module pluginModule = new PluginModule();
Injector injector = Guice.createInjector(applicationModule, pluginModule);
Application.setInjector(injector);
}
}

View File

@ -0,0 +1,32 @@
package net.sf.openrocket.startup;
import net.sf.openrocket.database.ComponentPresetDatabase;
import net.sf.openrocket.l10n.Translator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
public class BlockingComponentPresetDatabaseProvider implements Provider<ComponentPresetDatabase> {
private final static Logger log = LoggerFactory.getLogger(BlockingComponentPresetDatabaseProvider.class);
@Inject
private Translator trans;
private final ComponentPresetDatabaseLoader loader;
public BlockingComponentPresetDatabaseProvider(ComponentPresetDatabaseLoader loader) {
this.loader = loader;
}
@Override
public ComponentPresetDatabase get() {
loader.blockUntilLoaded();
return loader.getDatabase();
}
}

View File

@ -1,4 +1,4 @@
package net.sf.openrocket.gui.util;
package net.sf.openrocket.startup;
import java.awt.SplashScreen;
import java.awt.event.ActionEvent;
@ -13,8 +13,8 @@ import javax.swing.Timer;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.database.motor.ThrustCurveMotorSetDatabase;
import net.sf.openrocket.gui.main.Splash;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.MotorDatabaseLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -0,0 +1,103 @@
package net.sf.openrocket.startup;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.Collection;
import java.util.List;
import net.sf.openrocket.database.AsynchronousDatabaseLoader;
import net.sf.openrocket.database.ComponentPresetDatabase;
import net.sf.openrocket.file.iterator.DirectoryIterator;
import net.sf.openrocket.file.iterator.FileIterator;
import net.sf.openrocket.gui.util.SimpleFileFilter;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.xml.OpenRocketComponentLoader;
import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ComponentPresetDatabaseLoader extends AsynchronousDatabaseLoader {
private final static Logger log = LoggerFactory.getLogger(ComponentPresetDatabaseLoader.class);
private static final String SYSTEM_PRESET_DIR = "datafiles/presets";
private int fileCount = 0;
private int presetCount = 0;
private final ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase();
public ComponentPresetDatabaseLoader() {
super(0);
}
/**
* Returns the loaded database. If the database has not fully loaded,
* this blocks until it is.
*
* @return the motor database
*/
public ComponentPresetDatabase getDatabase() {
blockUntilLoaded();
return componentPresetDao;
}
@Override
protected void loadDatabase() {
long startTime = System.currentTimeMillis();
log.info("Loading component presets from " + SYSTEM_PRESET_DIR);
FileIterator iterator = DirectoryIterator.findDirectory(SYSTEM_PRESET_DIR, new SimpleFileFilter("", false, "ser"));
if (iterator != null) {
while (iterator.hasNext()) {
Pair<String, InputStream> f = iterator.next();
try {
ObjectInputStream ois = new ObjectInputStream(f.getV());
List<ComponentPreset> list = (List<ComponentPreset>) ois.readObject();
componentPresetDao.addAll(list);
fileCount++;
presetCount += list.size();
} catch (Exception ex) {
throw new BugException(ex);
}
}
}
SimpleFileFilter orcFilter = new SimpleFileFilter("", false, "orc");
try {
iterator = new DirectoryIterator(
((SwingPreferences) Application.getPreferences()).getDefaultUserComponentDirectory(),
orcFilter,
true);
} catch (IOException ioex) {
iterator = null;
log.debug("Error opening UserComponentDirectory", ioex);
}
if (iterator != null) {
while (iterator.hasNext()) {
Pair<String, InputStream> f = iterator.next();
Collection<ComponentPreset> presets = loadFile(f.getU(), f.getV());
componentPresetDao.addAll(presets);
fileCount++;
presetCount += presets.size();
}
}
long end = System.currentTimeMillis();
log.debug("Time to load presets: " + (end - startTime) + "ms " + presetCount + " loaded from " + fileCount + " files");
}
private Collection<ComponentPreset> loadFile(String fileName, InputStream stream) {
log.debug("loading from file: " + fileName);
OpenRocketComponentLoader loader = new OpenRocketComponentLoader();
Collection<ComponentPreset> presets = loader.load(stream, fileName);
return presets;
}
}

View File

@ -1,171 +0,0 @@
package net.sf.openrocket.startup;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.openrocket.database.ComponentPresetDatabase;
import net.sf.openrocket.file.iterator.DirectoryIterator;
import net.sf.openrocket.file.iterator.FileIterator;
import net.sf.openrocket.gui.util.SimpleFileFilter;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.xml.OpenRocketComponentLoader;
import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.Pair;
public class ConcurrentComponentPresetDatabaseLoader {
private static final Logger log = LoggerFactory.getLogger(ConcurrentComponentPresetDatabaseLoader.class);
private static final String SYSTEM_PRESET_DIR = "datafiles/presets";
private final CountDownLatch latch = new CountDownLatch(1);
private final ComponentPresetDatabase componentPresetDao;
private final ExecutorService writerPool;
private final ExecutorService loaderPool;
private final Thread workGenerator;
private FileIterator iterator;
private long startTime;
private long fileCount = 0;
private long presetCount = 0;
ConcurrentComponentPresetDatabaseLoader( ComponentPresetDatabase componentPresetDao ) {
this.componentPresetDao = componentPresetDao;
writerPool = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r,"PresetWriterThread");
return t;
}
});
loaderPool = Executors.newFixedThreadPool(3, new ThreadFactory() {
int threadCount = 0;
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r,"PresetLoaderPool-" + threadCount++);
t.setPriority(Thread.MIN_PRIORITY);
return t;
}
});
workGenerator = new Thread( new WorkGenerator(),"PresetGeneratorThread");
}
public void load() {
startTime = System.currentTimeMillis();
workGenerator.start();
}
public void await() throws InterruptedException {
latch.await();
loaderPool.shutdown();
loaderPool.awaitTermination(200, TimeUnit.SECONDS);
writerPool.shutdown();
writerPool.awaitTermination(200, TimeUnit.SECONDS);
if ( iterator != null ) {
iterator.close();
}
long end = System.currentTimeMillis();
log.debug("Time to load presets: " + (end-startTime) + "ms " + presetCount + " loaded from " + fileCount + " files");
}
private class WorkGenerator implements Runnable {
@Override
public void run() {
// Start loading
log.info("Loading component presets from " + SYSTEM_PRESET_DIR);
iterator = DirectoryIterator.findDirectory(SYSTEM_PRESET_DIR, new SimpleFileFilter("",false,"ser"));
if (iterator != null) {
while( iterator.hasNext() ) {
Pair<String,InputStream> f = iterator.next();
try {
ObjectInputStream ois = new ObjectInputStream(f.getV());
List<ComponentPreset> list = (List<ComponentPreset>) ois.readObject();
componentPresetDao.addAll(list);
fileCount++;
presetCount+=list.size();
}
catch ( Exception ex ) {
throw new BugException(ex);
}
}
}
try {
SimpleFileFilter orcFilter = new SimpleFileFilter("", false, "orc");
iterator = new DirectoryIterator(
((SwingPreferences) Application.getPreferences()).getDefaultUserComponentDirectory(),
orcFilter,
true);
if (iterator != null) {
while( iterator.hasNext() ) {
Pair<String,InputStream> f = iterator.next();
FileLoader loader = new FileLoader( f.getV(), f.getU() );
loaderPool.execute(loader);
fileCount ++;
}
}
} catch (IOException ioex ) {
log.debug("Error opening UserComponentDirectory", ioex);
}
latch.countDown();
}
}
private class FileLoader implements Runnable {
private final InputStream is;
private final String fileName;
public FileLoader(InputStream is, String fileName) {
super();
this.is = is;
this.fileName = fileName;
}
@Override
public void run() {
OpenRocketComponentLoader loader = new OpenRocketComponentLoader();
Collection<ComponentPreset> presets = loader.load(is, fileName);
PresetWriter writer = new PresetWriter(presets);
writerPool.execute(writer);
}
}
private class PresetWriter implements Runnable {
private final Collection<ComponentPreset> presets;
public PresetWriter(Collection<ComponentPreset> presets) {
super();
this.presets = presets;
}
@Override
public void run() {
presetCount += presets.size();
componentPresetDao.addAll(presets);
}
}
}

View File

@ -0,0 +1,19 @@
package net.sf.openrocket.startup;
import net.sf.openrocket.formatting.RocketDescriptor;
import net.sf.openrocket.formatting.RocketDescriptorImpl;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.Translator;
import com.google.inject.AbstractModule;
public class CoreServicesModule extends AbstractModule {
@Override
protected void configure() {
bind(Preferences.class).to(SwingPreferences.class);
bind(Translator.class).toProvider(TranslatorProvider.class);
bind(RocketDescriptor.class).to(RocketDescriptorImpl.class);
}
}

View File

@ -0,0 +1,57 @@
package net.sf.openrocket.startup;
import net.sf.openrocket.database.ComponentPresetDao;
import net.sf.openrocket.database.motor.MotorDatabase;
import net.sf.openrocket.database.motor.ThrustCurveMotorSetDatabase;
import net.sf.openrocket.gui.watcher.WatchService;
import net.sf.openrocket.gui.watcher.WatchServiceImpl;
import com.google.inject.AbstractModule;
import com.google.inject.Provider;
public class GuiModule extends AbstractModule {
private final Provider<ThrustCurveMotorSetDatabase> motorDatabaseProvider;
private final Provider<? extends ComponentPresetDao> componentDatabaseProvider;
public GuiModule() {
this.componentDatabaseProvider = loadPresetComponents();
this.motorDatabaseProvider = loadMotor();
}
@Override
protected void configure() {
bind(ComponentPresetDao.class).toProvider(componentDatabaseProvider);
bind(ThrustCurveMotorSetDatabase.class).toProvider(motorDatabaseProvider);
bind(MotorDatabase.class).toProvider(motorDatabaseProvider);
bind(WatchService.class).to(WatchServiceImpl.class);
}
/**
* Start loading preset components in background thread.
*
*/
public BlockingComponentPresetDatabaseProvider loadPresetComponents() {
ComponentPresetDatabaseLoader bg = new ComponentPresetDatabaseLoader();
bg.startLoading();
BlockingComponentPresetDatabaseProvider db = new BlockingComponentPresetDatabaseProvider(bg);
return db;
}
/**
* Start loading motors in background thread.
*
* Public for Python bindings.
*
* @return a provider for the database which blocks before returning the db.
*/
public BlockingMotorDatabaseProvider loadMotor() {
MotorDatabaseLoader bg = new MotorDatabaseLoader();
bg.startLoading();
BlockingMotorDatabaseProvider db = new BlockingMotorDatabaseProvider(bg);
return db;
}
}

View File

@ -1,169 +0,0 @@
package net.sf.openrocket.startup;
import java.io.PrintStream;
import java.util.Locale;
import java.util.prefs.Preferences;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.DebugTranslator;
import net.sf.openrocket.l10n.L10N;
import net.sf.openrocket.l10n.ResourceBundleTranslator;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.logging.LoggingSystemSetup;
import net.sf.openrocket.logging.PrintStreamToSLF4J;
import net.sf.openrocket.plugin.PluginModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* Second class in the OpenRocket startup sequence, responsible for
* IoC initialization.
*
* This class is responsible for initializing the Guice dependency injection
* mechanism, and the legacy Application class.
*
* This class must be very cautious about what classes it calls. This is because
* the loggers/translators for classes are initialized as static final members during
* class initialization. For example, this class MUST NOT use the Prefs class, because
* using it will cause LineStyle to be initialized, which then receives an invalid
* (not-yet-initialized) translator.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class GuiceStartup {
private final static Logger log = LoggerFactory.getLogger(GuiceStartup.class);
/**
* OpenRocket startup main method.
*/
public static void main(final String[] args) throws Exception {
// Check for "openrocket.debug" property before anything else
checkDebugStatus();
// Initialize logging first so we can use it
initializeLogging();
// Setup the translations
initializeL10n();
// Initialize preferences (*after* translator setup!)
Application.setPreferences(new SwingPreferences());
Injector injector = initializeGuice();
injector.getInstance(ApplicationStartup.class).runMain(args);
}
/**
* Set proper system properties if openrocket.debug is defined.
*/
private static void checkDebugStatus() {
if (System.getProperty("openrocket.debug") != null) {
setPropertyIfNotSet("openrocket.debug.menu", "true");
setPropertyIfNotSet("openrocket.debug.mutexlocation", "true");
setPropertyIfNotSet("openrocket.debug.motordigest", "true");
setPropertyIfNotSet("jogl.debug", "all");
}
}
private static void setPropertyIfNotSet(String key, String value) {
if (System.getProperty(key) == null) {
System.setProperty(key, value);
}
}
/**
* Initializes the logging system.
*/
public static void initializeLogging() {
LoggingSystemSetup.setupLoggingAppender();
if (System.getProperty("openrocket.debug") != null) {
LoggingSystemSetup.addConsoleAppender();
}
//Replace System.err with a PrintStream that logs lines to DEBUG, or VBOSE if they are indented.
//If debug info is not being output to the console then the data is both logged and written to
//stderr.
final PrintStream stdErr = System.err;
System.setErr(PrintStreamToSLF4J.getPrintStream("STDERR", stdErr));
}
/**
* Initializes the localization system.
*/
private static void initializeL10n() {
// Check for locale propery
String langcode = System.getProperty("openrocket.locale");
if (langcode != null) {
Locale l = L10N.toLocale(langcode);
log.info("Setting custom locale " + l);
Locale.setDefault(l);
} else {
// Check user-configured locale
Locale l = getUserLocale();
if (l != null) {
log.info("Setting user-selected locale " + l);
Locale.setDefault(l);
} else {
log.info("Using default locale " + Locale.getDefault());
}
}
// Setup the translator
Translator t;
t = new ResourceBundleTranslator("l10n.messages");
if (Locale.getDefault().getLanguage().equals("xx")) {
t = new DebugTranslator(t);
}
log.info("Set up translation for locale " + Locale.getDefault() +
", debug.currentFile=" + t.get("debug.currentFile"));
Application.setBaseTranslator(t);
}
private static Locale getUserLocale() {
/*
* This method MUST NOT use the Prefs class, since is causes a multitude
* of classes to be initialized. Therefore this duplicates the functionality
* of the Prefs class locally.
*/
if (System.getProperty("openrocket.debug.prefs") != null) {
return null;
}
return L10N.toLocale(Preferences.userRoot().node("OpenRocket").get("locale", null));
}
private static Injector initializeGuice() {
Module applicationModule = new ApplicationModule();
Module pluginModule = new PluginModule();
return Guice.createInjector(applicationModule, pluginModule);
}
}

View File

@ -24,9 +24,9 @@ import net.sf.openrocket.startup.jij.PluginClasspathProvider;
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class Startup {
public class JiJStartup {
private static final String STARTUP_CLASS = "net.sf.openrocket.startup.GuiceStartup";
private static final String STARTUP_CLASS = "net.sf.openrocket.startup.SwingApplication";
public static void main(String[] args) {
addClasspathUrlHandler();

View File

@ -103,7 +103,7 @@ final class OSXStartup {
// Set the dock icon to the largest icon
final Image dockIcon = Toolkit.getDefaultToolkit().getImage(
ApplicationStartup.class.getResource(ICON_RSRC));
SwingApplication.class.getResource(ICON_RSRC));
osxApp.setDockIconImage(dockIcon);
} catch (final Throwable t) {

View File

@ -196,7 +196,7 @@ public abstract class Preferences {
}
public Color getDefaultColor(Class<? extends RocketComponent> c) {
String color = get("componentColors", c, DEFAULT_COLORS);
String color = get("componentColors", c, StaticFieldHolder.DEFAULT_COLORS);
if (color == null)
return Color.BLACK;
@ -221,7 +221,7 @@ public abstract class Preferences {
* @return
*/
public final LineStyle getDefaultLineStyle(Class<? extends RocketComponent> c) {
String value = get("componentStyle", c, DEFAULT_LINE_STYLES);
String value = get("componentStyle", c, StaticFieldHolder.DEFAULT_LINE_STYLES);
try {
return LineStyle.valueOf(value);
} catch (Exception e) {
@ -263,11 +263,11 @@ public abstract class Preferences {
switch (type) {
case LINE:
return DefaultMaterialHolder.DEFAULT_LINE_MATERIAL;
return StaticFieldHolder.DEFAULT_LINE_MATERIAL;
case SURFACE:
return DefaultMaterialHolder.DEFAULT_SURFACE_MATERIAL;
return StaticFieldHolder.DEFAULT_SURFACE_MATERIAL;
case BULK:
return DefaultMaterialHolder.DEFAULT_BULK_MATERIAL;
return StaticFieldHolder.DEFAULT_BULK_MATERIAL;
}
throw new IllegalArgumentException("Unknown material type: " + type);
}
@ -390,27 +390,23 @@ public abstract class Preferences {
public abstract Set<String> getComponentFavorites(ComponentPreset.Type type);
/*
* Within a holder class so they will load only when needed.
*/
private static class StaticFieldHolder {
private static final Material DEFAULT_LINE_MATERIAL = Databases.findMaterial(Material.Type.LINE, "Elastic cord (round 2 mm, 1/16 in)");
private static final Material DEFAULT_SURFACE_MATERIAL = Databases.findMaterial(Material.Type.SURFACE, "Ripstop nylon");
private static final Material DEFAULT_BULK_MATERIAL = Databases.findMaterial(Material.Type.BULK, "Cardboard");
/*
* Map of default line styles
*/
private static final HashMap<Class<?>, String> DEFAULT_LINE_STYLES =
new HashMap<Class<?>, String>();
private static final HashMap<Class<?>, String> DEFAULT_LINE_STYLES = new HashMap<Class<?>, String>();
static {
DEFAULT_LINE_STYLES.put(RocketComponent.class, LineStyle.SOLID.name());
DEFAULT_LINE_STYLES.put(MassObject.class, LineStyle.DASHED.name());
}
/*
* Within a holder class so they will load only when needed.
*/
private static class DefaultMaterialHolder {
private static final Material DEFAULT_LINE_MATERIAL = Databases.findMaterial(Material.Type.LINE, "Elastic cord (round 2 mm, 1/16 in)");
private static final Material DEFAULT_SURFACE_MATERIAL = Databases.findMaterial(Material.Type.SURFACE, "Ripstop nylon");
private static final Material DEFAULT_BULK_MATERIAL = Databases.findMaterial(Material.Type.BULK, "Cardboard");
}
private static final HashMap<Class<?>, String> DEFAULT_COLORS =
new HashMap<Class<?>, String>();
private static final HashMap<Class<?>, String> DEFAULT_COLORS = new HashMap<Class<?>, String>();
static {
DEFAULT_COLORS.put(BodyComponent.class, "0,0,240");
DEFAULT_COLORS.put(FinSet.class, "0,0,200");
@ -419,7 +415,6 @@ public abstract class Preferences {
DEFAULT_COLORS.put(MassObject.class, "0,0,0");
DEFAULT_COLORS.put(RecoveryDevice.class, "255,0,0");
}
}
}

View File

@ -11,7 +11,6 @@ import net.sf.openrocket.file.iterator.DirectoryIterator;
import net.sf.openrocket.file.iterator.FileIterator;
import net.sf.openrocket.file.motor.GeneralMotorLoader;
import net.sf.openrocket.gui.util.SimpleFileFilter;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.util.Pair;
@ -27,7 +26,7 @@ public class SerializeMotors {
String inputDir = args[0];
String outputFile = args[1];
Application.setPreferences(new SwingPreferences());
//Application.setPreferences(new SwingPreferences());
File outFile = new File(outputFile);

View File

@ -12,28 +12,23 @@ import net.sf.openrocket.database.ComponentPresetDatabase;
import net.sf.openrocket.file.iterator.DirectoryIterator;
import net.sf.openrocket.file.iterator.FileIterator;
import net.sf.openrocket.gui.util.SimpleFileFilter;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.ResourceBundleTranslator;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.xml.OpenRocketComponentLoader;
import net.sf.openrocket.util.Pair;
public class SerializePresets {
public class SerializePresets extends BasicApplication {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
Application.setPreferences(new SwingPreferences());
Application.setBaseTranslator(new ResourceBundleTranslator("l10n.messages"));
SerializePresets app = new SerializePresets();
app.initializeApplication();
Locale.setDefault(Locale.ENGLISH);
ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase() {
@Override
protected void load() {
ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase();
FileIterator iterator = DirectoryIterator.findDirectory("resources-src/datafiles/presets", new SimpleFileFilter("", false, "orc"));
@ -48,14 +43,9 @@ public class SerializePresets {
OpenRocketComponentLoader loader = new OpenRocketComponentLoader();
Collection<ComponentPreset> presets = loader.load(is, fileName);
this.addAll(presets);
componentPresetDao.addAll(presets);
}
}
};
componentPresetDao.startLoading();
List<ComponentPreset> list = componentPresetDao.listAll();

View File

@ -4,6 +4,7 @@ import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.PrintStream;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
@ -13,23 +14,25 @@ import net.sf.openrocket.arch.SystemInfo;
import net.sf.openrocket.arch.SystemInfo.Platform;
import net.sf.openrocket.communication.UpdateInfo;
import net.sf.openrocket.communication.UpdateInfoRetriever;
import net.sf.openrocket.database.ComponentPresetDatabase;
import net.sf.openrocket.database.Databases;
import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
import net.sf.openrocket.gui.main.BasicFrame;
import net.sf.openrocket.gui.main.MRUDesignFile;
import net.sf.openrocket.gui.main.Splash;
import net.sf.openrocket.gui.main.SwingExceptionHandler;
import net.sf.openrocket.gui.util.BlockingMotorDatabaseProvider;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.logging.LoggingSystemSetup;
import net.sf.openrocket.logging.PrintStreamToSLF4J;
import net.sf.openrocket.plugin.PluginModule;
import net.sf.openrocket.util.BuildProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* The second class in the OpenRocket startup sequence. This class can assume the
@ -41,27 +44,22 @@ import com.google.inject.Injector;
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class ApplicationStartup {
private final static Logger log = LoggerFactory.getLogger(ApplicationStartup.class);
@Inject
private Injector injector;
public class SwingApplication {
private final static Logger log = LoggerFactory.getLogger(SwingApplication.class);
/**
* Run when starting up OpenRocket after Application has been set up.
*
* @param args command line arguments
* OpenRocket startup main method.
*/
public void runMain(final String[] args) throws Exception {
public static void main(final String[] args) throws Exception {
// Check for "openrocket.debug" property before anything else
checkDebugStatus();
// Initialize logging first so we can use it
initializeLogging();
log.info("Starting up OpenRocket version " + BuildProperties.getVersion());
Application.setInjector(injector);
Thread.sleep(1000);
// Check that we're not running headless
log.info("Checking for graphics head");
checkHead();
@ -71,18 +69,62 @@ public class ApplicationStartup {
OSXStartup.setupOSX();
}
final SwingApplication runner = new SwingApplication();
// Run the actual startup method in the EDT since it can use progress dialogs etc.
log.info("Moving startup to EDT");
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
runInEDT(args);
runner.runInEDT(args);
}
});
log.info("Startup complete");
}
/**
* Set proper system properties if openrocket.debug is defined.
*/
private static void checkDebugStatus() {
if (System.getProperty("openrocket.debug") != null) {
setPropertyIfNotSet("openrocket.debug.menu", "true");
setPropertyIfNotSet("openrocket.debug.mutexlocation", "true");
setPropertyIfNotSet("openrocket.debug.motordigest", "true");
setPropertyIfNotSet("jogl.debug", "all");
}
}
private static void setPropertyIfNotSet(String key, String value) {
if (System.getProperty(key) == null) {
System.setProperty(key, value);
}
}
/**
* Initializes the logging system.
*/
public static void initializeLogging() {
LoggingSystemSetup.setupLoggingAppender();
if (System.getProperty("openrocket.debug") != null) {
LoggingSystemSetup.addConsoleAppender();
}
//Replace System.err with a PrintStream that logs lines to DEBUG, or VBOSE if they are indented.
//If debug info is not being output to the console then the data is both logged and written to
//stderr.
final PrintStream stdErr = System.err;
System.setErr(PrintStreamToSLF4J.getPrintStream("STDERR", stdErr));
}
private Injector initializeGuice() {
Module applicationModule = new CoreServicesModule();
GuiModule guiModule = new GuiModule();
Module pluginModule = new PluginModule();
return Guice.createInjector(applicationModule, guiModule, pluginModule);
}
/**
* Run in the EDT when starting up OpenRocket.
@ -95,13 +137,28 @@ public class ApplicationStartup {
log.info("Initializing the splash screen");
Splash.init();
// Setup the uncaught exception handler
log.info("Registering exception handler");
SwingExceptionHandler exceptionHandler = new SwingExceptionHandler();
Application.setExceptionHandler(exceptionHandler);
exceptionHandler.registerExceptionHandler();
// Load motors etc.
log.info("Loading databases");
// There are some latent dependencies in here so the guiced application
// is created in two parts. In particular, the database loading processes
// require the translator to be setup correctly.
Module applicationModule = new CoreServicesModule();
Module pluginModule = new PluginModule();
Injector injector = Guice.createInjector(applicationModule, pluginModule);
Application.setInjector(injector);
// Update injector to contain database bindings
GuiModule guiModule = new GuiModule();
Injector injector2 = injector.createChildInjector(guiModule);
Application.setInjector(injector2);
// Start update info fetching
final UpdateInfoRetriever updateInfo;
if (Application.getPreferences().getCheckUpdates()) {
@ -123,22 +180,8 @@ public class ApplicationStartup {
// Load defaults
((SwingPreferences) Application.getPreferences()).loadDefaultUnits();
// Load motors etc.
log.info("Loading databases");
loadPresetComponents();
BlockingMotorDatabaseProvider db = loadMotor();
// Update injector to contain database bindings
ApplicationModule2 module = new ApplicationModule2(db);
Injector injector2 = injector.createChildInjector(module);
Application.setInjector(injector2);
Databases.fakeMethod();
// Starting action (load files or open new document)
log.info("Opening main application window");
if (!handleCommandLine(args)) {
@ -167,46 +210,10 @@ public class ApplicationStartup {
}
/**
* Start loading preset components in background thread.
*
* Public for Python bindings.
*/
public void loadPresetComponents() {
ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase(false) {
@Override
protected void load() {
ConcurrentComponentPresetDatabaseLoader presetLoader = new ConcurrentComponentPresetDatabaseLoader(this);
presetLoader.load();
try {
presetLoader.await();
} catch (InterruptedException iex) {
}
}
};
Application.setComponentPresetDao(componentPresetDao);
componentPresetDao.startLoading();
}
/**
* Start loading motors in background thread.
*
* Public for Python bindings.
*
* @return a provider for the database which blocks before returning the db.
*/
public BlockingMotorDatabaseProvider loadMotor() {
MotorDatabaseLoader bg = injector.getInstance(MotorDatabaseLoader.class);
bg.startLoading();
BlockingMotorDatabaseProvider db = new BlockingMotorDatabaseProvider(bg);
return db;
}
/**
* Check that the JRE is not running headless.
*/
private void checkHead() {
private static void checkHead() {
if (GraphicsEnvironment.isHeadless()) {
log.error("Application is headless.");

View File

@ -0,0 +1,75 @@
package net.sf.openrocket.startup;
import java.util.Locale;
import java.util.prefs.Preferences;
import net.sf.openrocket.l10n.DebugTranslator;
import net.sf.openrocket.l10n.L10N;
import net.sf.openrocket.l10n.ResourceBundleTranslator;
import net.sf.openrocket.l10n.Translator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Provider;
public class TranslatorProvider implements Provider<Translator> {
private final static Logger log = LoggerFactory.getLogger(TranslatorProvider.class);
@Override
public Translator get() {
// Check for locale propery
String langcode = System.getProperty("openrocket.locale");
if (langcode != null) {
Locale l = L10N.toLocale(langcode);
log.info("Setting custom locale " + l);
Locale.setDefault(l);
} else {
// Check user-configured locale
Locale l = getUserLocale();
if (l != null) {
log.info("Setting user-selected locale " + l);
Locale.setDefault(l);
} else {
log.info("Using default locale " + Locale.getDefault());
}
}
// Setup the translator
Translator t;
t = new ResourceBundleTranslator("l10n.messages");
if (Locale.getDefault().getLanguage().equals("xx")) {
t = new DebugTranslator(t);
}
log.info("Set up translation for locale " + Locale.getDefault() +
", debug.currentFile=" + t.get("debug.currentFile"));
return t;
}
private static Locale getUserLocale() {
/*
* This method MUST NOT use the Prefs class, since is causes a multitude
* of classes to be initialized. Therefore this duplicates the functionality
* of the Prefs class locally.
*/
if (System.getProperty("openrocket.debug.prefs") != null) {
return null;
}
return L10N.toLocale(Preferences.userRoot().node("OpenRocket").get("locale", null));
}
}

View File

@ -9,9 +9,7 @@ import net.sf.openrocket.document.StorageOptions;
import net.sf.openrocket.file.GeneralRocketLoader;
import net.sf.openrocket.file.GeneralRocketSaver;
import net.sf.openrocket.file.RocketLoadException;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.ResourceBundleTranslator;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.startup.BasicApplication;
/**
* Utility that loads Rocksim file formats and saves them in ORK format.
@ -75,8 +73,9 @@ public class RocksimConverter {
private static void setup() {
Locale.setDefault(Locale.US);
Application.setBaseTranslator(new ResourceBundleTranslator("l10n.messages"));
Application.setPreferences(new SwingPreferences());
BasicApplication app = new BasicApplication();
app.initializeApplication();
//?? Application.setPreferences(new SwingPreferences());
}
}

View File

@ -1,32 +0,0 @@
package net.sf.openrocket;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.plugin.PluginModule;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.startup.ApplicationModule;
import org.junit.BeforeClass;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
public abstract class AbstractBaseApplication {
@BeforeClass
public static void setUp() throws Exception {
Application.setInjector(initializeGuice());
}
private static Injector initializeGuice() {
Application.setPreferences(new SwingPreferences());
Module applicationModule = new ApplicationModule();
Module pluginModule = new PluginModule();
return Guice.createInjector(applicationModule, pluginModule);
}
}

View File

@ -16,6 +16,9 @@ import javax.swing.Action;
import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
import net.sf.openrocket.aerodynamics.FlightConditions;
import net.sf.openrocket.database.ComponentPresetDao;
import net.sf.openrocket.database.ComponentPresetDatabase;
import net.sf.openrocket.database.motor.MotorDatabase;
import net.sf.openrocket.database.motor.ThrustCurveMotorSetDatabase;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.document.Simulation;
@ -23,7 +26,6 @@ import net.sf.openrocket.file.GeneralRocketLoader;
import net.sf.openrocket.file.RocketLoadException;
import net.sf.openrocket.file.motor.GeneralMotorLoader;
import net.sf.openrocket.gui.main.UndoRedoAction;
import net.sf.openrocket.l10n.ResourceBundleTranslator;
import net.sf.openrocket.masscalc.BasicMassCalculator;
import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
@ -37,8 +39,9 @@ import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.simulation.FlightDataType;
import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.startup.ApplicationModule2;
import net.sf.openrocket.startup.GuiModule;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JMock;
@ -47,15 +50,18 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.util.Modules;
/**
* This class contains various integration tests that simulate user actions that
* might be performed.
*/
@RunWith(JMock.class)
public class IntegrationTest extends AbstractBaseApplication {
public class IntegrationTest extends BaseTestCase {
Mockery context = new JUnit4Mockery();
private OpenRocketDocument document;
@ -66,25 +72,48 @@ public class IntegrationTest extends AbstractBaseApplication {
private Configuration config;
private FlightConditions conditions;
@BeforeClass
public static void setupMotorDatabase() {
private static class EmptyComponentDbProvider implements Provider<ComponentPresetDao> {
final ComponentPresetDao db = new ComponentPresetDatabase();
@Override
public ComponentPresetDao get() {
return db;
}
}
private static class MotorDbProvider implements Provider<ThrustCurveMotorSetDatabase> {
final ThrustCurveMotorSetDatabase db = new ThrustCurveMotorSetDatabase();
public MotorDbProvider() {
db.addMotor(readMotor());
assertEquals(1, db.getMotorSets().size());
ApplicationModule2 module = new ApplicationModule2(new Provider<ThrustCurveMotorSetDatabase>() {
}
@Override
public ThrustCurveMotorSetDatabase get() {
return db;
}
}
});
Injector injector2 = Application.getInjector().createChildInjector(module);
@BeforeClass
public static void setupMotorDatabase() {
Module dbOverrides = new AbstractModule() {
@Override
protected void configure() {
bind(ComponentPresetDao.class).toProvider(new EmptyComponentDbProvider());
bind(MotorDatabase.class).toProvider(new MotorDbProvider());
}
};
Injector injector2 = Application.getInjector().createChildInjector(Modules.override(new GuiModule()).with(dbOverrides));
Application.setInjector(injector2);
Application.setBaseTranslator(new ResourceBundleTranslator("l10n.messages"));
}
@ -306,17 +335,17 @@ public class IntegrationTest extends AbstractBaseApplication {
private void checkUndoState(String undoDesc, String redoDesc) {
if (undoDesc == null) {
assertEquals("Undo", undoAction.getValue(Action.NAME));
assertEquals("[UndoRedoAction.OpenRocketDocument.Undo]", undoAction.getValue(Action.NAME));
assertFalse(undoAction.isEnabled());
} else {
assertEquals("Undo (" + undoDesc + ")", undoAction.getValue(Action.NAME));
assertEquals("[UndoRedoAction.OpenRocketDocument.Undo] (" + undoDesc + ")", undoAction.getValue(Action.NAME));
assertTrue(undoAction.isEnabled());
}
if (redoDesc == null) {
assertEquals("Redo", redoAction.getValue(Action.NAME));
assertEquals("[UndoRedoAction.OpenRocketDocument.Redo]", redoAction.getValue(Action.NAME));
assertFalse(redoAction.isEnabled());
} else {
assertEquals("Redo (" + redoDesc + ")", redoAction.getValue(Action.NAME));
assertEquals("[UndoRedoAction.OpenRocketDocument.Redo] (" + redoDesc + ")", redoAction.getValue(Action.NAME));
assertTrue(redoAction.isEnabled());
}
}

View File

@ -8,7 +8,6 @@ import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import net.sf.openrocket.AbstractBaseApplication;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.document.OpenRocketDocumentFactory;
import net.sf.openrocket.file.DatabaseMotorFinder;
@ -18,13 +17,14 @@ import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.LaunchLug;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.rocketcomponent.Stage;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import org.junit.Assert;
/**
* RocksimLoader Tester.
*/
public class RocksimLoaderTest extends AbstractBaseApplication {
public class RocksimLoaderTest extends BaseTestCase {
/**
* Test a bug reported via automated bug report. I have been unable to reproduce this bug

View File

@ -6,18 +6,15 @@ package net.sf.openrocket.file.rocksim.importt;
import java.lang.reflect.Field;
import java.util.List;
import net.sf.openrocket.AbstractBaseApplication;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import org.junit.Assert;
import org.junit.Before;
/**
* A base class for the Rocksim tests. Includes code from the junitx.addons project.
*/
public abstract class RocksimTestBase extends AbstractBaseApplication {
public abstract class RocksimTestBase extends BaseTestCase {
public void assertContains(RocketComponent child, List<RocketComponent> components) {
Assert.assertTrue("Components did not contain child", components.contains(child));

View File

@ -3,7 +3,6 @@ package net.sf.openrocket.optimization.rocketoptimization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import net.sf.openrocket.AbstractBaseApplication;
import net.sf.openrocket.document.Simulation;
import net.sf.openrocket.optimization.general.OptimizationException;
import net.sf.openrocket.optimization.general.Point;
@ -12,6 +11,7 @@ import net.sf.openrocket.unit.Unit;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.unit.Value;
import net.sf.openrocket.util.Pair;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import org.jmock.Expectations;
import org.jmock.Mockery;
@ -23,7 +23,7 @@ import org.junit.runner.RunWith;
@RunWith(JMock.class)
public class TestRocketOptimizationFunction extends AbstractBaseApplication {
public class TestRocketOptimizationFunction extends BaseTestCase {
Mockery context = new JUnit4Mockery();
@Mock

View File

@ -2,17 +2,17 @@ package net.sf.openrocket.optimization.rocketoptimization.modifiers;
import static net.sf.openrocket.util.MathUtil.EPSILON;
import static org.junit.Assert.assertEquals;
import net.sf.openrocket.AbstractBaseApplication;
import net.sf.openrocket.document.Simulation;
import net.sf.openrocket.optimization.general.OptimizationException;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class TestGenericModifier extends AbstractBaseApplication {
public class TestGenericModifier extends BaseTestCase {
private TestValue value;
private GenericModifier<TestValue> gm;

View File

@ -1,8 +1,6 @@
package net.sf.openrocket.plugin;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.startup.ApplicationModule;
import net.sf.openrocket.startup.CoreServicesModule;
import org.junit.Test;
@ -22,9 +20,7 @@ public class PluginTest {
@Test
public void testPluginModule() {
Application.setPreferences(new SwingPreferences());
Module applicationModule = new ApplicationModule();
Module applicationModule = new CoreServicesModule();
Injector injector = Guice.createInjector(applicationModule, new PluginModule());
PluginTester tester = injector.getInstance(PluginTester.class);

View File

@ -1,12 +1,12 @@
package net.sf.openrocket.simulation.customexpression;
import net.sf.openrocket.AbstractBaseApplication;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.document.OpenRocketDocumentFactory;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import org.junit.Test;
public class TestExpressions extends AbstractBaseApplication {
public class TestExpressions extends BaseTestCase {
@Test
public void testExpressions() {

View File

@ -1,16 +1,34 @@
package net.sf.openrocket.util.BaseTestCase;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.DebugTranslator;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.plugin.PluginModule;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.startup.CoreServicesModule;
import org.junit.BeforeClass;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.util.Modules;
public class BaseTestCase {
@BeforeClass
public static void setUpApplication () {
public static void setUp() throws Exception {
Module applicationModule = new CoreServicesModule();
Module debugTranslator = new AbstractModule() {
Application.setPreferences( new SwingPreferences() );
@Override
protected void configure() {
bind(Translator.class).toInstance(new DebugTranslator(null));
}
};
Module pluginModule = new PluginModule();
Injector injector = Guice.createInjector(Modules.override(applicationModule).with(debugTranslator), pluginModule);
Application.setInjector(injector);
}
}