diff --git a/core/build.xml b/core/build.xml index 04820e3a4..2af57b225 100644 --- a/core/build.xml +++ b/core/build.xml @@ -27,7 +27,7 @@ - + diff --git a/core/src/logback.xml b/core/src/logback.xml deleted file mode 100644 index 930599f30..000000000 --- a/core/src/logback.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/core/src/net/sf/openrocket/appearance/DecalImage.java b/core/src/net/sf/openrocket/appearance/DecalImage.java index 31aa9013a..544eda8b3 100644 --- a/core/src/net/sf/openrocket/appearance/DecalImage.java +++ b/core/src/net/sf/openrocket/appearance/DecalImage.java @@ -13,6 +13,7 @@ public interface DecalImage extends ChangeSource, Comparable { 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); } diff --git a/core/src/net/sf/openrocket/appearance/defaults/ResourceDecalImage.java b/core/src/net/sf/openrocket/appearance/defaults/ResourceDecalImage.java index 20d2661ac..65ae08506 100644 --- a/core/src/net/sf/openrocket/appearance/defaults/ResourceDecalImage.java +++ b/core/src/net/sf/openrocket/appearance/defaults/ResourceDecalImage.java @@ -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 diff --git a/core/src/net/sf/openrocket/database/ComponentPresetDatabase.java b/core/src/net/sf/openrocket/database/ComponentPresetDatabase.java index 24bca83ae..df9db3f22 100644 --- a/core/src/net/sf/openrocket/database/ComponentPresetDatabase.java +++ b/core/src/net/sf/openrocket/database/ComponentPresetDatabase.java @@ -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 implements ComponentPresetDao { +public class ComponentPresetDatabase extends Database 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 listAll() { - blockUntilLoaded(); return list; } @@ -45,7 +31,6 @@ public abstract class ComponentPresetDatabase extends Database @Override public List listForType( ComponentPreset.Type type ) { - blockUntilLoaded(); if ( type == null ) { return Collections.emptyList(); } @@ -71,8 +56,6 @@ public abstract class ComponentPresetDatabase extends Database */ @Override public List listForType( ComponentPreset.Type type, boolean favorite ) { - blockUntilLoaded(); - if ( !favorite ) { return listForType(type); } @@ -91,8 +74,6 @@ public abstract class ComponentPresetDatabase extends Database @Override public List listForTypes( ComponentPreset.Type ... type ) { - blockUntilLoaded(); - if( type == null || type.length == 0 ) { return Collections.emptyList(); } @@ -118,13 +99,11 @@ public abstract class ComponentPresetDatabase extends Database @Override public List listForTypes( List types ) { - blockUntilLoaded(); return listForTypes( (ComponentPreset.Type[]) types.toArray() ); } @Override public List find(String manufacturer, String partNo) { - blockUntilLoaded(); List presets = new ArrayList(); for( ComponentPreset preset : list ) { if ( preset.getManufacturer().getSimpleName().equals(manufacturer) && preset.getPartNo().equals(partNo) ) { @@ -136,75 +115,8 @@ public abstract class ComponentPresetDatabase extends Database @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); - } - } - } - } - } - } diff --git a/core/src/net/sf/openrocket/document/DecalRegistry.java b/core/src/net/sf/openrocket/document/DecalRegistry.java index 607e4adc5..931a4d7e7 100644 --- a/core/src/net/sf/openrocket/document/DecalRegistry.java +++ b/core/src/net/sf/openrocket/document/DecalRegistry.java @@ -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); } diff --git a/core/src/net/sf/openrocket/gui/ExportDecalDialog.java b/core/src/net/sf/openrocket/gui/ExportDecalDialog.java index b83262e01..457dfa54e 100644 --- a/core/src/net/sf/openrocket/gui/ExportDecalDialog.java +++ b/core/src/net/sf/openrocket/gui/ExportDecalDialog.java @@ -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); diff --git a/core/src/net/sf/openrocket/gui/components/compass/Tester.java b/core/src/net/sf/openrocket/gui/components/compass/Tester.java index 86a82a495..9273088f7 100644 --- a/core/src/net/sf/openrocket/gui/components/compass/Tester.java +++ b/core/src/net/sf/openrocket/gui/components/compass/Tester.java @@ -11,16 +11,16 @@ 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 { - + public static void main(String[] args) throws InterruptedException, InvocationTargetException { - Application.setBaseTranslator(new ResourceBundleTranslator("l10n.messages")); + BasicApplication baseApp = new BasicApplication(); + baseApp.initializeApplication(); GUIUtil.setBestLAF(); @@ -33,7 +33,7 @@ public class Tester { DoubleModel model = new DoubleModel(Math.toRadians(45), UnitGroup.UNITS_ANGLE); DoubleModel second = new DoubleModel(Math.toRadians(30), UnitGroup.UNITS_ANGLE); - + CompassPointer rose = new CompassSelector(model); rose.setPreferredSize(new Dimension(300, 300)); rose.setSecondaryModel(second); @@ -51,11 +51,11 @@ public class Tester { spin.setPreferredSize(new Dimension(50, 20)); panel.add(spin, "wrap para"); - + CompassSelectionButton button = new CompassSelectionButton(model); panel.add(button); - + frame.add(panel); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/core/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java b/core/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java index 459750cd2..94c424dfb 100644 --- a/core/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java +++ b/core/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java @@ -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); } diff --git a/core/src/net/sf/openrocket/gui/preset/ComponentPresetEditor.java b/core/src/net/sf/openrocket/gui/preset/ComponentPresetEditor.java index 696b6e59e..e4e9f94e2 100644 --- a/core/src/net/sf/openrocket/gui/preset/ComponentPresetEditor.java +++ b/core/src/net/sf/openrocket/gui/preset/ComponentPresetEditor.java @@ -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,486 +30,476 @@ 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 */ public class ComponentPresetEditor extends JPanel implements PresetResultListener { - - /** - * The logger. - */ - private static final Logger log = LoggerFactory.getLogger(ComponentPresetEditor.class); - - /** - * The I18N translator. - */ - private static Translator trans = null; - - /** - * The table of presets. - */ - private JTable table; - - /** - * The table's data model. - */ - private DataTableModel model; - - private final OpenedFileContext editContext = new OpenedFileContext(); - - static { - trans = Application.getTranslator(); - } - - /** - * Create the panel. - * - * @param frame the parent window - */ - public ComponentPresetEditor(final JFrame frame) { - 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", ""}); - - table = new JTable(model); - table.getTableHeader().setFont(new JLabel().getFont()); - //The action never gets called because the table MouseAdapter intercepts it first. Still need an empty - // instance though. - Action action = new AbstractAction() { - @Override - public void actionPerformed(final ActionEvent e) { - } - }; - //Create a editor/renderer for the delete operation. Instantiation self-registers into the table. - new ButtonColumn(table, action, 4); - table.getColumnModel().getColumn(4).setMaxWidth(Icons.EDIT_DELETE.getIconWidth()); - table.getColumnModel().getColumn(4).setMinWidth(Icons.EDIT_DELETE.getIconWidth()); - - JScrollPane scrollPane = new JScrollPane(table); - table.setFillsViewportHeight(true); - table.setAutoCreateRowSorter(true); - add(scrollPane, "cell 0 0 6 1,grow"); - - table.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - JTable target = (JTable) e.getSource(); - int selectedColumn = table.getColumnModel().getColumnIndexAtX(target.getSelectedColumn()); - final int targetSelectedRow = target.getSelectedRow(); - if (targetSelectedRow > -1 && targetSelectedRow < model.getRowCount()) { - int selectedRow = table.getRowSorter().convertRowIndexToModel(targetSelectedRow); - if (selectedColumn == 4) { - if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(ComponentPresetEditor.this, - "Do you want to delete this preset?", - "Confirm Delete", JOptionPane.YES_OPTION, - JOptionPane.QUESTION_MESSAGE)) { - model.removeRow(selectedRow); - } - } - else { - if (e.getClickCount() == 2) { - editContext.setEditingSelected(true); - new PresetEditorDialog(ComponentPresetEditor.this, - (ComponentPreset) model.getAssociatedObject(selectedRow), editContext.getMaterialsLoaded()).setVisible(true); - } - } - } - } - }); - - - JMenuBar menuBar = new JMenuBar(); - frame.setJMenuBar(menuBar); - - JMenu mnFile = new JMenu("File"); - menuBar.add(mnFile); - - JMenuItem mntmOpen = new JMenuItem("Open..."); - mnFile.add(mntmOpen); - mntmOpen.addActionListener(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - if (model.getRowCount() > 0) { - /* - * If the table model already contains presets, ask the user if they a) want to discard those - * 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", - "Merge", - "Discard", - "Cancel"}; - int n = JOptionPane.showOptionDialog(frame, - "The editor contains existing component presets. What would you like to do with them?", - "Existing Component Presets", - JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.QUESTION_MESSAGE, - null, - options, - options[0]); - if (n == 0) { //Save. Then remove existing rows and open. - if (saveAndHandleError()) { - model.removeAllRows(); - } - else { //Save failed; bail out. - return; - } - } - else if (n == 2) { //Discard and open - model.removeAllRows(); - } - else if (n == 3) { //Cancel. Bail out. - return; - } - } - //Open file dialog - openComponentFile(); - } - }); - - JSeparator separator = new JSeparator(); - mnFile.add(separator); - - JMenuItem mntmSave = new JMenuItem("Save As..."); - mnFile.add(mntmSave); - mntmSave.addActionListener(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - saveAndHandleError(); - } - }); - - JSeparator separator_1 = new JSeparator(); - mnFile.add(separator_1); - - JMenuItem mntmExit = new JMenuItem("Close"); - mnFile.add(mntmExit); - mntmExit.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - Window w = SwingUtilities.getWindowAncestor(ComponentPresetEditor.this); - w.dispose(); - } - }); - - - JButton addBtn = new JButton("Add"); - addBtn.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent arg0) { - editContext.setEditingSelected(false); - new PresetEditorDialog(ComponentPresetEditor.this).setVisible(true); - } - }); - add(addBtn, "cell 0 1,alignx left,aligny top"); - } - - /** - * Callback method from the PresetEditorDialog to notify this class when a preset has been saved. The 'save' is - * really just a call back here so the preset can be added to the master table. It's not to be confused with the - * save to disk. - * - * @param preset the new or modified preset - */ - @Override - public void notifyResult(final ComponentPreset preset) { - if (preset != null) { - DataTableModel myModel = (DataTableModel) table.getModel(); - //Is this a new preset? - 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); - } - else { - //This is a modified preset; update all of the columns and the stored associated instance. - int row = table.getSelectedRow(); - myModel.setValueAt(preset.getManufacturer().getDisplayName(), row, 0); - myModel.setValueAt(preset.getType().name(), row, 1); - myModel.setValueAt(preset.getPartNo(), row, 2); - myModel.setValueAt(description, row, 3); - myModel.associated.set(row, preset); - } - } - editContext.setEditingSelected(false); - } - - /** - * Launch the test main. - */ - public static void main(String[] args) { - try { - trans = new ResourceBundleTranslator("l10n.messages"); - net.sf.openrocket.startup.Application.setBaseTranslator(trans); - - 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) { - e.printStackTrace(); - } - } - - /** - * A table model that adds associated objects to each row, allowing for easy retrieval. - */ - class DataTableModel extends DefaultTableModel { - - private List associated = new ArrayList(); - - /** - * Constructs a DefaultTableModel with as many columns as there are elements in - * columnNames and rowCount of null object values. Each column's name - * will be taken from the columnNames array. - * - * @param columnNames array containing the names of the new columns; if this is null - * then the model has no columns - * - * @see #setDataVector - * @see #setValueAt - */ - DataTableModel(final Object[] columnNames) { - super(columnNames, 0); - } - - public void addRow(Object[] data, Object associatedData) { - super.addRow(data); - associated.add(getRowCount() - 1, associatedData); - } - - public void removeAllRows() { - for (int x = getRowCount(); x > 0; x--) { - super.removeRow(x - 1); - } - associated.clear(); - } - - @Override - public void removeRow(int row) { - super.removeRow(row); - associated.remove(row); - } - - public Object getAssociatedObject(int row) { - return associated.get(row); - } - - @Override - public boolean isCellEditable(int rowIndex, int mColIndex) { - return false; - } - } - - /** - * Open the component file. Present a chooser for the user to navigate to the file. - * - * @return true if the file was successfully opened; Note: side effect, is that the ComponentPresets read from the - * file are written to the table model. - */ - private boolean openComponentFile() { - final JFileChooser chooser = new JFileChooser(); - chooser.addChoosableFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER); - chooser.addChoosableFileFilter(FileHelper.CSV_FILE_FILTER); - chooser.setFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER); - chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); - if (editContext.getLastDirectory() != null) { - chooser.setCurrentDirectory(editContext.getLastDirectory()); - } - else { - chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultUserComponentDirectory()); - } - - int option = chooser.showOpenDialog(ComponentPresetEditor.this); - if (option != JFileChooser.APPROVE_OPTION) { - editContext.setOpenedFile(null); - log.info(Markers.USER_MARKER, "User decided not to open, option=" + option); - return false; - } - - File file = chooser.getSelectedFile(); - try { - if (file == null) { - log.info(Markers.USER_MARKER, "User did not select a file"); - return false; - } - - editContext.setLastDirectory(file.getParentFile()); - editContext.setMaterialsLoaded(null); - List presets = null; - - if (file.getName().toLowerCase().endsWith(".orc")) { - OpenRocketComponentDTO fileContents = new OpenRocketComponentSaver().unmarshalFromOpenRocketComponent(new FileReader(file)); - editContext.setMaterialsLoaded(new MaterialHolder(fileContents.asMaterialList())); - presets = fileContents.asComponentPresets(); - } - else { - if (file.getName().toLowerCase().endsWith(".csv")) { - file = file.getParentFile(); - } - presets = new ArrayList(); - MaterialHolder materialHolder = RocksimComponentFileTranslator.loadAll(presets, file); - editContext.setMaterialsLoaded(materialHolder); - } - if (presets != null) { - for (ComponentPreset next : presets) { - notifyResult(next); - } - editContext.setOpenedFile(file); - } - } - 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()); - editContext.setOpenedFile(null); - editContext.setEditingSelected(false); - return false; - } - return true; - } - - private boolean saveAndHandleError() { - try { - return saveAsORC(); - } - catch (Exception e1) { - JOptionPane.showMessageDialog(ComponentPresetEditor.this, e1.getLocalizedMessage(), - "Error saving ORC file.", JOptionPane.ERROR_MESSAGE); - return false; - } - } - - /** - * Save the contents of the table model as XML in .orc format. - * - * @return true if the file was written - * - * @throws JAXBException thrown if the data could not be marshaled - * @throws IOException thrown if there was a problem with writing the file - */ - private boolean saveAsORC() throws JAXBException, IOException { - File file = null; - - final JFileChooser chooser = new JFileChooser(); - chooser.addChoosableFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER); - - chooser.setFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER); - if (editContext.getOpenedFile() != null) { - chooser.setSelectedFile(editContext.getOpenedFile()); - } - else { - chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultUserComponentDirectory()); - } - - int option = chooser.showSaveDialog(ComponentPresetEditor.this); - if (option != JFileChooser.APPROVE_OPTION) { - log.info(Markers.USER_MARKER, "User decided not to save, option=" + option); - return false; - } - - file = chooser.getSelectedFile(); - if (file == null) { - log.info(Markers.USER_MARKER, "User did not select a file"); - return false; - } - - file = FileHelper.forceExtension(file, "orc"); - - MaterialHolder materials = new MaterialHolder(); - List presets = new ArrayList(); - - for (int x = 0; x < model.getRowCount(); x++) { - ComponentPreset preset = (ComponentPreset) model.getAssociatedObject(x); - // If we don't have a material already defined for saving... - if (materials.getMaterial(preset.get(ComponentPreset.MATERIAL)) == null) { - // Check if we loaded a material with this name. - Material m = null; - if (editContext.getMaterialsLoaded() != null) { - m = editContext.getMaterialsLoaded().getMaterial(preset.get - (ComponentPreset.MATERIAL)); - } - // If there was no material loaded with that name, use the component's material. - if (m == null) { - m = preset.get(ComponentPreset.MATERIAL); - } - materials.put(m); - } - presets.add(preset); - } - - return FileHelper.confirmWrite(file, this) && new OpenRocketComponentSaver().save(file, new ArrayList(materials.values()), presets); - } - - class OpenedFileContext { - - /** - * State variable to keep track of which file was opened, in case it needs to be saved back to that file. - */ - private File openedFile = null; - - /** - * Last directory; file chooser is set here so user doesn't have to keep navigating to a common area. - */ - private File lastDirectory = null; - - private boolean editingSelected = false; - - private MaterialHolder materialsLoaded = null; - - OpenedFileContext() { - } - - public File getOpenedFile() { - return openedFile; - } - - public void setOpenedFile(final File theOpenedFile) { - openedFile = theOpenedFile; - } - - public File getLastDirectory() { - return lastDirectory; - } - - public void setLastDirectory(final File theLastDirectory) { - lastDirectory = theLastDirectory; - } - - public boolean isEditingSelected() { - return editingSelected; - } - - public void setEditingSelected(final boolean theEditingSelected) { - editingSelected = theEditingSelected; - } - - public MaterialHolder getMaterialsLoaded() { - return materialsLoaded; - } - - public void setMaterialsLoaded(final MaterialHolder theMaterialsLoaded) { - materialsLoaded = theMaterialsLoaded; - } - } + + /** + * The logger. + */ + private static final Logger log = LoggerFactory.getLogger(ComponentPresetEditor.class); + + /** + * The table of presets. + */ + private JTable table; + + /** + * The table's data model. + */ + private DataTableModel model; + + private final OpenedFileContext editContext = new OpenedFileContext(); + + /** + * Create the panel. + * + * @param frame the parent window + */ + public ComponentPresetEditor(final JFrame frame) { + 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", "" }); + + table = new JTable(model); + table.getTableHeader().setFont(new JLabel().getFont()); + //The action never gets called because the table MouseAdapter intercepts it first. Still need an empty + // instance though. + Action action = new AbstractAction() { + @Override + public void actionPerformed(final ActionEvent e) { + } + }; + //Create a editor/renderer for the delete operation. Instantiation self-registers into the table. + new ButtonColumn(table, action, 4); + table.getColumnModel().getColumn(4).setMaxWidth(Icons.EDIT_DELETE.getIconWidth()); + table.getColumnModel().getColumn(4).setMinWidth(Icons.EDIT_DELETE.getIconWidth()); + + JScrollPane scrollPane = new JScrollPane(table); + table.setFillsViewportHeight(true); + table.setAutoCreateRowSorter(true); + add(scrollPane, "cell 0 0 6 1,grow"); + + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + JTable target = (JTable) e.getSource(); + int selectedColumn = table.getColumnModel().getColumnIndexAtX(target.getSelectedColumn()); + final int targetSelectedRow = target.getSelectedRow(); + if (targetSelectedRow > -1 && targetSelectedRow < model.getRowCount()) { + int selectedRow = table.getRowSorter().convertRowIndexToModel(targetSelectedRow); + if (selectedColumn == 4) { + if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(ComponentPresetEditor.this, + "Do you want to delete this preset?", + "Confirm Delete", JOptionPane.YES_OPTION, + JOptionPane.QUESTION_MESSAGE)) { + model.removeRow(selectedRow); + } + } + else { + if (e.getClickCount() == 2) { + editContext.setEditingSelected(true); + new PresetEditorDialog(ComponentPresetEditor.this, + (ComponentPreset) model.getAssociatedObject(selectedRow), editContext.getMaterialsLoaded()).setVisible(true); + } + } + } + } + }); + + + JMenuBar menuBar = new JMenuBar(); + frame.setJMenuBar(menuBar); + + JMenu mnFile = new JMenu("File"); + menuBar.add(mnFile); + + JMenuItem mntmOpen = new JMenuItem("Open..."); + mnFile.add(mntmOpen); + mntmOpen.addActionListener(new ActionListener() { + @Override + public void actionPerformed(final ActionEvent e) { + if (model.getRowCount() > 0) { + /* + * If the table model already contains presets, ask the user if they a) want to discard those + * 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", + "Merge", + "Discard", + "Cancel" }; + int n = JOptionPane.showOptionDialog(frame, + "The editor contains existing component presets. What would you like to do with them?", + "Existing Component Presets", + JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + options, + options[0]); + if (n == 0) { //Save. Then remove existing rows and open. + if (saveAndHandleError()) { + model.removeAllRows(); + } + else { //Save failed; bail out. + return; + } + } + else if (n == 2) { //Discard and open + model.removeAllRows(); + } + else if (n == 3) { //Cancel. Bail out. + return; + } + } + //Open file dialog + openComponentFile(); + } + }); + + JSeparator separator = new JSeparator(); + mnFile.add(separator); + + JMenuItem mntmSave = new JMenuItem("Save As..."); + mnFile.add(mntmSave); + mntmSave.addActionListener(new ActionListener() { + @Override + public void actionPerformed(final ActionEvent e) { + saveAndHandleError(); + } + }); + + JSeparator separator_1 = new JSeparator(); + mnFile.add(separator_1); + + JMenuItem mntmExit = new JMenuItem("Close"); + mnFile.add(mntmExit); + mntmExit.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + Window w = SwingUtilities.getWindowAncestor(ComponentPresetEditor.this); + w.dispose(); + } + }); + + + JButton addBtn = new JButton("Add"); + addBtn.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent arg0) { + editContext.setEditingSelected(false); + new PresetEditorDialog(ComponentPresetEditor.this).setVisible(true); + } + }); + add(addBtn, "cell 0 1,alignx left,aligny top"); + } + + /** + * Callback method from the PresetEditorDialog to notify this class when a preset has been saved. The 'save' is + * really just a call back here so the preset can be added to the master table. It's not to be confused with the + * save to disk. + * + * @param preset the new or modified preset + */ + @Override + public void notifyResult(final ComponentPreset preset) { + if (preset != null) { + DataTableModel myModel = (DataTableModel) table.getModel(); + //Is this a new preset? + 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); + } + else { + //This is a modified preset; update all of the columns and the stored associated instance. + int row = table.getSelectedRow(); + myModel.setValueAt(preset.getManufacturer().getDisplayName(), row, 0); + myModel.setValueAt(preset.getType().name(), row, 1); + myModel.setValueAt(preset.getPartNo(), row, 2); + myModel.setValueAt(description, row, 3); + myModel.associated.set(row, preset); + } + } + editContext.setEditingSelected(false); + } + + /** + * Launch the test main. + */ + public static void main(String[] args) { + BasicApplication app = new BasicApplication(); + app.initializeApplication(); + try { + // 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) { + e.printStackTrace(); + } + } + + /** + * A table model that adds associated objects to each row, allowing for easy retrieval. + */ + class DataTableModel extends DefaultTableModel { + + private List associated = new ArrayList(); + + /** + * Constructs a DefaultTableModel with as many columns as there are elements in + * columnNames and rowCount of null object values. Each column's name + * will be taken from the columnNames array. + * + * @param columnNames array containing the names of the new columns; if this is null + * then the model has no columns + * + * @see #setDataVector + * @see #setValueAt + */ + DataTableModel(final Object[] columnNames) { + super(columnNames, 0); + } + + public void addRow(Object[] data, Object associatedData) { + super.addRow(data); + associated.add(getRowCount() - 1, associatedData); + } + + public void removeAllRows() { + for (int x = getRowCount(); x > 0; x--) { + super.removeRow(x - 1); + } + associated.clear(); + } + + @Override + public void removeRow(int row) { + super.removeRow(row); + associated.remove(row); + } + + public Object getAssociatedObject(int row) { + return associated.get(row); + } + + @Override + public boolean isCellEditable(int rowIndex, int mColIndex) { + return false; + } + } + + /** + * Open the component file. Present a chooser for the user to navigate to the file. + * + * @return true if the file was successfully opened; Note: side effect, is that the ComponentPresets read from the + * file are written to the table model. + */ + private boolean openComponentFile() { + final JFileChooser chooser = new JFileChooser(); + chooser.addChoosableFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER); + chooser.addChoosableFileFilter(FileHelper.CSV_FILE_FILTER); + chooser.setFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER); + chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); + if (editContext.getLastDirectory() != null) { + chooser.setCurrentDirectory(editContext.getLastDirectory()); + } + else { + chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultUserComponentDirectory()); + } + + int option = chooser.showOpenDialog(ComponentPresetEditor.this); + if (option != JFileChooser.APPROVE_OPTION) { + editContext.setOpenedFile(null); + log.info(Markers.USER_MARKER, "User decided not to open, option=" + option); + return false; + } + + File file = chooser.getSelectedFile(); + try { + if (file == null) { + log.info(Markers.USER_MARKER, "User did not select a file"); + return false; + } + + editContext.setLastDirectory(file.getParentFile()); + editContext.setMaterialsLoaded(null); + List presets = null; + + if (file.getName().toLowerCase().endsWith(".orc")) { + OpenRocketComponentDTO fileContents = new OpenRocketComponentSaver().unmarshalFromOpenRocketComponent(new FileReader(file)); + editContext.setMaterialsLoaded(new MaterialHolder(fileContents.asMaterialList())); + presets = fileContents.asComponentPresets(); + } + else { + if (file.getName().toLowerCase().endsWith(".csv")) { + file = file.getParentFile(); + } + presets = new ArrayList(); + MaterialHolder materialHolder = RocksimComponentFileTranslator.loadAll(presets, file); + editContext.setMaterialsLoaded(materialHolder); + } + if (presets != null) { + for (ComponentPreset next : presets) { + notifyResult(next); + } + editContext.setOpenedFile(file); + } + } 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()); + editContext.setOpenedFile(null); + editContext.setEditingSelected(false); + return false; + } + return true; + } + + private boolean saveAndHandleError() { + try { + return saveAsORC(); + } catch (Exception e1) { + JOptionPane.showMessageDialog(ComponentPresetEditor.this, e1.getLocalizedMessage(), + "Error saving ORC file.", JOptionPane.ERROR_MESSAGE); + return false; + } + } + + /** + * Save the contents of the table model as XML in .orc format. + * + * @return true if the file was written + * + * @throws JAXBException thrown if the data could not be marshaled + * @throws IOException thrown if there was a problem with writing the file + */ + private boolean saveAsORC() throws JAXBException, IOException { + File file = null; + + final JFileChooser chooser = new JFileChooser(); + chooser.addChoosableFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER); + + chooser.setFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER); + if (editContext.getOpenedFile() != null) { + chooser.setSelectedFile(editContext.getOpenedFile()); + } + else { + chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultUserComponentDirectory()); + } + + int option = chooser.showSaveDialog(ComponentPresetEditor.this); + if (option != JFileChooser.APPROVE_OPTION) { + log.info(Markers.USER_MARKER, "User decided not to save, option=" + option); + return false; + } + + file = chooser.getSelectedFile(); + if (file == null) { + log.info(Markers.USER_MARKER, "User did not select a file"); + return false; + } + + file = FileHelper.forceExtension(file, "orc"); + + MaterialHolder materials = new MaterialHolder(); + List presets = new ArrayList(); + + for (int x = 0; x < model.getRowCount(); x++) { + ComponentPreset preset = (ComponentPreset) model.getAssociatedObject(x); + // If we don't have a material already defined for saving... + if (materials.getMaterial(preset.get(ComponentPreset.MATERIAL)) == null) { + // Check if we loaded a material with this name. + Material m = null; + if (editContext.getMaterialsLoaded() != null) { + m = editContext.getMaterialsLoaded().getMaterial(preset.get + (ComponentPreset.MATERIAL)); + } + // If there was no material loaded with that name, use the component's material. + if (m == null) { + m = preset.get(ComponentPreset.MATERIAL); + } + materials.put(m); + } + presets.add(preset); + } + + return FileHelper.confirmWrite(file, this) && new OpenRocketComponentSaver().save(file, new ArrayList(materials.values()), presets); + } + + class OpenedFileContext { + + /** + * State variable to keep track of which file was opened, in case it needs to be saved back to that file. + */ + private File openedFile = null; + + /** + * Last directory; file chooser is set here so user doesn't have to keep navigating to a common area. + */ + private File lastDirectory = null; + + private boolean editingSelected = false; + + private MaterialHolder materialsLoaded = null; + + OpenedFileContext() { + } + + public File getOpenedFile() { + return openedFile; + } + + public void setOpenedFile(final File theOpenedFile) { + openedFile = theOpenedFile; + } + + public File getLastDirectory() { + return lastDirectory; + } + + public void setLastDirectory(final File theLastDirectory) { + lastDirectory = theLastDirectory; + } + + public boolean isEditingSelected() { + return editingSelected; + } + + public void setEditingSelected(final boolean theEditingSelected) { + editingSelected = theEditingSelected; + } + + public MaterialHolder getMaterialsLoaded() { + return materialsLoaded; + } + + public void setMaterialsLoaded(final MaterialHolder theMaterialsLoaded) { + materialsLoaded = theMaterialsLoaded; + } + } } diff --git a/core/src/net/sf/openrocket/gui/util/EditDecalHelper.java b/core/src/net/sf/openrocket/gui/util/EditDecalHelper.java index f67722ad1..0d6f2d074 100644 --- a/core/src/net/sf/openrocket/gui/util/EditDecalHelper.java +++ b/core/src/net/sf/openrocket/gui/util/EditDecalHelper.java @@ -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,12 +56,8 @@ public class EditDecalHelper { } - private static final Translator trans = Application.getTranslator(); + public void editDecal(Window parent, OpenRocketDocument doc, RocketComponent component, DecalImage decal) throws EditDecalHelperException { - private static final SwingPreferences prefs = ((SwingPreferences) Application.getPreferences()); - - public static 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); diff --git a/core/src/net/sf/openrocket/logging/LoggingSystemSetup.java b/core/src/net/sf/openrocket/logging/LoggingSystemSetup.java index baa3e0f64..774660803 100644 --- a/core/src/net/sf/openrocket/logging/LoggingSystemSetup.java +++ b/core/src/net/sf/openrocket/logging/LoggingSystemSetup.java @@ -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(); diff --git a/core/src/net/sf/openrocket/preset/loader/RocksimComponentFileTranslator.java b/core/src/net/sf/openrocket/preset/loader/RocksimComponentFileTranslator.java index 5e10c2af9..3593817dd 100644 --- a/core/src/net/sf/openrocket/preset/loader/RocksimComponentFileTranslator.java +++ b/core/src/net/sf/openrocket/preset/loader/RocksimComponentFileTranslator.java @@ -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(materialMap.values()), allPresets); diff --git a/core/src/net/sf/openrocket/startup/Application.java b/core/src/net/sf/openrocket/startup/Application.java index fe65093ab..c9a5fdf82 100644 --- a/core/src/net/sf/openrocket/startup/Application.java +++ b/core/src/net/sf/openrocket/startup/Application.java @@ -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; } diff --git a/core/src/net/sf/openrocket/startup/ApplicationModule.java b/core/src/net/sf/openrocket/startup/ApplicationModule.java deleted file mode 100644 index 0738d15e9..000000000 --- a/core/src/net/sf/openrocket/startup/ApplicationModule.java +++ /dev/null @@ -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); - } - -} diff --git a/core/src/net/sf/openrocket/startup/ApplicationModule2.java b/core/src/net/sf/openrocket/startup/ApplicationModule2.java deleted file mode 100644 index c86f54d31..000000000 --- a/core/src/net/sf/openrocket/startup/ApplicationModule2.java +++ /dev/null @@ -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 motorDatabaseProvider; - - - public ApplicationModule2(Provider motorDatabaseProvider) { - this.motorDatabaseProvider = motorDatabaseProvider; - } - - - @Override - protected void configure() { - bind(ThrustCurveMotorSetDatabase.class).toProvider(motorDatabaseProvider); - bind(MotorDatabase.class).toProvider(motorDatabaseProvider); - } - -} diff --git a/core/src/net/sf/openrocket/startup/BasicApplication.java b/core/src/net/sf/openrocket/startup/BasicApplication.java new file mode 100644 index 000000000..d1701e1f0 --- /dev/null +++ b/core/src/net/sf/openrocket/startup/BasicApplication.java @@ -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); + } + +} diff --git a/core/src/net/sf/openrocket/startup/BlockingComponentPresetDatabaseProvider.java b/core/src/net/sf/openrocket/startup/BlockingComponentPresetDatabaseProvider.java new file mode 100644 index 000000000..1e8392e72 --- /dev/null +++ b/core/src/net/sf/openrocket/startup/BlockingComponentPresetDatabaseProvider.java @@ -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 { + + 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(); + } + +} diff --git a/core/src/net/sf/openrocket/gui/util/BlockingMotorDatabaseProvider.java b/core/src/net/sf/openrocket/startup/BlockingMotorDatabaseProvider.java similarity index 97% rename from core/src/net/sf/openrocket/gui/util/BlockingMotorDatabaseProvider.java rename to core/src/net/sf/openrocket/startup/BlockingMotorDatabaseProvider.java index c35d1401f..d72ba2455 100644 --- a/core/src/net/sf/openrocket/gui/util/BlockingMotorDatabaseProvider.java +++ b/core/src/net/sf/openrocket/startup/BlockingMotorDatabaseProvider.java @@ -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; diff --git a/core/src/net/sf/openrocket/startup/ComponentPresetDatabaseLoader.java b/core/src/net/sf/openrocket/startup/ComponentPresetDatabaseLoader.java new file mode 100644 index 000000000..a4b9d6bd4 --- /dev/null +++ b/core/src/net/sf/openrocket/startup/ComponentPresetDatabaseLoader.java @@ -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 f = iterator.next(); + try { + ObjectInputStream ois = new ObjectInputStream(f.getV()); + List list = (List) 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 f = iterator.next(); + Collection 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 loadFile(String fileName, InputStream stream) { + log.debug("loading from file: " + fileName); + OpenRocketComponentLoader loader = new OpenRocketComponentLoader(); + Collection presets = loader.load(stream, fileName); + return presets; + + } +} diff --git a/core/src/net/sf/openrocket/startup/ConcurrentComponentPresetDatabaseLoader.java b/core/src/net/sf/openrocket/startup/ConcurrentComponentPresetDatabaseLoader.java deleted file mode 100644 index 0169238b7..000000000 --- a/core/src/net/sf/openrocket/startup/ConcurrentComponentPresetDatabaseLoader.java +++ /dev/null @@ -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 f = iterator.next(); - try { - ObjectInputStream ois = new ObjectInputStream(f.getV()); - List list = (List) 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 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 presets = loader.load(is, fileName); - PresetWriter writer = new PresetWriter(presets); - writerPool.execute(writer); - } - } - - private class PresetWriter implements Runnable { - private final Collection presets; - - public PresetWriter(Collection presets) { - super(); - this.presets = presets; - } - - @Override - public void run() { - presetCount += presets.size(); - componentPresetDao.addAll(presets); - } - - } -} diff --git a/core/src/net/sf/openrocket/startup/CoreServicesModule.java b/core/src/net/sf/openrocket/startup/CoreServicesModule.java new file mode 100644 index 000000000..8d906b307 --- /dev/null +++ b/core/src/net/sf/openrocket/startup/CoreServicesModule.java @@ -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); + } + +} diff --git a/core/src/net/sf/openrocket/startup/GuiModule.java b/core/src/net/sf/openrocket/startup/GuiModule.java new file mode 100644 index 000000000..be26ad27a --- /dev/null +++ b/core/src/net/sf/openrocket/startup/GuiModule.java @@ -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 motorDatabaseProvider; + private final Provider 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; + } + + +} diff --git a/core/src/net/sf/openrocket/startup/GuiceStartup.java b/core/src/net/sf/openrocket/startup/GuiceStartup.java deleted file mode 100644 index 589224fd3..000000000 --- a/core/src/net/sf/openrocket/startup/GuiceStartup.java +++ /dev/null @@ -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 - */ -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); - } - -} diff --git a/core/src/net/sf/openrocket/startup/Startup.java b/core/src/net/sf/openrocket/startup/JiJStartup.java similarity index 96% rename from core/src/net/sf/openrocket/startup/Startup.java rename to core/src/net/sf/openrocket/startup/JiJStartup.java index 56e91cf42..5b00881ea 100644 --- a/core/src/net/sf/openrocket/startup/Startup.java +++ b/core/src/net/sf/openrocket/startup/JiJStartup.java @@ -24,9 +24,9 @@ import net.sf.openrocket.startup.jij.PluginClasspathProvider; * * @author Sampo Niskanen */ -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(); diff --git a/core/src/net/sf/openrocket/startup/OSXStartup.java b/core/src/net/sf/openrocket/startup/OSXStartup.java index a5e8aefcf..fe657334f 100644 --- a/core/src/net/sf/openrocket/startup/OSXStartup.java +++ b/core/src/net/sf/openrocket/startup/OSXStartup.java @@ -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) { diff --git a/core/src/net/sf/openrocket/startup/Preferences.java b/core/src/net/sf/openrocket/startup/Preferences.java index 46e1239d0..dc3e2b64f 100644 --- a/core/src/net/sf/openrocket/startup/Preferences.java +++ b/core/src/net/sf/openrocket/startup/Preferences.java @@ -22,7 +22,7 @@ import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.UniqueID; public abstract class Preferences { - + /* * Well known string keys to preferences. * There are other strings out there in the source as well. @@ -37,40 +37,40 @@ public abstract class Preferences { public static final String EXPORT_EVENT_COMMENTS = "ExportEventComments"; public static final String EXPORT_COMMENT_CHARACTER = "ExportCommentCharacter"; public static final String USER_LOCAL = "locale"; - + public static final String PLOT_SHOW_POINTS = "ShowPlotPoints"; - + private static final String CHECK_UPDATES = "CheckUpdates"; public static final String LAST_UPDATE = "LastUpdateVersion"; - + public static final String MOTOR_DIAMETER_FILTER = "MotorDiameterMatch"; public static final String MOTOR_HIDE_SIMILAR = "MotorHideSimilar"; - + // Node names public static final String PREFERRED_THRUST_CURVE_MOTOR_NODE = "preferredThrustCurveMotors"; - private static final String AUTO_OPEN_LAST_DESIGN = "AUTO_OPEN_LAST_DESIGN"; - - /* - * ****************************************************************************************** - * - * Abstract methods which must be implemented by any derived class. - */ + private static final String AUTO_OPEN_LAST_DESIGN = "AUTO_OPEN_LAST_DESIGN"; + + /* + * ****************************************************************************************** + * + * Abstract methods which must be implemented by any derived class. + */ public abstract boolean getBoolean(String key, boolean defaultValue); - + public abstract void putBoolean(String key, boolean value); - + public abstract int getInt(String key, int defaultValue); - + public abstract void putInt(String key, int value); - + public abstract double getDouble(String key, double defaultValue); - + public abstract void putDouble(String key, double value); - + public abstract String getString(String key, String defaultValue); - + public abstract void putString(String key, String value); - + /** * Directory represents a way to collect multiple keys together. Implementors may * choose to concatenate the directory with the key using some special character. @@ -80,41 +80,41 @@ public abstract class Preferences { * @return */ public abstract String getString(String directory, String key, String defaultValue); - + public abstract void putString(String directory, String key, String value); - + /* * ****************************************************************************************** */ public final boolean getCheckUpdates() { return this.getBoolean(CHECK_UPDATES, BuildProperties.getDefaultCheckUpdates()); } - + public final void setCheckUpdates(boolean check) { this.putBoolean(CHECK_UPDATES, check); } - + public final double getDefaultMach() { // TODO: HIGH: implement custom default mach number return 0.3; } - - /** - * Enable/Disable the auto-opening of the last edited design file on startup. - */ - public final void setAutoOpenLastDesignOnStartup(boolean enabled) { - this.putBoolean(AUTO_OPEN_LAST_DESIGN, enabled); - } - - /** - * Answer if the auto-opening of the last edited design file on startup is enabled. - * - * @return true if the application should automatically open the last edited design file on startup. - */ - public final boolean isAutoOpenLastDesignOnStartupEnabled() { - return this.getBoolean(AUTO_OPEN_LAST_DESIGN, false); - } - + + /** + * Enable/Disable the auto-opening of the last edited design file on startup. + */ + public final void setAutoOpenLastDesignOnStartup(boolean enabled) { + this.putBoolean(AUTO_OPEN_LAST_DESIGN, enabled); + } + + /** + * Answer if the auto-opening of the last edited design file on startup is enabled. + * + * @return true if the application should automatically open the last edited design file on startup. + */ + public final boolean isAutoOpenLastDesignOnStartupEnabled() { + return this.getBoolean(AUTO_OPEN_LAST_DESIGN, false); + } + /** * Return the OpenRocket unique ID. * @@ -128,7 +128,7 @@ public abstract class Preferences { } return id; } - + /** * Returns a limited-range integer value from the preferences. If the value * in the preferences is negative or greater than max, then the default value @@ -145,7 +145,7 @@ public abstract class Preferences { return def; return v; } - + /** * Helper method that puts an integer choice value into the preferences. * @@ -155,7 +155,7 @@ public abstract class Preferences { public final void putChoice(String key, int value) { this.putInt(key, value); } - + /** * Retrieve an enum value from the user preferences. * @@ -168,19 +168,19 @@ public abstract class Preferences { if (def == null) { throw new BugException("Default value cannot be null"); } - + String value = getString(key, null); if (value == null) { return def; } - + try { return Enum.valueOf(def.getDeclaringClass(), value); } catch (IllegalArgumentException e) { return def; } } - + /** * Store an enum value to the user preferences. * @@ -194,12 +194,12 @@ public abstract class Preferences { putString(key, value.name()); } } - + public Color getDefaultColor(Class c) { - String color = get("componentColors", c, DEFAULT_COLORS); + String color = get("componentColors", c, StaticFieldHolder.DEFAULT_COLORS); if (color == null) return Color.BLACK; - + Color clr = parseColor(color); if (clr != null) { return clr; @@ -207,28 +207,28 @@ public abstract class Preferences { return Color.BLACK; } } - + public final void setDefaultColor(Class c, Color color) { if (color == null) return; putString("componentColors", c.getSimpleName(), stringifyColor(color)); } - - + + /** * Retrieve a Line style for the given component. * @param c * @return */ public final LineStyle getDefaultLineStyle(Class 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) { return LineStyle.SOLID; } } - + /** * Set a default line style for the given component. * @param c @@ -240,7 +240,7 @@ public abstract class Preferences { return; putString("componentStyle", c.getSimpleName(), style.name()); } - + /** * Get the default material type for the given component. * @param componentClass @@ -250,7 +250,7 @@ public abstract class Preferences { public Material getDefaultComponentMaterial( Class componentClass, Material.Type type) { - + String material = get("componentMaterials", componentClass, null); if (material != null) { try { @@ -260,18 +260,18 @@ public abstract class Preferences { } catch (IllegalArgumentException ignore) { } } - + 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); } - + /** * Set the default material for a component type. * @param componentClass @@ -279,11 +279,11 @@ public abstract class Preferences { */ public void setDefaultComponentMaterial( Class componentClass, Material material) { - + putString("componentMaterials", componentClass.getSimpleName(), material == null ? null : material.toStorableString()); } - + /** * get a net.sf.openrocket.util.Color object for the given key. * @param key @@ -297,7 +297,7 @@ public abstract class Preferences { } return c; } - + /** * set a net.sf.openrocket.util.Color preference value for the given key. * @param key @@ -306,7 +306,7 @@ public abstract class Preferences { public final void putColor(String key, Color value) { putString(key, stringifyColor(value)); } - + /** * Helper function to convert a string representation into a net.sf.openrocket.util.Color object. * @param color @@ -316,7 +316,7 @@ public abstract class Preferences { if (color == null) { return null; } - + String[] rgb = color.split(","); if (rgb.length == 3) { try { @@ -329,7 +329,7 @@ public abstract class Preferences { } return null; } - + /** * Helper function to convert a net.sf.openrocket.util.Color object into a * String before storing in a preference. @@ -340,7 +340,7 @@ public abstract class Preferences { String string = color.getRed() + "," + color.getGreen() + "," + color.getBlue(); return string; } - + /** * Special helper function which allows for a map of default values. * @@ -355,7 +355,7 @@ public abstract class Preferences { protected String get(String directory, Class componentClass, Map, String> defaultMap) { - + // Search preferences Class c = componentClass; while (c != null && RocketComponent.class.isAssignableFrom(c)) { @@ -364,10 +364,10 @@ public abstract class Preferences { return value; c = c.getSuperclass(); } - + if (defaultMap == null) return null; - + // Search defaults c = componentClass; while (RocketComponent.class.isAssignableFrom(c)) { @@ -376,50 +376,45 @@ public abstract class Preferences { return value; c = c.getSuperclass(); } - + return null; } - + public abstract void addUserMaterial(Material m); - + public abstract Set getUserMaterials(); - + public abstract void removeUserMaterial(Material m); - + public abstract void setComponentFavorite(ComponentPreset preset, ComponentPreset.Type type, boolean favorite); - + public abstract Set getComponentFavorites(ComponentPreset.Type type); - - /* - * Map of default line styles - */ - private static final HashMap, String> DEFAULT_LINE_STYLES = - new HashMap, 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 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, String> DEFAULT_LINE_STYLES = new HashMap, String>(); + static { + DEFAULT_LINE_STYLES.put(RocketComponent.class, LineStyle.SOLID.name()); + DEFAULT_LINE_STYLES.put(MassObject.class, LineStyle.DASHED.name()); + } + private static final HashMap, String> DEFAULT_COLORS = new HashMap, String>(); + static { + DEFAULT_COLORS.put(BodyComponent.class, "0,0,240"); + DEFAULT_COLORS.put(FinSet.class, "0,0,200"); + DEFAULT_COLORS.put(LaunchLug.class, "0,0,180"); + DEFAULT_COLORS.put(InternalComponent.class, "170,0,100"); + DEFAULT_COLORS.put(MassObject.class, "0,0,0"); + DEFAULT_COLORS.put(RecoveryDevice.class, "255,0,0"); + } } - - private static final HashMap, String> DEFAULT_COLORS = - new HashMap, String>(); - static { - DEFAULT_COLORS.put(BodyComponent.class, "0,0,240"); - DEFAULT_COLORS.put(FinSet.class, "0,0,200"); - DEFAULT_COLORS.put(LaunchLug.class, "0,0,180"); - DEFAULT_COLORS.put(InternalComponent.class, "170,0,100"); - DEFAULT_COLORS.put(MassObject.class, "0,0,0"); - DEFAULT_COLORS.put(RecoveryDevice.class, "255,0,0"); - } - - - + } diff --git a/core/src/net/sf/openrocket/startup/SerializeMotors.java b/core/src/net/sf/openrocket/startup/SerializeMotors.java index cf22958f5..a07bfff46 100644 --- a/core/src/net/sf/openrocket/startup/SerializeMotors.java +++ b/core/src/net/sf/openrocket/startup/SerializeMotors.java @@ -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); diff --git a/core/src/net/sf/openrocket/startup/SerializePresets.java b/core/src/net/sf/openrocket/startup/SerializePresets.java index f2259ab24..6fc329666 100644 --- a/core/src/net/sf/openrocket/startup/SerializePresets.java +++ b/core/src/net/sf/openrocket/startup/SerializePresets.java @@ -12,50 +12,40 @@ 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() { - - FileIterator iterator = DirectoryIterator.findDirectory("resources-src/datafiles/presets", new SimpleFileFilter("", false, "orc")); - - if (iterator == null) { - throw new RuntimeException("Can't find resources-src/presets directory"); - } - while (iterator.hasNext()) { - Pair f = iterator.next(); - String fileName = f.getU(); - InputStream is = f.getV(); - - OpenRocketComponentLoader loader = new OpenRocketComponentLoader(); - Collection presets = loader.load(is, fileName); - - this.addAll(presets); - - } - } - - }; + ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase(); - componentPresetDao.startLoading(); + FileIterator iterator = DirectoryIterator.findDirectory("resources-src/datafiles/presets", new SimpleFileFilter("", false, "orc")); + + if (iterator == null) { + throw new RuntimeException("Can't find resources-src/presets directory"); + } + while (iterator.hasNext()) { + Pair f = iterator.next(); + String fileName = f.getU(); + InputStream is = f.getV(); + + OpenRocketComponentLoader loader = new OpenRocketComponentLoader(); + Collection presets = loader.load(is, fileName); + + componentPresetDao.addAll(presets); + + } List list = componentPresetDao.listAll(); diff --git a/core/src/net/sf/openrocket/startup/ApplicationStartup.java b/core/src/net/sf/openrocket/startup/SwingApplication.java similarity index 71% rename from core/src/net/sf/openrocket/startup/ApplicationStartup.java rename to core/src/net/sf/openrocket/startup/SwingApplication.java index c469513d4..1bf5c7020 100644 --- a/core/src/net/sf/openrocket/startup/ApplicationStartup.java +++ b/core/src/net/sf/openrocket/startup/SwingApplication.java @@ -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 */ -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."); diff --git a/core/src/net/sf/openrocket/startup/TranslatorProvider.java b/core/src/net/sf/openrocket/startup/TranslatorProvider.java new file mode 100644 index 000000000..36731af90 --- /dev/null +++ b/core/src/net/sf/openrocket/startup/TranslatorProvider.java @@ -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 { + + 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)); + } + + + +} diff --git a/core/src/net/sf/openrocket/utils/RocksimConverter.java b/core/src/net/sf/openrocket/utils/RocksimConverter.java index 8a3ac1a0b..2b40334df 100644 --- a/core/src/net/sf/openrocket/utils/RocksimConverter.java +++ b/core/src/net/sf/openrocket/utils/RocksimConverter.java @@ -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()); } } diff --git a/core/test/net/sf/openrocket/AbstractBaseApplication.java b/core/test/net/sf/openrocket/AbstractBaseApplication.java deleted file mode 100644 index e5bdab0c6..000000000 --- a/core/test/net/sf/openrocket/AbstractBaseApplication.java +++ /dev/null @@ -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); - } - -} diff --git a/core/test/net/sf/openrocket/IntegrationTest.java b/core/test/net/sf/openrocket/IntegrationTest.java index 4080c88a8..302100753 100644 --- a/core/test/net/sf/openrocket/IntegrationTest.java +++ b/core/test/net/sf/openrocket/IntegrationTest.java @@ -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; + private static class EmptyComponentDbProvider implements Provider { + + final ComponentPresetDao db = new ComponentPresetDatabase(); + + @Override + public ComponentPresetDao get() { + return db; + } + } + + private static class MotorDbProvider implements Provider { + + final ThrustCurveMotorSetDatabase db = new ThrustCurveMotorSetDatabase(); + + public MotorDbProvider() { + db.addMotor(readMotor()); + + assertEquals(1, db.getMotorSets().size()); + } + + @Override + public ThrustCurveMotorSetDatabase get() { + return db; + } + } + @BeforeClass public static void setupMotorDatabase() { - final ThrustCurveMotorSetDatabase db = new ThrustCurveMotorSetDatabase(); - db.addMotor(readMotor()); - - assertEquals(1, db.getMotorSets().size()); - - ApplicationModule2 module = new ApplicationModule2(new Provider() { + Module dbOverrides = new AbstractModule() { @Override - public ThrustCurveMotorSetDatabase get() { - return db; + protected void configure() { + bind(ComponentPresetDao.class).toProvider(new EmptyComponentDbProvider()); + bind(MotorDatabase.class).toProvider(new MotorDbProvider()); } - }); - Injector injector2 = Application.getInjector().createChildInjector(module); + + }; + + 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()); } } diff --git a/core/test/net/sf/openrocket/file/rocksim/importt/RocksimLoaderTest.java b/core/test/net/sf/openrocket/file/rocksim/importt/RocksimLoaderTest.java index 856e55b5d..b7e6976e4 100644 --- a/core/test/net/sf/openrocket/file/rocksim/importt/RocksimLoaderTest.java +++ b/core/test/net/sf/openrocket/file/rocksim/importt/RocksimLoaderTest.java @@ -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 diff --git a/core/test/net/sf/openrocket/file/rocksim/importt/RocksimTestBase.java b/core/test/net/sf/openrocket/file/rocksim/importt/RocksimTestBase.java index d264e8132..0795fa9fa 100644 --- a/core/test/net/sf/openrocket/file/rocksim/importt/RocksimTestBase.java +++ b/core/test/net/sf/openrocket/file/rocksim/importt/RocksimTestBase.java @@ -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 components) { Assert.assertTrue("Components did not contain child", components.contains(child)); diff --git a/core/test/net/sf/openrocket/optimization/rocketoptimization/TestRocketOptimizationFunction.java b/core/test/net/sf/openrocket/optimization/rocketoptimization/TestRocketOptimizationFunction.java index fd9995255..608788a3e 100644 --- a/core/test/net/sf/openrocket/optimization/rocketoptimization/TestRocketOptimizationFunction.java +++ b/core/test/net/sf/openrocket/optimization/rocketoptimization/TestRocketOptimizationFunction.java @@ -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 diff --git a/core/test/net/sf/openrocket/optimization/rocketoptimization/modifiers/TestGenericModifier.java b/core/test/net/sf/openrocket/optimization/rocketoptimization/modifiers/TestGenericModifier.java index d7a83774e..46d1ba1a1 100644 --- a/core/test/net/sf/openrocket/optimization/rocketoptimization/modifiers/TestGenericModifier.java +++ b/core/test/net/sf/openrocket/optimization/rocketoptimization/modifiers/TestGenericModifier.java @@ -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 gm; diff --git a/core/test/net/sf/openrocket/plugin/PluginTest.java b/core/test/net/sf/openrocket/plugin/PluginTest.java index ce121e532..4af1b1157 100644 --- a/core/test/net/sf/openrocket/plugin/PluginTest.java +++ b/core/test/net/sf/openrocket/plugin/PluginTest.java @@ -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); diff --git a/core/test/net/sf/openrocket/simulation/customexpression/TestExpressions.java b/core/test/net/sf/openrocket/simulation/customexpression/TestExpressions.java index 47312038c..87c35a0e5 100644 --- a/core/test/net/sf/openrocket/simulation/customexpression/TestExpressions.java +++ b/core/test/net/sf/openrocket/simulation/customexpression/TestExpressions.java @@ -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() { diff --git a/core/test/net/sf/openrocket/util/BaseTestCase/BaseTestCase.java b/core/test/net/sf/openrocket/util/BaseTestCase/BaseTestCase.java index c5d1feb13..360982965 100644 --- a/core/test/net/sf/openrocket/util/BaseTestCase/BaseTestCase.java +++ b/core/test/net/sf/openrocket/util/BaseTestCase/BaseTestCase.java @@ -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; -public class BaseTestCase { +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 () { - - Application.setPreferences( new SwingPreferences() ); - + public static void setUp() throws Exception { + Module applicationModule = new CoreServicesModule(); + Module debugTranslator = new AbstractModule() { + + @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); } }