Refactored some gui specific utility classes from net.sf.openrocket.util to net.sf...
authorkruland2607 <kruland2607@180e2498-e6e9-4542-8430-84ac67f01cd8>
Thu, 1 Dec 2011 19:16:22 +0000 (19:16 +0000)
committerkruland2607 <kruland2607@180e2498-e6e9-4542-8430-84ac67f01cd8>
Thu, 1 Dec 2011 19:16:22 +0000 (19:16 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@213 180e2498-e6e9-4542-8430-84ac67f01cd8

56 files changed:
src/net/sf/openrocket/document/OpenRocketDocument.java
src/net/sf/openrocket/file/motor/MotorLoaderHelper.java
src/net/sf/openrocket/gui/components/SimulationExportPanel.java
src/net/sf/openrocket/gui/components/compass/Tester.java
src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java
src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
src/net/sf/openrocket/gui/configdialog/RocketConfig.java
src/net/sf/openrocket/gui/dialogs/AboutDialog.java
src/net/sf/openrocket/gui/dialogs/BugReportDialog.java
src/net/sf/openrocket/gui/dialogs/ComponentAnalysisDialog.java
src/net/sf/openrocket/gui/dialogs/CustomMaterialDialog.java
src/net/sf/openrocket/gui/dialogs/DebugLogDialog.java
src/net/sf/openrocket/gui/dialogs/DetailDialog.java
src/net/sf/openrocket/gui/dialogs/EditMotorConfigurationDialog.java
src/net/sf/openrocket/gui/dialogs/ExampleDesignDialog.java
src/net/sf/openrocket/gui/dialogs/LicenseDialog.java
src/net/sf/openrocket/gui/dialogs/MotorDatabaseLoadingDialog.java
src/net/sf/openrocket/gui/dialogs/PrintDialog.java
src/net/sf/openrocket/gui/dialogs/PrintSettingsDialog.java
src/net/sf/openrocket/gui/dialogs/ScaleDialog.java
src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java
src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java
src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorPlotDialog.java
src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java
src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java
src/net/sf/openrocket/gui/dialogs/optimization/OptimizationPlotDialog.java
src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java
src/net/sf/openrocket/gui/main/BasicFrame.java
src/net/sf/openrocket/gui/main/RocketActions.java
src/net/sf/openrocket/gui/main/SimulationEditDialog.java
src/net/sf/openrocket/gui/main/SimulationPanel.java
src/net/sf/openrocket/gui/main/SimulationRunDialog.java
src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java
src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java
src/net/sf/openrocket/gui/print/ConceptPrintDialog.java
src/net/sf/openrocket/gui/scalefigure/ScaleSelector.java
src/net/sf/openrocket/gui/util/ConcurrentProgressMonitor.java [new file with mode: 0644]
src/net/sf/openrocket/gui/util/ConcurrentProgressMonitorInputStream.java [new file with mode: 0644]
src/net/sf/openrocket/gui/util/FileHelper.java [new file with mode: 0644]
src/net/sf/openrocket/gui/util/GUIUtil.java [new file with mode: 0644]
src/net/sf/openrocket/gui/util/Icons.java [new file with mode: 0644]
src/net/sf/openrocket/gui/util/OpenFileWorker.java [new file with mode: 0644]
src/net/sf/openrocket/gui/util/SaveCSVWorker.java [new file with mode: 0644]
src/net/sf/openrocket/gui/util/SaveFileWorker.java [new file with mode: 0644]
src/net/sf/openrocket/gui/util/SimpleFileFilter.java [new file with mode: 0644]
src/net/sf/openrocket/startup/Startup2.java
src/net/sf/openrocket/util/ConcurrentProgressMonitor.java [deleted file]
src/net/sf/openrocket/util/ConcurrentProgressMonitorInputStream.java [deleted file]
src/net/sf/openrocket/util/FileHelper.java [deleted file]
src/net/sf/openrocket/util/GUIUtil.java [deleted file]
src/net/sf/openrocket/util/Icons.java [deleted file]
src/net/sf/openrocket/util/OpenFileWorker.java [deleted file]
src/net/sf/openrocket/util/SaveCSVWorker.java [deleted file]
src/net/sf/openrocket/util/SaveFileWorker.java [deleted file]
src/net/sf/openrocket/util/SimpleFileFilter.java [deleted file]
src/net/sf/openrocket/utils/MotorPlot.java

index c935bd294e0d5ca12e113a480390924ef43614bc..3853f4ab86a761529ea28b6864dc04ffc03d6d99 100644 (file)
@@ -12,6 +12,7 @@ import net.sf.openrocket.document.events.DocumentChangeEvent;
 import net.sf.openrocket.document.events.DocumentChangeListener;
 import net.sf.openrocket.document.events.SimulationChangeEvent;
 import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.gui.util.Icons;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.logging.TraceException;
@@ -22,7 +23,6 @@ import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.ArrayList;
 import net.sf.openrocket.util.BugException;
-import net.sf.openrocket.util.Icons;
 
 /**
  * Class describing an entire OpenRocket document, including a rocket and
index d3bbc3dc60e009686d9c8899793bb98cefb896f8..049738a49a42e17a1ed99361f0106f7b8bb40f8f 100644 (file)
@@ -11,12 +11,12 @@ import java.util.List;
 
 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.logging.LogHelper;
 import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.motor.ThrustCurveMotor;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.Pair;
-import net.sf.openrocket.util.SimpleFileFilter;
 
 public final class MotorLoaderHelper {
        
index cd73c5f9e1d55a37768f3a266b90cdacc2c720f0..30ef196b1aa125671372d1c44a5918ad6057acea 100644 (file)
@@ -21,6 +21,9 @@ import javax.swing.table.TableColumnModel;
 
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.gui.util.FileHelper;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.SaveCSVWorker;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.simulation.FlightData;
 import net.sf.openrocket.simulation.FlightDataBranch;
@@ -28,10 +31,7 @@ import net.sf.openrocket.simulation.FlightDataType;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
-import net.sf.openrocket.util.FileHelper;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Prefs;
-import net.sf.openrocket.util.SaveCSVWorker;
 
 public class SimulationExportPanel extends JPanel {
        
index eda95f5673f5efd116a5b1dcec419127f1e660a3..86a82a495fc2e8ca9a4f6996e96aee56e445bd09 100644 (file)
@@ -10,10 +10,10 @@ 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.unit.UnitGroup;
-import net.sf.openrocket.util.GUIUtil;
 
 public class Tester {
        
index 5bb3448bc5f8d0f698bc5b2925d2c28ec107ea46..a669b2dc57611027718d00d9b86402d16ef38e14 100644 (file)
@@ -8,13 +8,13 @@ import java.lang.reflect.InvocationTargetException;
 import javax.swing.JDialog;
 
 import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.BugException;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Reflection;
 
 /**
index 802434d76d2748001688823485068ed32e4a7e68..1ed1ccecb96a6e22bf1bfdab3b48fed06cea0a49 100644 (file)
@@ -35,6 +35,7 @@ import net.sf.openrocket.gui.components.ColorIcon;
 import net.sf.openrocket.gui.components.StyledLabel;
 import net.sf.openrocket.gui.components.StyledLabel.Style;
 import net.sf.openrocket.gui.components.UnitSelector;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.ComponentAssembly;
@@ -44,7 +45,6 @@ import net.sf.openrocket.rocketcomponent.NoseCone;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.UnitGroup;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Invalidatable;
 import net.sf.openrocket.util.LineStyle;
 import net.sf.openrocket.util.Prefs;
index 701295c2473d3ecfd9b4e447952a31d3eb3af5a2..c692f4983b0c81698372720cd93c0b3fa9021c68 100644 (file)
@@ -12,11 +12,11 @@ import javax.swing.JTextArea;
 
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.GUIUtil;
 
 public class RocketConfig extends RocketComponentConfig {
        private static final Translator trans = Application.getTranslator();
index 5f42865ba83c18ccbcb164371ac6540b0abba7c9..e02a3c26f4e85462dffa4f4fb1a46dcfe8556829 100644 (file)
@@ -14,11 +14,11 @@ import net.sf.openrocket.gui.components.DescriptionArea;
 import net.sf.openrocket.gui.components.StyledLabel;
 import net.sf.openrocket.gui.components.StyledLabel.Style;
 import net.sf.openrocket.gui.components.URLLabel;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.Icons;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.Chars;
-import net.sf.openrocket.util.GUIUtil;
-import net.sf.openrocket.util.Icons;
 import net.sf.openrocket.util.Prefs;
 
 public class AboutDialog extends JDialog {
index f9001bf2426edb9ee1b8a46784d42cf04ae1b497..27ae214caf351f4a27c033b695e101cd3d8c1cfe 100644 (file)
@@ -30,12 +30,12 @@ import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.communication.BugReporter;
 import net.sf.openrocket.gui.components.SelectableLabel;
 import net.sf.openrocket.gui.components.StyledLabel;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogLevelBufferLogger;
 import net.sf.openrocket.logging.LogLine;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.BugException;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.JarUtil;
 import net.sf.openrocket.util.Prefs;
 
index 7318d5c74f38921fde84f897d26a9ed492253c8c..8fba84e1607d675241042bc60de6d684dc9e230f 100644 (file)
@@ -50,6 +50,7 @@ import net.sf.openrocket.gui.components.StageSelector;
 import net.sf.openrocket.gui.components.StyledLabel;
 import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.gui.scalefigure.RocketPanel;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.masscalc.BasicMassCalculator;
 import net.sf.openrocket.masscalc.MassCalculator;
@@ -62,7 +63,6 @@ import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.Coordinate;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.Prefs;
 
index aad2f47e92dcd1d6a69573c9db317ee4bf21a030..5e5aece88236278b28b4e56ea451daa372f006f0 100644 (file)
@@ -18,10 +18,10 @@ import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.components.StyledLabel;
 import net.sf.openrocket.gui.components.UnitSelector;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.GUIUtil;
 
 public class CustomMaterialDialog extends JDialog {
 
index 53742c161bb6d647f9727286ddf74e83b665275a..5c36f5d878422e5e5d0120bf456993cf5edac281 100644 (file)
@@ -42,6 +42,7 @@ import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.gui.adaptors.Column;
 import net.sf.openrocket.gui.adaptors.ColumnTableModel;
 import net.sf.openrocket.gui.components.SelectableLabel;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.DelegatorLogger;
 import net.sf.openrocket.logging.LogHelper;
@@ -51,7 +52,6 @@ import net.sf.openrocket.logging.LogLine;
 import net.sf.openrocket.logging.StackTraceWriter;
 import net.sf.openrocket.logging.TraceException;
 import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.NumericComparator;
 
 public class DebugLogDialog extends JDialog {
index 87e36e67852418682510f1367e992e63994f9881..d1f0f547c67bbb9874b2cdc6e3dec8af7075968d 100644 (file)
@@ -6,7 +6,7 @@ import javax.swing.JOptionPane;
 import javax.swing.JScrollPane;
 import javax.swing.JTextArea;
 
-import net.sf.openrocket.util.GUIUtil;
+import net.sf.openrocket.gui.util.GUIUtil;
 
 public class DetailDialog {
        
index b1ef4a9c60e528c7e67324be7829fef0efff2ce6..0a41ce66546fa079efaac3223ba6b30d15baf01e 100644 (file)
@@ -28,6 +28,7 @@ import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.gui.dialogs.motor.MotorChooserDialog;
 import net.sf.openrocket.gui.main.BasicFrame;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.rocketcomponent.MotorMount;
@@ -35,7 +36,6 @@ import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.Chars;
-import net.sf.openrocket.util.GUIUtil;
 
 public class EditMotorConfigurationDialog extends JDialog {
        
index 069791ab51a4347cfee9b41389b65c3a31f1bf9a..95ad56dfe7d8c4cb022eeed56f114cf8aa73a10b 100644 (file)
@@ -27,10 +27,10 @@ import javax.swing.JScrollPane;
 import javax.swing.ListSelectionModel;
 
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.BugException;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.JarUtil;
 
 public class ExampleDesignDialog extends JDialog {
index 920e0b47fbe38e14000d21ddd069f507e9469241..c3e6141e59eee6cf050ebc799069b6402981fa49 100644 (file)
@@ -16,9 +16,9 @@ import javax.swing.JTextArea;
 
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.gui.components.StyledLabel;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.GUIUtil;
 
 public class LicenseDialog extends JDialog {
        private static final String LICENSE_FILENAME = "LICENSE.TXT";
index 006b30f43e2729d8ac18e33eb3365e3d56dfa165..203a903b0552e46714e574c4f8046dd1a7ae3e65 100644 (file)
@@ -13,10 +13,10 @@ import javax.swing.Timer;
 
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.GUIUtil;
 
 /**
  * A progress dialog displayed while loading motors.
index 924baace34a00de203146057f3de76edde215106..8d8721ef08a3700fc05e82799684c6f778d66a36 100644 (file)
@@ -34,12 +34,12 @@ import net.sf.openrocket.gui.print.PrintableContext;
 import net.sf.openrocket.gui.print.TemplateProperties;
 import net.sf.openrocket.gui.print.components.CheckTreeManager;
 import net.sf.openrocket.gui.print.components.RocketPrintTree;
+import net.sf.openrocket.gui.util.FileHelper;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.FileHelper;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Prefs;
 
 /**
index 183ee7a1ff75f6b8882423731efd0fe1b6421e01..53411709e87ad4aec6468d1c1b9e3edb70679029 100644 (file)
@@ -19,10 +19,10 @@ import net.sf.openrocket.gui.components.ColorChooserButton;
 import net.sf.openrocket.gui.print.PaperOrientation;
 import net.sf.openrocket.gui.print.PaperSize;
 import net.sf.openrocket.gui.print.PrintSettings;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.GUIUtil;
 
 /**
  * This class is a dialog for displaying advanced settings for printing rocket related info.
index c6ccc23987561d22fba64fdcdd2469759e8cd16a..fb8b32fdc38b8715789347f1f99ddbc98d0b60fe 100644 (file)
@@ -26,6 +26,7 @@ import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.components.BasicSlider;
 import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.BodyComponent;
@@ -53,7 +54,6 @@ import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.Reflection;
 import net.sf.openrocket.util.Reflection.Method;
index 08f72089297fa56ca21f5b01deeb8f727ac717ea..3ec6d6a1595622453e6bff8c9a986e53d0d801bc 100644 (file)
@@ -15,12 +15,12 @@ import javax.swing.JPanel;
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.communication.UpdateInfo;
 import net.sf.openrocket.gui.components.URLLabel;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.Icons;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.Chars;
 import net.sf.openrocket.util.ComparablePair;
-import net.sf.openrocket.util.GUIUtil;
-import net.sf.openrocket.util.Icons;
 
 public class UpdateInfoDialog extends JDialog {
        
index 8c6849e981f4d5a28a16e9d30af506083e401bb2..eeb939c7aa09e50ec6efa37bfaa921a9f99d85c7 100644 (file)
@@ -14,11 +14,11 @@ import javax.swing.JPanel;
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.gui.dialogs.MotorDatabaseLoadingDialog;
 import net.sf.openrocket.gui.dialogs.motor.thrustcurve.ThrustCurveMotorSelectionPanel;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.motor.ThrustCurveMotor;
 import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.GUIUtil;
 
 public class MotorChooserDialog extends JDialog implements CloseableDialog {
        
index 22238caa8f82c90b1c16a6e055a9c17426d4c96a..c1ecb7cfb9db2d935ca282a6bd2578016bd88127 100644 (file)
@@ -13,11 +13,11 @@ import javax.swing.JDialog;
 import javax.swing.JPanel;
 
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.motor.ThrustCurveMotor;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.UnitGroup;
-import net.sf.openrocket.util.GUIUtil;
 
 import org.jfree.chart.ChartFactory;
 import org.jfree.chart.ChartPanel;
index ca0fb811de48ab835f136e69a281f62d545f44af..28749156416023030c4981c6144b74a53fdd5b3b 100644 (file)
@@ -47,6 +47,8 @@ import net.sf.openrocket.gui.components.StyledLabel;
 import net.sf.openrocket.gui.components.StyledLabel.Style;
 import net.sf.openrocket.gui.dialogs.motor.CloseableDialog;
 import net.sf.openrocket.gui.dialogs.motor.MotorSelector;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.Icons;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.motor.Motor;
@@ -55,8 +57,6 @@ import net.sf.openrocket.motor.ThrustCurveMotor;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.BugException;
-import net.sf.openrocket.util.GUIUtil;
-import net.sf.openrocket.util.Icons;
 import net.sf.openrocket.util.Prefs;
 import net.sf.openrocket.utils.MotorCorrelation;
 
index 1478a2b12847f6bf39f6d1251d444750363763d7..66688bf5d70309d0c3c0bc723495277430888bc9 100644 (file)
@@ -65,6 +65,8 @@ import net.sf.openrocket.gui.components.UnitCellEditor;
 import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.gui.scalefigure.RocketFigure;
 import net.sf.openrocket.gui.scalefigure.ScaleScrollPane;
+import net.sf.openrocket.gui.util.FileHelper;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.optimization.general.OptimizationException;
@@ -88,8 +90,6 @@ import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.unit.Value;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Chars;
-import net.sf.openrocket.util.FileHelper;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Named;
 import net.sf.openrocket.util.Prefs;
 import net.sf.openrocket.util.TextUtil;
index c90c31ab1cbbf1cf893bb439db53871422584348..1df3214e282f5a3d85c7ddd42c1d2b96240a2e4f 100644 (file)
@@ -18,6 +18,7 @@ import javax.swing.JPanel;
 
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.gui.components.StyledLabel;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.optimization.general.Point;
@@ -27,7 +28,6 @@ import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.unit.Value;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.LinearInterpolator;
 import net.sf.openrocket.util.MathUtil;
 
index a13be044bc2382b973c575992b5563e0277e4d29..4c3f0fd6f2ca1e9e3923786fc67239d1c8b69e9f 100644 (file)
@@ -36,15 +36,15 @@ import net.sf.openrocket.gui.components.DescriptionArea;
 import net.sf.openrocket.gui.components.StyledLabel;
 import net.sf.openrocket.gui.components.StyledLabel.Style;
 import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.SimpleFileFilter;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Named;
 import net.sf.openrocket.util.Prefs;
-import net.sf.openrocket.util.SimpleFileFilter;
 import net.sf.openrocket.util.Utils;
 
 
index 5f2d92e016b255116fad7d889e44c1c6f241b12a..fb86fbb115e792fb03ed2ca0dec6362c953f0859 100644 (file)
@@ -83,6 +83,11 @@ import net.sf.openrocket.gui.dialogs.optimization.GeneralOptimizationDialog;
 import net.sf.openrocket.gui.dialogs.preferences.PreferencesDialog;
 import net.sf.openrocket.gui.main.componenttree.ComponentTree;
 import net.sf.openrocket.gui.scalefigure.RocketPanel;
+import net.sf.openrocket.gui.util.FileHelper;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.Icons;
+import net.sf.openrocket.gui.util.OpenFileWorker;
+import net.sf.openrocket.gui.util.SaveFileWorker;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
@@ -92,15 +97,10 @@ import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.Stage;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.BugException;
-import net.sf.openrocket.util.FileHelper;
-import net.sf.openrocket.util.GUIUtil;
-import net.sf.openrocket.util.Icons;
 import net.sf.openrocket.util.MemoryManagement;
 import net.sf.openrocket.util.MemoryManagement.MemoryData;
-import net.sf.openrocket.util.OpenFileWorker;
 import net.sf.openrocket.util.Prefs;
 import net.sf.openrocket.util.Reflection;
-import net.sf.openrocket.util.SaveFileWorker;
 import net.sf.openrocket.util.TestRockets;
 
 public class BasicFrame extends JFrame {
index 625afdab34efc0232c65bfc4ba027ec15da028a2..4bd754a93319f92b58ec1b47d0bc29a8f4f65542 100644 (file)
@@ -17,6 +17,7 @@ import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.gui.components.StyledLabel;
 import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
+import net.sf.openrocket.gui.util.Icons;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
@@ -24,7 +25,6 @@ import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.Stage;
 import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.Icons;
 import net.sf.openrocket.util.Pair;
 import net.sf.openrocket.util.Prefs;
 
index 92c2dac81aebc5a6d9c0a33b2c0c084338417346..39b5fbea2e934e3ae1c688a3e4a1ba51a3cd14a9 100644 (file)
@@ -43,6 +43,8 @@ import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.gui.plot.Axis;
 import net.sf.openrocket.gui.plot.PlotConfiguration;
 import net.sf.openrocket.gui.plot.SimulationPlotPanel;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.Icons;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.models.atmosphere.ExtendedISAModel;
 import net.sf.openrocket.rocketcomponent.Configuration;
@@ -57,9 +59,7 @@ import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.Chars;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.GeodeticComputationStrategy;
-import net.sf.openrocket.util.Icons;
 import net.sf.openrocket.util.Prefs;
 
 import org.jfree.chart.ChartFactory;
index 6a4bef03c65c0c5fbc38fc7f8331445578a2d83c..36b5a608d116e47d203b6b7011dfbfa0c65c1b4c 100644 (file)
@@ -34,6 +34,7 @@ import net.sf.openrocket.document.events.SimulationChangeEvent;
 import net.sf.openrocket.gui.adaptors.Column;
 import net.sf.openrocket.gui.adaptors.ColumnTableModel;
 import net.sf.openrocket.gui.components.StyledLabel;
+import net.sf.openrocket.gui.util.Icons;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
@@ -41,7 +42,6 @@ import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
 import net.sf.openrocket.simulation.FlightData;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.UnitGroup;
-import net.sf.openrocket.util.Icons;
 import net.sf.openrocket.util.Prefs;
 
 public class SimulationPanel extends JPanel {
index 9ac4a3690f3c86fb9d3bd63d9295026bfed47576..cc1be696683cec34d742763e29098d8af31a10aa 100644 (file)
@@ -23,6 +23,7 @@ import javax.swing.JProgressBar;
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.gui.dialogs.DetailDialog;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.Configuration;
@@ -38,7 +39,6 @@ import net.sf.openrocket.simulation.listeners.SimulationListener;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.Prefs;
 
index e1e1b2d7a9f0c2c758532ec41e5b8f3704a8ea27..0cd08ff1c396c861be4fa24c2acce227ce12c92f 100644 (file)
@@ -33,6 +33,7 @@ import javax.swing.JPanel;
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.gui.components.StyledLabel;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.simulation.FlightDataBranch;
 import net.sf.openrocket.simulation.FlightDataType;
@@ -41,7 +42,6 @@ import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.BugException;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.Prefs;
 
index f2afcae608ebcdc0b8de30052ef0fd60e1ea10d3..06544f52676938211927e56925044e36a4995b9e 100644 (file)
@@ -24,14 +24,14 @@ import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.gui.components.DescriptionArea;
 import net.sf.openrocket.gui.components.UnitSelector;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.Icons;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.simulation.FlightDataBranch;
 import net.sf.openrocket.simulation.FlightDataType;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
-import net.sf.openrocket.util.GUIUtil;
-import net.sf.openrocket.util.Icons;
 import net.sf.openrocket.util.Utils;
 
 /**
index 9347ecbff958575590cc8b4407b546d3ad6d9e42..9a07efa0893596b4df490c10273a72d1bf8588e7 100644 (file)
@@ -13,7 +13,7 @@ import javax.swing.JScrollPane;
 import javax.swing.SwingUtilities;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.util.GUIUtil;
+import net.sf.openrocket.gui.util.GUIUtil;
 
 public class ConceptPrintDialog extends JDialog {
        
index d4452d6c9bfbcf0d8ad9ebfdff3f5654c9b6488a..a93847d36505558016d526325ff9cfa11bf69c62 100644 (file)
@@ -12,7 +12,7 @@ import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.util.Icons;
+import net.sf.openrocket.gui.util.Icons;
 
 public class ScaleSelector extends JPanel {
 
diff --git a/src/net/sf/openrocket/gui/util/ConcurrentProgressMonitor.java b/src/net/sf/openrocket/gui/util/ConcurrentProgressMonitor.java
new file mode 100644 (file)
index 0000000..b6aa6ea
--- /dev/null
@@ -0,0 +1,61 @@
+package net.sf.openrocket.gui.util;
+
+import java.awt.Component;
+
+import javax.swing.ProgressMonitor;
+import javax.swing.SwingUtilities;
+
+
+/**
+ * A thread-safe <code>ProgressMonitor</code>.  This class may be instantiated
+ * and the method {@link #setProgress(int)} called safely from any thread.
+ * <p>
+ * Why the FSCK&!#&% isn't the default API version thread-safe?!?!
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class ConcurrentProgressMonitor extends ProgressMonitor {
+
+       public ConcurrentProgressMonitor(Component parentComponent, Object message,
+                       String note, int min, int max) {
+               super(parentComponent, message, note, min, max);
+       }
+
+       @Override
+       public void setProgress(final int nv) {
+               
+               if (SwingUtilities.isEventDispatchThread()) {
+                       super.setProgress(nv);
+               } else {
+                       
+                       SwingUtilities.invokeLater(new Runnable() {
+
+                               @Override
+                               public void run() {
+                                       ConcurrentProgressMonitor.super.setProgress(nv);
+                               }
+                               
+                       });
+               }
+       }
+       
+       
+       @Override
+       public void close() {
+               if (SwingUtilities.isEventDispatchThread()) {
+                       super.close();
+               } else {
+                       
+                       SwingUtilities.invokeLater(new Runnable() {
+
+                               @Override
+                               public void run() {
+                                       ConcurrentProgressMonitor.super.close();
+                               }
+                               
+                       });
+               }
+       }
+
+
+}
diff --git a/src/net/sf/openrocket/gui/util/ConcurrentProgressMonitorInputStream.java b/src/net/sf/openrocket/gui/util/ConcurrentProgressMonitorInputStream.java
new file mode 100644 (file)
index 0000000..ccc0d79
--- /dev/null
@@ -0,0 +1,144 @@
+package net.sf.openrocket.gui.util;
+
+import java.awt.Component;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+
+
+
+/**
+ * A functional equivalent of <code>ProgressMonitorInputStream</code> which 
+ * uses {@link ConcurrentProgressMonitor} and leaves the progress dialog open
+ * to be manually closed later on.
+ */
+
+public class ConcurrentProgressMonitorInputStream extends FilterInputStream {
+       private ConcurrentProgressMonitor monitor;
+       private int nread = 0;
+       private int size = 0;
+
+
+       /**
+        * Constructs an object to monitor the progress of an input stream.
+        *
+        * @param message Descriptive text to be placed in the dialog box
+        *                if one is popped up.
+        * @param parentComponent The component triggering the operation
+        *                        being monitored.
+        * @param in The input stream to be monitored.
+        */
+       public ConcurrentProgressMonitorInputStream(Component parentComponent,
+                       Object message, InputStream in) {
+               super(in);
+               try {
+                       size = in.available();
+               } catch (IOException ioe) {
+                       size = 0;
+               }
+               monitor = new ConcurrentProgressMonitor(parentComponent, message, null, 0,
+                               size + 1);
+       }
+
+
+       /**
+        * Get the ProgressMonitor object being used by this stream. Normally
+        * this isn't needed unless you want to do something like change the
+        * descriptive text partway through reading the file.
+        * @return the ProgressMonitor object used by this object 
+        */
+       public ConcurrentProgressMonitor getProgressMonitor() {
+               return monitor;
+       }
+
+
+       /**
+        * Overrides <code>FilterInputStream.read</code> 
+        * to update the progress monitor after the read.
+        */
+       @Override
+       public int read() throws IOException {
+               int c = in.read();
+               if (c >= 0)
+                       monitor.setProgress(++nread);
+               if (monitor.isCanceled()) {
+                       InterruptedIOException exc = new InterruptedIOException("progress");
+                       exc.bytesTransferred = nread;
+                       throw exc;
+               }
+               return c;
+       }
+
+
+       /**
+        * Overrides <code>FilterInputStream.read</code> 
+        * to update the progress monitor after the read.
+        */
+       @Override
+       public int read(byte b[]) throws IOException {
+               int nr = in.read(b);
+               if (nr > 0)
+                       monitor.setProgress(nread += nr);
+               if (monitor.isCanceled()) {
+                       InterruptedIOException exc = new InterruptedIOException("progress");
+                       exc.bytesTransferred = nread;
+                       throw exc;
+               }
+               return nr;
+       }
+
+
+       /**
+        * Overrides <code>FilterInputStream.read</code> 
+        * to update the progress monitor after the read.
+        */
+       @Override
+       public int read(byte b[], int off, int len) throws IOException {
+               int nr = in.read(b, off, len);
+               if (nr > 0)
+                       monitor.setProgress(nread += nr);
+               if (monitor.isCanceled()) {
+                       InterruptedIOException exc = new InterruptedIOException("progress");
+                       exc.bytesTransferred = nread;
+                       throw exc;
+               }
+               return nr;
+       }
+
+
+       /**
+        * Overrides <code>FilterInputStream.skip</code> 
+        * to update the progress monitor after the skip.
+        */
+       @Override
+       public long skip(long n) throws IOException {
+               long nr = in.skip(n);
+               if (nr > 0)
+                       monitor.setProgress(nread += nr);
+               return nr;
+       }
+
+
+       /**
+        * Overrides <code>FilterInputStream.close</code> 
+        * to close the progress monitor as well as the stream.
+        */
+       @Override
+       public void close() throws IOException {
+               in.close();
+        monitor.close();
+       }
+
+
+       /**
+        * Overrides <code>FilterInputStream.reset</code> 
+        * to reset the progress monitor as well as the stream.
+        */
+       @Override
+       public synchronized void reset() throws IOException {
+               in.reset();
+               nread = size - in.available();
+               monitor.setProgress(nread);
+       }
+}
diff --git a/src/net/sf/openrocket/gui/util/FileHelper.java b/src/net/sf/openrocket/gui/util/FileHelper.java
new file mode 100644 (file)
index 0000000..8c49639
--- /dev/null
@@ -0,0 +1,120 @@
+package net.sf.openrocket.gui.util;
+
+import java.awt.Component;
+import java.io.File;
+import java.io.IOException;
+
+import javax.swing.JOptionPane;
+import javax.swing.filechooser.FileFilter;
+
+import net.sf.openrocket.l10n.L10N;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
+
+/**
+ * Helper methods related to user-initiated file manipulation.
+ * <p>
+ * These methods log the necessary information to the debug log.
+* 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public final class FileHelper {
+       private static final LogHelper log = Application.getLogger();
+       private static final Translator trans = Application.getTranslator();
+       
+
+       // TODO: HIGH: Rename translation keys
+       
+       /** File filter for any rocket designs (*.ork, *.rkt) */
+       public static final FileFilter ALL_DESIGNS_FILTER =
+                       new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter1"),
+                                       ".ork", ".ork.gz", ".rkt", ".rkt.gz");
+       
+       /** File filter for OpenRocket designs (*.ork) */
+       public static final FileFilter OPENROCKET_DESIGN_FILTER =
+                       new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter2"), ".ork", ".ork.gz");
+       
+       /** File filter for RockSim designs (*.rkt) */
+       public static final FileFilter ROCKSIM_DESIGN_FILTER =
+                       new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter3"), ".rkt", ".rkt.gz");
+       
+       /** File filter for PDF files (*.pdf) */
+       public static final FileFilter PDF_FILTER =
+                       new SimpleFileFilter(trans.get("filetypes.pdf"), ".pdf");
+       
+       /** File filter for CSV files (*.csv) */
+       public static final FileFilter CSV_FILE_FILTER =
+                       new SimpleFileFilter(trans.get("SimExpPan.desc"), ".csv");
+       
+       
+
+
+
+       private FileHelper() {
+               // Prevent instantiation
+       }
+       
+       /**
+        * Ensure that the provided file has a file extension.  If the file does not have
+        * any extension, append the provided extension to it.
+        * 
+        * @param original              the original file
+        * @param extension             the extension to append if none exists (without preceding dot)
+        * @return                              the resulting filen
+        */
+       public static File ensureExtension(File original, String extension) {
+               
+               if (original.getName().indexOf('.') < 0) {
+                       log.debug(1, "File name does not contain extension, adding '" + extension + "'");
+                       String name = original.getAbsolutePath();
+                       name = name + "." + extension;
+                       return new File(name);
+               }
+               
+               return original;
+       }
+       
+       
+       /**
+        * Confirm that it is allowed to write to a file.  If the file exists,
+        * a confirmation dialog will be presented to the user to ensure overwriting is ok.
+        * 
+        * @param file          the file that is going to be written.
+        * @param parent        the parent component for the dialog.
+        * @return                      <code>true</code> to write, <code>false</code> to abort.
+        */
+       public static boolean confirmWrite(File file, Component parent) {
+               if (file.exists()) {
+                       log.info(1, "File " + file + " exists, confirming overwrite from user");
+                       int result = JOptionPane.showConfirmDialog(parent,
+                                       L10N.replace(trans.get("error.fileExists.desc"), "{filename}", file.getName()),
+                                       trans.get("error.fileExists.title"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
+                       if (result != JOptionPane.YES_OPTION) {
+                               log.user(1, "User decided not to overwrite the file");
+                               return false;
+                       }
+                       log.user(1, "User decided to overwrite the file");
+               }
+               return true;
+       }
+       
+       
+       /**
+        * Display an error message to the user that writing a file failed.
+        * 
+        * @param e                     the I/O exception that caused the error.
+        * @param parent        the parent component for the dialog.
+        */
+       public static void errorWriting(IOException e, Component parent) {
+               
+               log.warn(1, "Error writing to file", e);
+               JOptionPane.showMessageDialog(parent,
+                               new Object[] {
+                                               trans.get("error.writing.desc"),
+                                               e.getLocalizedMessage()
+                               }, trans.get("error.writing.title"), JOptionPane.ERROR_MESSAGE);
+               
+       }
+       
+}
diff --git a/src/net/sf/openrocket/gui/util/GUIUtil.java b/src/net/sf/openrocket/gui/util/GUIUtil.java
new file mode 100644 (file)
index 0000000..34258d5
--- /dev/null
@@ -0,0 +1,569 @@
+package net.sf.openrocket.gui.util;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Image;
+import java.awt.KeyboardFocusManager;
+import java.awt.Point;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.beans.PropertyChangeListener;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.imageio.ImageIO;
+import javax.swing.AbstractAction;
+import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.BoundedRangeModel;
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultBoundedRangeModel;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.DefaultListSelectionModel;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JRootPane;
+import javax.swing.JSlider;
+import javax.swing.JSpinner;
+import javax.swing.JTable;
+import javax.swing.JTree;
+import javax.swing.KeyStroke;
+import javax.swing.ListSelectionModel;
+import javax.swing.LookAndFeel;
+import javax.swing.RootPaneContainer;
+import javax.swing.SpinnerModel;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ChangeListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.DefaultTableColumnModel;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableModel;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.DefaultTreeSelectionModel;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreeSelectionModel;
+
+import net.sf.openrocket.gui.Resettable;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.BugException;
+import net.sf.openrocket.util.Invalidatable;
+import net.sf.openrocket.util.MemoryManagement;
+import net.sf.openrocket.util.Prefs;
+
+public class GUIUtil {
+       private static final LogHelper log = Application.getLogger();
+       
+       private static final KeyStroke ESCAPE = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+       private static final String CLOSE_ACTION_KEY = "escape:WINDOW_CLOSING";
+       
+       private static final List<Image> images = new ArrayList<Image>();
+       static {
+               loadImage("pix/icon/icon-256.png");
+               loadImage("pix/icon/icon-064.png");
+               loadImage("pix/icon/icon-048.png");
+               loadImage("pix/icon/icon-032.png");
+               loadImage("pix/icon/icon-016.png");
+       }
+       
+       private static void loadImage(String file) {
+               InputStream is;
+               
+               is = ClassLoader.getSystemResourceAsStream(file);
+               if (is == null)
+                       return;
+               
+               try {
+                       Image image = ImageIO.read(is);
+                       images.add(image);
+               } catch (IOException ignore) {
+                       ignore.printStackTrace();
+               }
+       }
+       
+       
+
+       /**
+        * Set suitable options for a single-use disposable dialog.  This includes
+        * setting ESC to close the dialog, adding the appropriate window icons and
+        * setting the location based on the platform.  If defaultButton is provided, 
+        * it is set to the default button action.
+        * <p>
+        * The default button must be already attached to the dialog.
+        * 
+        * @param dialog                the dialog.
+        * @param defaultButton the default button of the dialog, or <code>null</code>.
+        */
+       public static void setDisposableDialogOptions(JDialog dialog, JButton defaultButton) {
+               installEscapeCloseOperation(dialog);
+               setWindowIcons(dialog);
+               addModelNullingListener(dialog);
+               dialog.setLocationByPlatform(true);
+               dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+               dialog.pack();
+               if (defaultButton != null) {
+                       setDefaultButton(defaultButton);
+               }
+       }
+       
+       
+
+       /**
+        * Add the correct action to close a JDialog when the ESC key is pressed.
+        * The dialog is closed by sending is a WINDOW_CLOSING event.
+        * 
+        * @param dialog        the dialog for which to install the action.
+        */
+       public static void installEscapeCloseOperation(final JDialog dialog) {
+               Action dispatchClosing = new AbstractAction() {
+                       @Override
+                       public void actionPerformed(ActionEvent event) {
+                               log.user("Closing dialog " + dialog);
+                               dialog.dispatchEvent(new WindowEvent(dialog, WindowEvent.WINDOW_CLOSING));
+                       }
+               };
+               JRootPane root = dialog.getRootPane();
+               root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ESCAPE, CLOSE_ACTION_KEY);
+               root.getActionMap().put(CLOSE_ACTION_KEY, dispatchClosing);
+       }
+       
+       
+       /**
+        * Set the given button as the default button of the frame/dialog it is in.  The button
+        * must be first attached to the window component hierarchy.
+        * 
+        * @param button        the button to set as the default button.
+        */
+       public static void setDefaultButton(JButton button) {
+               Window w = SwingUtilities.windowForComponent(button);
+               if (w == null) {
+                       throw new IllegalArgumentException("Attach button to a window first.");
+               }
+               if (!(w instanceof RootPaneContainer)) {
+                       throw new IllegalArgumentException("Button not attached to RootPaneContainer, w=" + w);
+               }
+               ((RootPaneContainer) w).getRootPane().setDefaultButton(button);
+       }
+       
+       
+
+       /**
+        * Change the behavior of a component so that TAB and Shift-TAB cycles the focus of
+        * the components.  This is necessary for e.g. <code>JTextArea</code>.
+        * 
+        * @param c             the component to modify
+        */
+       public static void setTabToFocusing(Component c) {
+               Set<KeyStroke> strokes = new HashSet<KeyStroke>(Arrays.asList(KeyStroke.getKeyStroke("pressed TAB")));
+               c.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, strokes);
+               strokes = new HashSet<KeyStroke>(Arrays.asList(KeyStroke.getKeyStroke("shift pressed TAB")));
+               c.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, strokes);
+       }
+       
+       
+
+       /**
+        * Set the OpenRocket icons to the window icons.
+        * 
+        * @param window        the window to set.
+        */
+       public static void setWindowIcons(Window window) {
+               window.setIconImages(images);
+       }
+       
+       /**
+        * Add a listener to the provided window that will call {@link #setNullModels(Component)}
+        * on the window once it is closed.  This method may only be used on single-use
+        * windows and dialogs, that will never be shown again once closed!
+        * 
+        * @param window        the window to add the listener to.
+        */
+       public static void addModelNullingListener(final Window window) {
+               window.addWindowListener(new WindowAdapter() {
+                       @Override
+                       public void windowClosed(WindowEvent e) {
+                               log.debug("Clearing all models of window " + window);
+                               setNullModels(window);
+                               MemoryManagement.collectable(window);
+                       }
+               });
+       }
+       
+       
+
+       /**
+        * Set the best available look-and-feel into use.
+        */
+       public static void setBestLAF() {
+               /*
+                * Set the look-and-feel.  On Linux, Motif/Metal is sometimes incorrectly used 
+                * which is butt-ugly, so if the system l&f is Motif/Metal, we search for a few
+                * other alternatives.
+                */
+               try {
+                       // Set system L&F
+                       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+                       
+                       // Check whether we have an ugly L&F
+                       LookAndFeel laf = UIManager.getLookAndFeel();
+                       if (laf == null ||
+                                       laf.getName().matches(".*[mM][oO][tT][iI][fF].*") ||
+                                       laf.getName().matches(".*[mM][eE][tT][aA][lL].*")) {
+                               
+                               // Search for better LAF
+                               UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
+                               String lafNames[] = {
+                                               ".*[gG][tT][kK].*",
+                                               ".*[wW][iI][nN].*",
+                                               ".*[mM][aA][cC].*",
+                                               ".*[aA][qQ][uU][aA].*",
+                                               ".*[nN][iI][mM][bB].*"
+                               };
+                               
+                               lf: for (String lafName : lafNames) {
+                                       for (UIManager.LookAndFeelInfo l : info) {
+                                               if (l.getName().matches(lafName)) {
+                                                       UIManager.setLookAndFeel(l.getClassName());
+                                                       break lf;
+                                               }
+                                       }
+                               }
+                       }
+               } catch (Exception e) {
+                       log.warn("Error setting LAF: " + e);
+               }
+       }
+       
+       
+       /**
+        * Changes the size of the font of the specified component by the given amount.
+        * 
+        * @param component             the component for which to change the font
+        * @param size                  the change in the font size
+        */
+       public static void changeFontSize(JComponent component, float size) {
+               Font font = component.getFont();
+               font = font.deriveFont(font.getSize2D() + size);
+               component.setFont(font);
+       }
+       
+       
+
+       /**
+        * Automatically remember the size of a window.  This stores the window size in the user
+        * preferences when resizing/maximizing the window and sets the state on the first call.
+        */
+       public static void rememberWindowSize(final Window window) {
+               window.addComponentListener(new ComponentAdapter() {
+                       @Override
+                       public void componentResized(ComponentEvent e) {
+                               log.debug("Storing size of " + window.getClass().getName() + ": " + window.getSize());
+                               Prefs.setWindowSize(window.getClass(), window.getSize());
+                               if (window instanceof JFrame) {
+                                       if ((((JFrame) window).getExtendedState() & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH) {
+                                               log.debug("Storing maximized state of " + window.getClass().getName());
+                                               Prefs.setWindowMaximized(window.getClass());
+                                       }
+                               }
+                       }
+               });
+               
+               if (Prefs.isWindowMaximized(window.getClass())) {
+                       if (window instanceof JFrame) {
+                               ((JFrame) window).setExtendedState(JFrame.MAXIMIZED_BOTH);
+                       }
+               } else {
+                       Dimension dim = Prefs.getWindowSize(window.getClass());
+                       if (dim != null) {
+                               window.setSize(dim);
+                       }
+               }
+       }
+       
+       
+       /**
+        * Automatically remember the position of a window.  The position is stored in the user preferences
+        * every time the window is moved and set from there when first calling this method.
+        */
+       public static void rememberWindowPosition(final Window window) {
+               window.addComponentListener(new ComponentAdapter() {
+                       @Override
+                       public void componentMoved(ComponentEvent e) {
+                               Prefs.setWindowPosition(window.getClass(), window.getLocation());
+                       }
+               });
+               
+               // Set window position according to preferences, and set prefs when moving
+               Point position = Prefs.getWindowPosition(window.getClass());
+               if (position != null) {
+                       window.setLocationByPlatform(false);
+                       window.setLocation(position);
+               }
+       }
+       
+       
+       /**
+        * Changes the style of the font of the specified border.
+        * 
+        * @param border                the component for which to change the font
+        * @param style                 the change in the font style
+        */
+       public static void changeFontStyle(TitledBorder border, int style) {
+               /*
+                * The fix of JRE bug #4129681 causes a TitledBorder occasionally to
+                * return a null font.  We try to work around the issue by detecting it
+                * and reverting to the font of a JLabel instead.
+                */
+               Font font = border.getTitleFont();
+               if (font == null) {
+                       log.error("Border font is null, reverting to JLabel font");
+                       font = new JLabel().getFont();
+                       if (font == null) {
+                               log.error("JLabel font is null, not modifying font");
+                               return;
+                       }
+               }
+               font = font.deriveFont(style);
+               if (font == null) {
+                       throw new BugException("Derived font is null");
+               }
+               border.setTitleFont(font);
+       }
+       
+       
+
+       /**
+        * Traverses recursively the component tree, and sets all applicable component 
+        * models to null, so as to remove the listener connections.  After calling this
+        * method the component hierarchy should no longed be used.
+        * <p>
+        * All components that use custom models should be added to this method, as
+        * there exists no standard way of removing the model from a component.
+        * 
+        * @param c             the component (<code>null</code> is ok)
+        */
+       public static void setNullModels(Component c) {
+               if (c == null)
+                       return;
+               
+               // Remove various listeners
+               for (ComponentListener l : c.getComponentListeners()) {
+                       c.removeComponentListener(l);
+               }
+               for (FocusListener l : c.getFocusListeners()) {
+                       c.removeFocusListener(l);
+               }
+               for (MouseListener l : c.getMouseListeners()) {
+                       c.removeMouseListener(l);
+               }
+               for (PropertyChangeListener l : c.getPropertyChangeListeners()) {
+                       c.removePropertyChangeListener(l);
+               }
+               for (PropertyChangeListener l : c.getPropertyChangeListeners("model")) {
+                       c.removePropertyChangeListener("model", l);
+               }
+               for (PropertyChangeListener l : c.getPropertyChangeListeners("action")) {
+                       c.removePropertyChangeListener("action", l);
+               }
+               
+               // Remove models for known components
+               //  Why the FSCK must this be so hard?!?!?
+               
+               if (c instanceof JSpinner) {
+                       
+                       JSpinner spinner = (JSpinner) c;
+                       for (ChangeListener l : spinner.getChangeListeners()) {
+                               spinner.removeChangeListener(l);
+                       }
+                       SpinnerModel model = spinner.getModel();
+                       spinner.setModel(new SpinnerNumberModel());
+                       if (model instanceof Invalidatable) {
+                               ((Invalidatable) model).invalidate();
+                       }
+                       
+               } else if (c instanceof JSlider) {
+                       
+                       JSlider slider = (JSlider) c;
+                       for (ChangeListener l : slider.getChangeListeners()) {
+                               slider.removeChangeListener(l);
+                       }
+                       BoundedRangeModel model = slider.getModel();
+                       slider.setModel(new DefaultBoundedRangeModel());
+                       if (model instanceof Invalidatable) {
+                               ((Invalidatable) model).invalidate();
+                       }
+                       
+               } else if (c instanceof JComboBox) {
+                       
+                       JComboBox combo = (JComboBox) c;
+                       for (ActionListener l : combo.getActionListeners()) {
+                               combo.removeActionListener(l);
+                       }
+                       ComboBoxModel model = combo.getModel();
+                       combo.setModel(new DefaultComboBoxModel());
+                       if (model instanceof Invalidatable) {
+                               ((Invalidatable) model).invalidate();
+                       }
+                       
+               } else if (c instanceof AbstractButton) {
+                       
+                       AbstractButton button = (AbstractButton) c;
+                       for (ActionListener l : button.getActionListeners()) {
+                               button.removeActionListener(l);
+                       }
+                       Action model = button.getAction();
+                       button.setAction(new AbstractAction() {
+                               @Override
+                               public void actionPerformed(ActionEvent e) {
+                               }
+                       });
+                       if (model instanceof Invalidatable) {
+                               ((Invalidatable) model).invalidate();
+                       }
+                       
+               } else if (c instanceof JTable) {
+                       
+                       JTable table = (JTable) c;
+                       TableModel model1 = table.getModel();
+                       table.setModel(new DefaultTableModel());
+                       if (model1 instanceof Invalidatable) {
+                               ((Invalidatable) model1).invalidate();
+                       }
+                       
+                       TableColumnModel model2 = table.getColumnModel();
+                       table.setColumnModel(new DefaultTableColumnModel());
+                       if (model2 instanceof Invalidatable) {
+                               ((Invalidatable) model2).invalidate();
+                       }
+                       
+                       ListSelectionModel model3 = table.getSelectionModel();
+                       table.setSelectionModel(new DefaultListSelectionModel());
+                       if (model3 instanceof Invalidatable) {
+                               ((Invalidatable) model3).invalidate();
+                       }
+                       
+               } else if (c instanceof JTree) {
+                       
+                       JTree tree = (JTree) c;
+                       TreeModel model1 = tree.getModel();
+                       tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
+                       if (model1 instanceof Invalidatable) {
+                               ((Invalidatable) model1).invalidate();
+                       }
+                       
+                       TreeSelectionModel model2 = tree.getSelectionModel();
+                       tree.setSelectionModel(new DefaultTreeSelectionModel());
+                       if (model2 instanceof Invalidatable) {
+                               ((Invalidatable) model2).invalidate();
+                       }
+                       
+               } else if (c instanceof Resettable) {
+                       
+                       ((Resettable) c).resetModel();
+                       
+               }
+               
+               // Recurse the component
+               if (c instanceof Container) {
+                       Component[] cs = ((Container) c).getComponents();
+                       for (Component sub : cs)
+                               setNullModels(sub);
+               }
+               
+       }
+       
+       
+
+       /**
+        * A mouse listener that toggles the state of a boolean value in a table model
+        * when clicked on another column of the table.
+        * <p>
+        * NOTE:  If the table model does not extend AbstractTableModel, the model must
+        * fire a change event (which in normal table usage is not necessary).
+        * 
+        * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+        */
+       public static class BooleanTableClickListener extends MouseAdapter {
+               
+               private final JTable table;
+               private final int clickColumn;
+               private final int booleanColumn;
+               
+               
+               public BooleanTableClickListener(JTable table) {
+                       this(table, 1, 0);
+               }
+               
+               
+               public BooleanTableClickListener(JTable table, int clickColumn, int booleanColumn) {
+                       this.table = table;
+                       this.clickColumn = clickColumn;
+                       this.booleanColumn = booleanColumn;
+               }
+               
+               @Override
+               public void mouseClicked(MouseEvent e) {
+                       if (e.getButton() != MouseEvent.BUTTON1)
+                               return;
+                       
+                       Point p = e.getPoint();
+                       int col = table.columnAtPoint(p);
+                       if (col < 0)
+                               return;
+                       col = table.convertColumnIndexToModel(col);
+                       if (col != clickColumn)
+                               return;
+                       
+                       int row = table.rowAtPoint(p);
+                       if (row < 0)
+                               return;
+                       row = table.convertRowIndexToModel(row);
+                       if (row < 0)
+                               return;
+                       
+                       TableModel model = table.getModel();
+                       Object value = model.getValueAt(row, booleanColumn);
+                       
+                       if (!(value instanceof Boolean)) {
+                               throw new IllegalStateException("Table value at row=" + row + " col=" +
+                                               booleanColumn + " is not a Boolean, value=" + value);
+                       }
+                       
+                       Boolean b = (Boolean) value;
+                       b = !b;
+                       model.setValueAt(b, row, booleanColumn);
+                       if (model instanceof AbstractTableModel) {
+                               ((AbstractTableModel) model).fireTableCellUpdated(row, booleanColumn);
+                       }
+               }
+               
+       }
+       
+}
diff --git a/src/net/sf/openrocket/gui/util/Icons.java b/src/net/sf/openrocket/gui/util/Icons.java
new file mode 100644 (file)
index 0000000..8adf191
--- /dev/null
@@ -0,0 +1,102 @@
+package net.sf.openrocket.gui.util;
+
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
+
+
+public class Icons {
+       private static final LogHelper log = Application.getLogger();
+       private static final Translator trans = Application.getTranslator();
+       
+       static {
+               log.debug("Starting to load icons");
+       }
+       
+       /**
+        * Icons used for showing the status of a simulation (up to date, out of date, etc).
+        */
+       public static final Map<Simulation.Status, Icon> SIMULATION_STATUS_ICON_MAP;
+       static {
+               HashMap<Simulation.Status, Icon> map = new HashMap<Simulation.Status, Icon>();
+               map.put(Simulation.Status.NOT_SIMULATED, loadImageIcon("pix/spheres/gray-16x16.png", "Not simulated"));
+               map.put(Simulation.Status.UPTODATE, loadImageIcon("pix/spheres/green-16x16.png", "Up to date"));
+               map.put(Simulation.Status.LOADED, loadImageIcon("pix/spheres/yellow-16x16.png", "Loaded from file"));
+               map.put(Simulation.Status.OUTDATED, loadImageIcon("pix/spheres/red-16x16.png", "Out-of-date"));
+               map.put(Simulation.Status.EXTERNAL, loadImageIcon("pix/spheres/blue-16x16.png", "Imported data"));
+               SIMULATION_STATUS_ICON_MAP = Collections.unmodifiableMap(map);
+       }
+       
+       public static final Icon SIMULATION_LISTENER_OK;
+       public static final Icon SIMULATION_LISTENER_ERROR;
+       static {
+               SIMULATION_LISTENER_OK = SIMULATION_STATUS_ICON_MAP.get(Simulation.Status.UPTODATE);
+               SIMULATION_LISTENER_ERROR = SIMULATION_STATUS_ICON_MAP.get(Simulation.Status.OUTDATED);
+       }
+       
+
+       public static final Icon FILE_NEW = loadImageIcon("pix/icons/document-new.png", "New document");
+       public static final Icon FILE_OPEN = loadImageIcon("pix/icons/document-open.png", "Open document");
+       public static final Icon FILE_OPEN_EXAMPLE = loadImageIcon("pix/icons/document-open-example.png", "Open example document");
+       public static final Icon FILE_SAVE = loadImageIcon("pix/icons/document-save.png", "Save document");
+       public static final Icon FILE_SAVE_AS = loadImageIcon("pix/icons/document-save-as.png", "Save document as");
+       public static final Icon FILE_PRINT = loadImageIcon("pix/icons/document-print.png", "Print document");
+       public static final Icon FILE_CLOSE = loadImageIcon("pix/icons/document-close.png", "Close document");
+       public static final Icon FILE_QUIT = loadImageIcon("pix/icons/application-exit.png", "Quit OpenRocket");
+       
+       public static final Icon EDIT_UNDO = loadImageIcon("pix/icons/edit-undo.png", trans.get("Icons.Undo"));
+       public static final Icon EDIT_REDO = loadImageIcon("pix/icons/edit-redo.png", trans.get("Icons.Redo"));
+       public static final Icon EDIT_CUT = loadImageIcon("pix/icons/edit-cut.png", "Cut");
+       public static final Icon EDIT_COPY = loadImageIcon("pix/icons/edit-copy.png", "Copy");
+       public static final Icon EDIT_PASTE = loadImageIcon("pix/icons/edit-paste.png", "Paste");
+       public static final Icon EDIT_DELETE = loadImageIcon("pix/icons/edit-delete.png", "Delete");
+       public static final Icon EDIT_SCALE = loadImageIcon("pix/icons/edit-scale.png", "Scale");
+       
+       public static final Icon HELP_ABOUT = loadImageIcon("pix/icons/help-about.png", "About");
+       public static final Icon HELP_BUG_REPORT = loadImageIcon("pix/icons/help-bug.png", "Bug report");
+       public static final Icon HELP_DEBUG_LOG = loadImageIcon("pix/icons/help-log.png", "Debug log");
+       public static final Icon HELP_LICENSE = loadImageIcon("pix/icons/help-license.png", "License");
+       
+       public static final Icon ZOOM_IN = loadImageIcon("pix/icons/zoom-in.png", "Zoom in");
+       public static final Icon ZOOM_OUT = loadImageIcon("pix/icons/zoom-out.png", "Zoom out");
+       
+       public static final Icon PREFERENCES = loadImageIcon("pix/icons/preferences.png", "Preferences");
+       
+       public static final Icon DELETE = loadImageIcon("pix/icons/delete.png", "Delete");
+       
+       static {
+               log.debug("Icons loaded");
+       }
+       
+       /**
+        * Load an ImageIcon from the specified file.  The file is obtained as a system
+        * resource from the normal classpath.  If the file cannot be loaded a bug dialog
+        * is opened and <code>null</code> is returned.
+        * 
+        * @param file  the file to load.
+        * @param name  the description of the icon.
+        * @return              the ImageIcon, or null if could not be loaded (after the user closes the dialog)
+        */
+       public static ImageIcon loadImageIcon(String file, String name) {
+               if (System.getProperty("openrocket.unittest") != null) {
+                       return new ImageIcon();
+               }
+               
+               URL url = ClassLoader.getSystemResource(file);
+               if (url == null) {
+                       ExceptionHandler.handleErrorCondition("Image file " + file + " not found, ignoring.");
+                       return null;
+               }
+               return new ImageIcon(url, name);
+       }
+}
diff --git a/src/net/sf/openrocket/gui/util/OpenFileWorker.java b/src/net/sf/openrocket/gui/util/OpenFileWorker.java
new file mode 100644 (file)
index 0000000..a52692e
--- /dev/null
@@ -0,0 +1,175 @@
+package net.sf.openrocket.gui.util;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+
+import javax.swing.SwingWorker;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.file.RocketLoader;
+import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.MathUtil;
+
+
+/**
+ * A SwingWorker thread that opens a rocket design file.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class OpenFileWorker extends SwingWorker<OpenRocketDocument, Void> {
+       private static final LogHelper log = Application.getLogger();
+       
+       private final File file;
+       private final InputStream stream;
+       private final RocketLoader loader;
+       
+       public OpenFileWorker(File file, RocketLoader loader) {
+               this.file = file;
+               this.stream = null;
+               this.loader = loader;
+       }
+       
+       
+       public OpenFileWorker(InputStream stream, RocketLoader loader) {
+               this.stream = stream;
+               this.file = null;
+               this.loader = loader;
+       }
+       
+       public RocketLoader getRocketLoader() {
+               return loader;
+       }
+       
+       @Override
+       protected OpenRocketDocument doInBackground() throws Exception {
+               InputStream is;
+               
+               // Get the correct input stream
+               if (file != null) {
+                       is = new FileInputStream(file);
+               } else {
+                       is = stream;
+               }
+               
+               // Buffer stream unless already buffered
+               if (!(is instanceof BufferedInputStream)) {
+                       is = new BufferedInputStream(is);
+               }
+               
+               // Encapsulate in a ProgressInputStream
+               is = new ProgressInputStream(is);
+               
+               try {
+                       return loader.load(is);
+               } finally {
+                       try {
+                               is.close();
+                       } catch (Exception e) {
+                               ExceptionHandler.handleErrorCondition("Error closing file", e);
+                       }
+               }
+       }
+       
+       
+
+
+       private class ProgressInputStream extends FilterInputStream {
+               
+               private final int size;
+               private int readBytes = 0;
+               private int progress = -1;
+               
+               protected ProgressInputStream(InputStream in) {
+                       super(in);
+                       int s;
+                       try {
+                               s = in.available();
+                       } catch (IOException e) {
+                               log.info("Exception while estimating available bytes!", e);
+                               s = 0;
+                       }
+                       size = Math.max(s, 1);
+               }
+               
+               
+
+               @Override
+               public int read() throws IOException {
+                       int c = in.read();
+                       if (c >= 0) {
+                               readBytes++;
+                               setProgress();
+                       }
+                       if (isCancelled()) {
+                               throw new InterruptedIOException("OpenFileWorker was cancelled");
+                       }
+                       return c;
+               }
+               
+               @Override
+               public int read(byte[] b, int off, int len) throws IOException {
+                       int n = in.read(b, off, len);
+                       if (n > 0) {
+                               readBytes += n;
+                               setProgress();
+                       }
+                       if (isCancelled()) {
+                               throw new InterruptedIOException("OpenFileWorker was cancelled");
+                       }
+                       return n;
+               }
+               
+               @Override
+               public int read(byte[] b) throws IOException {
+                       int n = in.read(b);
+                       if (n > 0) {
+                               readBytes += n;
+                               setProgress();
+                       }
+                       if (isCancelled()) {
+                               throw new InterruptedIOException("OpenFileWorker was cancelled");
+                       }
+                       return n;
+               }
+               
+               @Override
+               public long skip(long n) throws IOException {
+                       long nr = in.skip(n);
+                       if (nr > 0) {
+                               readBytes += nr;
+                               setProgress();
+                       }
+                       if (isCancelled()) {
+                               throw new InterruptedIOException("OpenFileWorker was cancelled");
+                       }
+                       return nr;
+               }
+               
+               @Override
+               public synchronized void reset() throws IOException {
+                       in.reset();
+                       readBytes = size - in.available();
+                       setProgress();
+                       if (isCancelled()) {
+                               throw new InterruptedIOException("OpenFileWorker was cancelled");
+                       }
+               }
+               
+               
+
+               private void setProgress() {
+                       int p = MathUtil.clamp(readBytes * 100 / size, 0, 100);
+                       if (progress != p) {
+                               progress = p;
+                               OpenFileWorker.this.setProgress(progress);
+                       }
+               }
+       }
+}
diff --git a/src/net/sf/openrocket/gui/util/SaveCSVWorker.java b/src/net/sf/openrocket/gui/util/SaveCSVWorker.java
new file mode 100644 (file)
index 0000000..585a63a
--- /dev/null
@@ -0,0 +1,132 @@
+package net.sf.openrocket.gui.util;
+
+import java.awt.Window;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+
+import javax.swing.JOptionPane;
+import javax.swing.SwingWorker;
+
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.file.CSVExport;
+import net.sf.openrocket.gui.dialogs.SwingWorkerDialog;
+import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.simulation.FlightDataBranch;
+import net.sf.openrocket.simulation.FlightDataType;
+import net.sf.openrocket.unit.Unit;
+import net.sf.openrocket.util.BugException;
+import net.sf.openrocket.util.ProgressOutputStream;
+
+
+public class SaveCSVWorker extends SwingWorker<Void, Void> {
+       
+       private static final int BYTES_PER_FIELD_PER_POINT = 7;
+
+       private final File file;
+       private final Simulation simulation;
+       private final FlightDataBranch branch;
+       private final FlightDataType[] fields;
+       private final Unit[] units;
+       private final String fieldSeparator;
+       private final String commentStarter;
+       private final boolean simulationComments;
+       private final boolean fieldComments;
+       private final boolean eventComments;
+       
+       
+       public SaveCSVWorker(File file, Simulation simulation, FlightDataBranch branch,
+                       FlightDataType[] fields, Unit[] units, String fieldSeparator, String commentStarter,
+                       boolean simulationComments, boolean fieldComments, boolean eventComments) {
+               this.file = file;
+               this.simulation = simulation;
+               this.branch = branch;
+               this.fields = fields;
+               this.units = units;
+               this.fieldSeparator = fieldSeparator;
+               this.commentStarter = commentStarter;
+               this.simulationComments = simulationComments;
+               this.fieldComments = fieldComments;
+               this.eventComments = eventComments;
+       }
+
+
+       @Override
+       protected Void doInBackground() throws Exception {
+               
+               int estimate = BYTES_PER_FIELD_PER_POINT * fields.length * branch.getLength();
+               estimate = Math.max(estimate, 1000);
+               
+               // Create the ProgressOutputStream that provides progress estimates
+               ProgressOutputStream os = new ProgressOutputStream(
+                               new BufferedOutputStream(new FileOutputStream(file)), 
+                               estimate, this) {
+                       
+                       @Override
+                       protected void setProgress(int progress) {
+                               SaveCSVWorker.this.setProgress(progress);
+                       }
+                       
+               };
+               
+               try {
+                       CSVExport.exportCSV(os, simulation, branch, fields, units, fieldSeparator, 
+                                       commentStarter, simulationComments, fieldComments, eventComments);
+               } finally {
+                       try {
+                               os.close();
+                       } catch (Exception e) {
+                               ExceptionHandler.handleErrorCondition("Error closing file", e);
+                       }
+               }
+               return null;
+       }
+       
+       
+       
+       /**
+        * Exports a CSV file using a progress dialog if necessary.
+        *
+        * @return      <code>true</code> if the save was successful, <code>false</code> otherwise.
+        */
+       public static boolean export(File file, Simulation simulation, FlightDataBranch branch,
+                       FlightDataType[] fields, Unit[] units, String fieldSeparator, String commentStarter,
+                       boolean simulationComments, boolean fieldComments, boolean eventComments,
+                       Window parent) {
+               
+
+               SaveCSVWorker worker = new SaveCSVWorker(file, simulation, branch, fields, units,
+                               fieldSeparator, commentStarter, simulationComments, fieldComments, 
+                               eventComments);
+               
+           if (!SwingWorkerDialog.runWorker(parent, "Exporting flight data", 
+                       "Writing " + file.getName() + "...", worker)) {
+               
+               // User cancelled the save
+               file.delete();
+               return false;
+           }
+           
+           try {
+                       worker.get();
+               } catch (ExecutionException e) {
+                       Throwable cause = e.getCause();
+                       
+                       if (cause instanceof IOException) {
+                       JOptionPane.showMessageDialog(parent, new String[] { 
+                                       "An I/O error occurred while saving:",
+                                       e.getMessage() }, "Saving failed", JOptionPane.ERROR_MESSAGE);
+                       return false;
+                       } else {
+                               throw new BugException("Unknown error when saving file", e);
+                       }
+                       
+               } catch (InterruptedException e) {
+                       throw new BugException("EDT was interrupted", e);
+               }
+               
+               return true;
+       }
+}
diff --git a/src/net/sf/openrocket/gui/util/SaveFileWorker.java b/src/net/sf/openrocket/gui/util/SaveFileWorker.java
new file mode 100644 (file)
index 0000000..b9191c4
--- /dev/null
@@ -0,0 +1,57 @@
+package net.sf.openrocket.gui.util;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+
+import javax.swing.SwingWorker;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.file.RocketSaver;
+import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.util.ProgressOutputStream;
+
+public class SaveFileWorker extends SwingWorker<Void, Void> {
+
+       private final OpenRocketDocument document;
+       private final File file;
+       private final RocketSaver saver;
+       
+       public SaveFileWorker(OpenRocketDocument document, File file, RocketSaver saver) {
+               this.document = document;
+               this.file = file;
+               this.saver = saver;
+       }
+       
+       
+       @Override
+       protected Void doInBackground() throws Exception {
+               
+               int estimate = (int)saver.estimateFileSize(document, 
+                               document.getDefaultStorageOptions());
+               
+               // Create the ProgressOutputStream that provides progress estimates
+               ProgressOutputStream os = new ProgressOutputStream(
+                               new BufferedOutputStream(new FileOutputStream(file)), 
+                               estimate, this) {
+                       
+                       @Override
+                       protected void setProgress(int progress) {
+                               SaveFileWorker.this.setProgress(progress);
+                       }
+                       
+               };
+               
+               try {
+                       saver.save(os, document);
+               } finally {
+                       try {
+                               os.close();
+                       } catch (Exception e) {
+                               ExceptionHandler.handleErrorCondition("Error closing file", e);
+                       }
+               }
+               return null;
+       }
+       
+}
diff --git a/src/net/sf/openrocket/gui/util/SimpleFileFilter.java b/src/net/sf/openrocket/gui/util/SimpleFileFilter.java
new file mode 100644 (file)
index 0000000..39ded91
--- /dev/null
@@ -0,0 +1,77 @@
+package net.sf.openrocket.gui.util;
+
+import java.io.File;
+
+import javax.swing.filechooser.FileFilter;
+
+/**
+ * A FileFilter similar to FileNameExtensionFilter except that
+ * it allows multipart extensions (.ork.gz), and also implements
+ * the java.io.FileFilter interface.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class SimpleFileFilter extends FileFilter implements java.io.FileFilter {
+
+       private final String description;
+       private final boolean acceptDir;
+       private final String[] extensions;
+       
+       
+       /**
+        * Create filter that accepts files with the provided extensions that
+        * accepts directories as well.
+        * 
+        * @param description   the description of this file filter.
+        * @param extensions    an array of extensions that match this filter.
+        */
+       public SimpleFileFilter(String description, String ... extensions) {
+               this(description, true, extensions);
+       }
+       
+
+       /**
+        * Create filter that accepts files with the provided extensions.
+        * 
+        * @param description   the description of this file filter.
+        * @param acceptDir             whether to accept directories
+        * @param extensions    an array of extensions that match this filter.
+        */
+       public SimpleFileFilter(String description, boolean acceptDir, String ... extensions) {
+               this.description = description;
+               this.acceptDir = acceptDir;
+               this.extensions = new String[extensions.length];
+               for (int i=0; i<extensions.length; i++) {
+                       String ext = extensions[i].toLowerCase();
+                       if (ext.charAt(0) == '.') {
+                               this.extensions[i] = ext;
+                       } else {
+                               this.extensions[i] = '.' + ext;
+                       }
+               }
+       }
+       
+       
+       @Override
+       public boolean accept(File file) {
+               if (file == null)
+                       return false;
+               if (file.isDirectory())
+                       return acceptDir;
+               
+               String filename = file.getName();
+               filename = filename.toLowerCase();
+               for (String ext: extensions) {
+                       if (filename.endsWith(ext))
+                               return true;
+               }
+               
+               return false;
+       }
+
+       @Override
+       public String getDescription() {
+               return description;
+       }
+
+}
index 4371fc3e740ceade7f9808210c1e04d2539bb186..6a7aa6edaca46fa66cdc81c9d3564b0fd6a0c274 100644 (file)
@@ -23,12 +23,12 @@ import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
 import net.sf.openrocket.gui.main.BasicFrame;
 import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.gui.main.Splash;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.SimpleFileFilter;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.motor.ThrustCurveMotor;
-import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Prefs;
-import net.sf.openrocket.util.SimpleFileFilter;
 
 /**
  * The second class in the OpenRocket startup sequence.  This class can assume the
diff --git a/src/net/sf/openrocket/util/ConcurrentProgressMonitor.java b/src/net/sf/openrocket/util/ConcurrentProgressMonitor.java
deleted file mode 100644 (file)
index 7253c89..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-package net.sf.openrocket.util;
-
-import java.awt.Component;
-
-import javax.swing.ProgressMonitor;
-import javax.swing.SwingUtilities;
-
-
-/**
- * A thread-safe <code>ProgressMonitor</code>.  This class may be instantiated
- * and the method {@link #setProgress(int)} called safely from any thread.
- * <p>
- * Why the FSCK&!#&% isn't the default API version thread-safe?!?!
- * 
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-public class ConcurrentProgressMonitor extends ProgressMonitor {
-
-       public ConcurrentProgressMonitor(Component parentComponent, Object message,
-                       String note, int min, int max) {
-               super(parentComponent, message, note, min, max);
-       }
-
-       @Override
-       public void setProgress(final int nv) {
-               
-               if (SwingUtilities.isEventDispatchThread()) {
-                       super.setProgress(nv);
-               } else {
-                       
-                       SwingUtilities.invokeLater(new Runnable() {
-
-                               @Override
-                               public void run() {
-                                       ConcurrentProgressMonitor.super.setProgress(nv);
-                               }
-                               
-                       });
-               }
-       }
-       
-       
-       @Override
-       public void close() {
-               if (SwingUtilities.isEventDispatchThread()) {
-                       super.close();
-               } else {
-                       
-                       SwingUtilities.invokeLater(new Runnable() {
-
-                               @Override
-                               public void run() {
-                                       ConcurrentProgressMonitor.super.close();
-                               }
-                               
-                       });
-               }
-       }
-
-
-}
diff --git a/src/net/sf/openrocket/util/ConcurrentProgressMonitorInputStream.java b/src/net/sf/openrocket/util/ConcurrentProgressMonitorInputStream.java
deleted file mode 100644 (file)
index 6c45a6c..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-package net.sf.openrocket.util;
-
-import java.awt.Component;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InterruptedIOException;
-
-
-/**
- * A functional equivalent of <code>ProgressMonitorInputStream</code> which 
- * uses {@link ConcurrentProgressMonitor} and leaves the progress dialog open
- * to be manually closed later on.
- */
-
-public class ConcurrentProgressMonitorInputStream extends FilterInputStream {
-       private ConcurrentProgressMonitor monitor;
-       private int nread = 0;
-       private int size = 0;
-
-
-       /**
-        * Constructs an object to monitor the progress of an input stream.
-        *
-        * @param message Descriptive text to be placed in the dialog box
-        *                if one is popped up.
-        * @param parentComponent The component triggering the operation
-        *                        being monitored.
-        * @param in The input stream to be monitored.
-        */
-       public ConcurrentProgressMonitorInputStream(Component parentComponent,
-                       Object message, InputStream in) {
-               super(in);
-               try {
-                       size = in.available();
-               } catch (IOException ioe) {
-                       size = 0;
-               }
-               monitor = new ConcurrentProgressMonitor(parentComponent, message, null, 0,
-                               size + 1);
-       }
-
-
-       /**
-        * Get the ProgressMonitor object being used by this stream. Normally
-        * this isn't needed unless you want to do something like change the
-        * descriptive text partway through reading the file.
-        * @return the ProgressMonitor object used by this object 
-        */
-       public ConcurrentProgressMonitor getProgressMonitor() {
-               return monitor;
-       }
-
-
-       /**
-        * Overrides <code>FilterInputStream.read</code> 
-        * to update the progress monitor after the read.
-        */
-       @Override
-       public int read() throws IOException {
-               int c = in.read();
-               if (c >= 0)
-                       monitor.setProgress(++nread);
-               if (monitor.isCanceled()) {
-                       InterruptedIOException exc = new InterruptedIOException("progress");
-                       exc.bytesTransferred = nread;
-                       throw exc;
-               }
-               return c;
-       }
-
-
-       /**
-        * Overrides <code>FilterInputStream.read</code> 
-        * to update the progress monitor after the read.
-        */
-       @Override
-       public int read(byte b[]) throws IOException {
-               int nr = in.read(b);
-               if (nr > 0)
-                       monitor.setProgress(nread += nr);
-               if (monitor.isCanceled()) {
-                       InterruptedIOException exc = new InterruptedIOException("progress");
-                       exc.bytesTransferred = nread;
-                       throw exc;
-               }
-               return nr;
-       }
-
-
-       /**
-        * Overrides <code>FilterInputStream.read</code> 
-        * to update the progress monitor after the read.
-        */
-       @Override
-       public int read(byte b[], int off, int len) throws IOException {
-               int nr = in.read(b, off, len);
-               if (nr > 0)
-                       monitor.setProgress(nread += nr);
-               if (monitor.isCanceled()) {
-                       InterruptedIOException exc = new InterruptedIOException("progress");
-                       exc.bytesTransferred = nread;
-                       throw exc;
-               }
-               return nr;
-       }
-
-
-       /**
-        * Overrides <code>FilterInputStream.skip</code> 
-        * to update the progress monitor after the skip.
-        */
-       @Override
-       public long skip(long n) throws IOException {
-               long nr = in.skip(n);
-               if (nr > 0)
-                       monitor.setProgress(nread += nr);
-               return nr;
-       }
-
-
-       /**
-        * Overrides <code>FilterInputStream.close</code> 
-        * to close the progress monitor as well as the stream.
-        */
-       @Override
-       public void close() throws IOException {
-               in.close();
-        monitor.close();
-       }
-
-
-       /**
-        * Overrides <code>FilterInputStream.reset</code> 
-        * to reset the progress monitor as well as the stream.
-        */
-       @Override
-       public synchronized void reset() throws IOException {
-               in.reset();
-               nread = size - in.available();
-               monitor.setProgress(nread);
-       }
-}
diff --git a/src/net/sf/openrocket/util/FileHelper.java b/src/net/sf/openrocket/util/FileHelper.java
deleted file mode 100644 (file)
index 0929c32..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-package net.sf.openrocket.util;
-
-import java.awt.Component;
-import java.io.File;
-import java.io.IOException;
-
-import javax.swing.JOptionPane;
-import javax.swing.filechooser.FileFilter;
-
-import net.sf.openrocket.l10n.L10N;
-import net.sf.openrocket.l10n.Translator;
-import net.sf.openrocket.logging.LogHelper;
-import net.sf.openrocket.startup.Application;
-
-/**
- * Helper methods related to user-initiated file manipulation.
- * <p>
- * These methods log the necessary information to the debug log.
-* 
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-public final class FileHelper {
-       private static final LogHelper log = Application.getLogger();
-       private static final Translator trans = Application.getTranslator();
-       
-
-       // TODO: HIGH: Rename translation keys
-       
-       /** File filter for any rocket designs (*.ork, *.rkt) */
-       public static final FileFilter ALL_DESIGNS_FILTER =
-                       new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter1"),
-                                       ".ork", ".ork.gz", ".rkt", ".rkt.gz");
-       
-       /** File filter for OpenRocket designs (*.ork) */
-       public static final FileFilter OPENROCKET_DESIGN_FILTER =
-                       new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter2"), ".ork", ".ork.gz");
-       
-       /** File filter for RockSim designs (*.rkt) */
-       public static final FileFilter ROCKSIM_DESIGN_FILTER =
-                       new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter3"), ".rkt", ".rkt.gz");
-       
-       /** File filter for PDF files (*.pdf) */
-       public static final FileFilter PDF_FILTER =
-                       new SimpleFileFilter(trans.get("filetypes.pdf"), ".pdf");
-       
-       /** File filter for CSV files (*.csv) */
-       public static final FileFilter CSV_FILE_FILTER =
-                       new SimpleFileFilter(trans.get("SimExpPan.desc"), ".csv");
-       
-       
-
-
-
-       private FileHelper() {
-               // Prevent instantiation
-       }
-       
-       /**
-        * Ensure that the provided file has a file extension.  If the file does not have
-        * any extension, append the provided extension to it.
-        * 
-        * @param original              the original file
-        * @param extension             the extension to append if none exists (without preceding dot)
-        * @return                              the resulting filen
-        */
-       public static File ensureExtension(File original, String extension) {
-               
-               if (original.getName().indexOf('.') < 0) {
-                       log.debug(1, "File name does not contain extension, adding '" + extension + "'");
-                       String name = original.getAbsolutePath();
-                       name = name + "." + extension;
-                       return new File(name);
-               }
-               
-               return original;
-       }
-       
-       
-       /**
-        * Confirm that it is allowed to write to a file.  If the file exists,
-        * a confirmation dialog will be presented to the user to ensure overwriting is ok.
-        * 
-        * @param file          the file that is going to be written.
-        * @param parent        the parent component for the dialog.
-        * @return                      <code>true</code> to write, <code>false</code> to abort.
-        */
-       public static boolean confirmWrite(File file, Component parent) {
-               if (file.exists()) {
-                       log.info(1, "File " + file + " exists, confirming overwrite from user");
-                       int result = JOptionPane.showConfirmDialog(parent,
-                                       L10N.replace(trans.get("error.fileExists.desc"), "{filename}", file.getName()),
-                                       trans.get("error.fileExists.title"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
-                       if (result != JOptionPane.YES_OPTION) {
-                               log.user(1, "User decided not to overwrite the file");
-                               return false;
-                       }
-                       log.user(1, "User decided to overwrite the file");
-               }
-               return true;
-       }
-       
-       
-       /**
-        * Display an error message to the user that writing a file failed.
-        * 
-        * @param e                     the I/O exception that caused the error.
-        * @param parent        the parent component for the dialog.
-        */
-       public static void errorWriting(IOException e, Component parent) {
-               
-               log.warn(1, "Error writing to file", e);
-               JOptionPane.showMessageDialog(parent,
-                               new Object[] {
-                                               trans.get("error.writing.desc"),
-                                               e.getLocalizedMessage()
-                               }, trans.get("error.writing.title"), JOptionPane.ERROR_MESSAGE);
-               
-       }
-       
-}
diff --git a/src/net/sf/openrocket/util/GUIUtil.java b/src/net/sf/openrocket/util/GUIUtil.java
deleted file mode 100644 (file)
index e74dbc1..0000000
+++ /dev/null
@@ -1,565 +0,0 @@
-package net.sf.openrocket.util;
-
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.Image;
-import java.awt.KeyboardFocusManager;
-import java.awt.Point;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ComponentAdapter;
-import java.awt.event.ComponentEvent;
-import java.awt.event.ComponentListener;
-import java.awt.event.FocusListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.beans.PropertyChangeListener;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.imageio.ImageIO;
-import javax.swing.AbstractAction;
-import javax.swing.AbstractButton;
-import javax.swing.Action;
-import javax.swing.BoundedRangeModel;
-import javax.swing.ComboBoxModel;
-import javax.swing.DefaultBoundedRangeModel;
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.DefaultListSelectionModel;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JComponent;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JRootPane;
-import javax.swing.JSlider;
-import javax.swing.JSpinner;
-import javax.swing.JTable;
-import javax.swing.JTree;
-import javax.swing.KeyStroke;
-import javax.swing.ListSelectionModel;
-import javax.swing.LookAndFeel;
-import javax.swing.RootPaneContainer;
-import javax.swing.SpinnerModel;
-import javax.swing.SpinnerNumberModel;
-import javax.swing.SwingUtilities;
-import javax.swing.UIManager;
-import javax.swing.border.TitledBorder;
-import javax.swing.event.ChangeListener;
-import javax.swing.table.AbstractTableModel;
-import javax.swing.table.DefaultTableColumnModel;
-import javax.swing.table.DefaultTableModel;
-import javax.swing.table.TableColumnModel;
-import javax.swing.table.TableModel;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.DefaultTreeSelectionModel;
-import javax.swing.tree.TreeModel;
-import javax.swing.tree.TreeSelectionModel;
-
-import net.sf.openrocket.gui.Resettable;
-import net.sf.openrocket.logging.LogHelper;
-import net.sf.openrocket.startup.Application;
-
-public class GUIUtil {
-       private static final LogHelper log = Application.getLogger();
-       
-       private static final KeyStroke ESCAPE = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
-       private static final String CLOSE_ACTION_KEY = "escape:WINDOW_CLOSING";
-       
-       private static final List<Image> images = new ArrayList<Image>();
-       static {
-               loadImage("pix/icon/icon-256.png");
-               loadImage("pix/icon/icon-064.png");
-               loadImage("pix/icon/icon-048.png");
-               loadImage("pix/icon/icon-032.png");
-               loadImage("pix/icon/icon-016.png");
-       }
-       
-       private static void loadImage(String file) {
-               InputStream is;
-               
-               is = ClassLoader.getSystemResourceAsStream(file);
-               if (is == null)
-                       return;
-               
-               try {
-                       Image image = ImageIO.read(is);
-                       images.add(image);
-               } catch (IOException ignore) {
-                       ignore.printStackTrace();
-               }
-       }
-       
-       
-
-       /**
-        * Set suitable options for a single-use disposable dialog.  This includes
-        * setting ESC to close the dialog, adding the appropriate window icons and
-        * setting the location based on the platform.  If defaultButton is provided, 
-        * it is set to the default button action.
-        * <p>
-        * The default button must be already attached to the dialog.
-        * 
-        * @param dialog                the dialog.
-        * @param defaultButton the default button of the dialog, or <code>null</code>.
-        */
-       public static void setDisposableDialogOptions(JDialog dialog, JButton defaultButton) {
-               installEscapeCloseOperation(dialog);
-               setWindowIcons(dialog);
-               addModelNullingListener(dialog);
-               dialog.setLocationByPlatform(true);
-               dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
-               dialog.pack();
-               if (defaultButton != null) {
-                       setDefaultButton(defaultButton);
-               }
-       }
-       
-       
-
-       /**
-        * Add the correct action to close a JDialog when the ESC key is pressed.
-        * The dialog is closed by sending is a WINDOW_CLOSING event.
-        * 
-        * @param dialog        the dialog for which to install the action.
-        */
-       public static void installEscapeCloseOperation(final JDialog dialog) {
-               Action dispatchClosing = new AbstractAction() {
-                       @Override
-                       public void actionPerformed(ActionEvent event) {
-                               log.user("Closing dialog " + dialog);
-                               dialog.dispatchEvent(new WindowEvent(dialog, WindowEvent.WINDOW_CLOSING));
-                       }
-               };
-               JRootPane root = dialog.getRootPane();
-               root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ESCAPE, CLOSE_ACTION_KEY);
-               root.getActionMap().put(CLOSE_ACTION_KEY, dispatchClosing);
-       }
-       
-       
-       /**
-        * Set the given button as the default button of the frame/dialog it is in.  The button
-        * must be first attached to the window component hierarchy.
-        * 
-        * @param button        the button to set as the default button.
-        */
-       public static void setDefaultButton(JButton button) {
-               Window w = SwingUtilities.windowForComponent(button);
-               if (w == null) {
-                       throw new IllegalArgumentException("Attach button to a window first.");
-               }
-               if (!(w instanceof RootPaneContainer)) {
-                       throw new IllegalArgumentException("Button not attached to RootPaneContainer, w=" + w);
-               }
-               ((RootPaneContainer) w).getRootPane().setDefaultButton(button);
-       }
-       
-       
-
-       /**
-        * Change the behavior of a component so that TAB and Shift-TAB cycles the focus of
-        * the components.  This is necessary for e.g. <code>JTextArea</code>.
-        * 
-        * @param c             the component to modify
-        */
-       public static void setTabToFocusing(Component c) {
-               Set<KeyStroke> strokes = new HashSet<KeyStroke>(Arrays.asList(KeyStroke.getKeyStroke("pressed TAB")));
-               c.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, strokes);
-               strokes = new HashSet<KeyStroke>(Arrays.asList(KeyStroke.getKeyStroke("shift pressed TAB")));
-               c.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, strokes);
-       }
-       
-       
-
-       /**
-        * Set the OpenRocket icons to the window icons.
-        * 
-        * @param window        the window to set.
-        */
-       public static void setWindowIcons(Window window) {
-               window.setIconImages(images);
-       }
-       
-       /**
-        * Add a listener to the provided window that will call {@link #setNullModels(Component)}
-        * on the window once it is closed.  This method may only be used on single-use
-        * windows and dialogs, that will never be shown again once closed!
-        * 
-        * @param window        the window to add the listener to.
-        */
-       public static void addModelNullingListener(final Window window) {
-               window.addWindowListener(new WindowAdapter() {
-                       @Override
-                       public void windowClosed(WindowEvent e) {
-                               log.debug("Clearing all models of window " + window);
-                               setNullModels(window);
-                               MemoryManagement.collectable(window);
-                       }
-               });
-       }
-       
-       
-
-       /**
-        * Set the best available look-and-feel into use.
-        */
-       public static void setBestLAF() {
-               /*
-                * Set the look-and-feel.  On Linux, Motif/Metal is sometimes incorrectly used 
-                * which is butt-ugly, so if the system l&f is Motif/Metal, we search for a few
-                * other alternatives.
-                */
-               try {
-                       // Set system L&F
-                       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
-                       
-                       // Check whether we have an ugly L&F
-                       LookAndFeel laf = UIManager.getLookAndFeel();
-                       if (laf == null ||
-                                       laf.getName().matches(".*[mM][oO][tT][iI][fF].*") ||
-                                       laf.getName().matches(".*[mM][eE][tT][aA][lL].*")) {
-                               
-                               // Search for better LAF
-                               UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
-                               String lafNames[] = {
-                                               ".*[gG][tT][kK].*",
-                                               ".*[wW][iI][nN].*",
-                                               ".*[mM][aA][cC].*",
-                                               ".*[aA][qQ][uU][aA].*",
-                                               ".*[nN][iI][mM][bB].*"
-                               };
-                               
-                               lf: for (String lafName : lafNames) {
-                                       for (UIManager.LookAndFeelInfo l : info) {
-                                               if (l.getName().matches(lafName)) {
-                                                       UIManager.setLookAndFeel(l.getClassName());
-                                                       break lf;
-                                               }
-                                       }
-                               }
-                       }
-               } catch (Exception e) {
-                       log.warn("Error setting LAF: " + e);
-               }
-       }
-       
-       
-       /**
-        * Changes the size of the font of the specified component by the given amount.
-        * 
-        * @param component             the component for which to change the font
-        * @param size                  the change in the font size
-        */
-       public static void changeFontSize(JComponent component, float size) {
-               Font font = component.getFont();
-               font = font.deriveFont(font.getSize2D() + size);
-               component.setFont(font);
-       }
-       
-       
-
-       /**
-        * Automatically remember the size of a window.  This stores the window size in the user
-        * preferences when resizing/maximizing the window and sets the state on the first call.
-        */
-       public static void rememberWindowSize(final Window window) {
-               window.addComponentListener(new ComponentAdapter() {
-                       @Override
-                       public void componentResized(ComponentEvent e) {
-                               log.debug("Storing size of " + window.getClass().getName() + ": " + window.getSize());
-                               Prefs.setWindowSize(window.getClass(), window.getSize());
-                               if (window instanceof JFrame) {
-                                       if ((((JFrame) window).getExtendedState() & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH) {
-                                               log.debug("Storing maximized state of " + window.getClass().getName());
-                                               Prefs.setWindowMaximized(window.getClass());
-                                       }
-                               }
-                       }
-               });
-               
-               if (Prefs.isWindowMaximized(window.getClass())) {
-                       if (window instanceof JFrame) {
-                               ((JFrame) window).setExtendedState(JFrame.MAXIMIZED_BOTH);
-                       }
-               } else {
-                       Dimension dim = Prefs.getWindowSize(window.getClass());
-                       if (dim != null) {
-                               window.setSize(dim);
-                       }
-               }
-       }
-       
-       
-       /**
-        * Automatically remember the position of a window.  The position is stored in the user preferences
-        * every time the window is moved and set from there when first calling this method.
-        */
-       public static void rememberWindowPosition(final Window window) {
-               window.addComponentListener(new ComponentAdapter() {
-                       @Override
-                       public void componentMoved(ComponentEvent e) {
-                               Prefs.setWindowPosition(window.getClass(), window.getLocation());
-                       }
-               });
-               
-               // Set window position according to preferences, and set prefs when moving
-               Point position = Prefs.getWindowPosition(window.getClass());
-               if (position != null) {
-                       window.setLocationByPlatform(false);
-                       window.setLocation(position);
-               }
-       }
-       
-       
-       /**
-        * Changes the style of the font of the specified border.
-        * 
-        * @param border                the component for which to change the font
-        * @param style                 the change in the font style
-        */
-       public static void changeFontStyle(TitledBorder border, int style) {
-               /*
-                * The fix of JRE bug #4129681 causes a TitledBorder occasionally to
-                * return a null font.  We try to work around the issue by detecting it
-                * and reverting to the font of a JLabel instead.
-                */
-               Font font = border.getTitleFont();
-               if (font == null) {
-                       log.error("Border font is null, reverting to JLabel font");
-                       font = new JLabel().getFont();
-                       if (font == null) {
-                               log.error("JLabel font is null, not modifying font");
-                               return;
-                       }
-               }
-               font = font.deriveFont(style);
-               if (font == null) {
-                       throw new BugException("Derived font is null");
-               }
-               border.setTitleFont(font);
-       }
-       
-       
-
-       /**
-        * Traverses recursively the component tree, and sets all applicable component 
-        * models to null, so as to remove the listener connections.  After calling this
-        * method the component hierarchy should no longed be used.
-        * <p>
-        * All components that use custom models should be added to this method, as
-        * there exists no standard way of removing the model from a component.
-        * 
-        * @param c             the component (<code>null</code> is ok)
-        */
-       public static void setNullModels(Component c) {
-               if (c == null)
-                       return;
-               
-               // Remove various listeners
-               for (ComponentListener l : c.getComponentListeners()) {
-                       c.removeComponentListener(l);
-               }
-               for (FocusListener l : c.getFocusListeners()) {
-                       c.removeFocusListener(l);
-               }
-               for (MouseListener l : c.getMouseListeners()) {
-                       c.removeMouseListener(l);
-               }
-               for (PropertyChangeListener l : c.getPropertyChangeListeners()) {
-                       c.removePropertyChangeListener(l);
-               }
-               for (PropertyChangeListener l : c.getPropertyChangeListeners("model")) {
-                       c.removePropertyChangeListener("model", l);
-               }
-               for (PropertyChangeListener l : c.getPropertyChangeListeners("action")) {
-                       c.removePropertyChangeListener("action", l);
-               }
-               
-               // Remove models for known components
-               //  Why the FSCK must this be so hard?!?!?
-               
-               if (c instanceof JSpinner) {
-                       
-                       JSpinner spinner = (JSpinner) c;
-                       for (ChangeListener l : spinner.getChangeListeners()) {
-                               spinner.removeChangeListener(l);
-                       }
-                       SpinnerModel model = spinner.getModel();
-                       spinner.setModel(new SpinnerNumberModel());
-                       if (model instanceof Invalidatable) {
-                               ((Invalidatable) model).invalidate();
-                       }
-                       
-               } else if (c instanceof JSlider) {
-                       
-                       JSlider slider = (JSlider) c;
-                       for (ChangeListener l : slider.getChangeListeners()) {
-                               slider.removeChangeListener(l);
-                       }
-                       BoundedRangeModel model = slider.getModel();
-                       slider.setModel(new DefaultBoundedRangeModel());
-                       if (model instanceof Invalidatable) {
-                               ((Invalidatable) model).invalidate();
-                       }
-                       
-               } else if (c instanceof JComboBox) {
-                       
-                       JComboBox combo = (JComboBox) c;
-                       for (ActionListener l : combo.getActionListeners()) {
-                               combo.removeActionListener(l);
-                       }
-                       ComboBoxModel model = combo.getModel();
-                       combo.setModel(new DefaultComboBoxModel());
-                       if (model instanceof Invalidatable) {
-                               ((Invalidatable) model).invalidate();
-                       }
-                       
-               } else if (c instanceof AbstractButton) {
-                       
-                       AbstractButton button = (AbstractButton) c;
-                       for (ActionListener l : button.getActionListeners()) {
-                               button.removeActionListener(l);
-                       }
-                       Action model = button.getAction();
-                       button.setAction(new AbstractAction() {
-                               @Override
-                               public void actionPerformed(ActionEvent e) {
-                               }
-                       });
-                       if (model instanceof Invalidatable) {
-                               ((Invalidatable) model).invalidate();
-                       }
-                       
-               } else if (c instanceof JTable) {
-                       
-                       JTable table = (JTable) c;
-                       TableModel model1 = table.getModel();
-                       table.setModel(new DefaultTableModel());
-                       if (model1 instanceof Invalidatable) {
-                               ((Invalidatable) model1).invalidate();
-                       }
-                       
-                       TableColumnModel model2 = table.getColumnModel();
-                       table.setColumnModel(new DefaultTableColumnModel());
-                       if (model2 instanceof Invalidatable) {
-                               ((Invalidatable) model2).invalidate();
-                       }
-                       
-                       ListSelectionModel model3 = table.getSelectionModel();
-                       table.setSelectionModel(new DefaultListSelectionModel());
-                       if (model3 instanceof Invalidatable) {
-                               ((Invalidatable) model3).invalidate();
-                       }
-                       
-               } else if (c instanceof JTree) {
-                       
-                       JTree tree = (JTree) c;
-                       TreeModel model1 = tree.getModel();
-                       tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
-                       if (model1 instanceof Invalidatable) {
-                               ((Invalidatable) model1).invalidate();
-                       }
-                       
-                       TreeSelectionModel model2 = tree.getSelectionModel();
-                       tree.setSelectionModel(new DefaultTreeSelectionModel());
-                       if (model2 instanceof Invalidatable) {
-                               ((Invalidatable) model2).invalidate();
-                       }
-                       
-               } else if (c instanceof Resettable) {
-                       
-                       ((Resettable) c).resetModel();
-                       
-               }
-               
-               // Recurse the component
-               if (c instanceof Container) {
-                       Component[] cs = ((Container) c).getComponents();
-                       for (Component sub : cs)
-                               setNullModels(sub);
-               }
-               
-       }
-       
-       
-
-       /**
-        * A mouse listener that toggles the state of a boolean value in a table model
-        * when clicked on another column of the table.
-        * <p>
-        * NOTE:  If the table model does not extend AbstractTableModel, the model must
-        * fire a change event (which in normal table usage is not necessary).
-        * 
-        * @author Sampo Niskanen <sampo.niskanen@iki.fi>
-        */
-       public static class BooleanTableClickListener extends MouseAdapter {
-               
-               private final JTable table;
-               private final int clickColumn;
-               private final int booleanColumn;
-               
-               
-               public BooleanTableClickListener(JTable table) {
-                       this(table, 1, 0);
-               }
-               
-               
-               public BooleanTableClickListener(JTable table, int clickColumn, int booleanColumn) {
-                       this.table = table;
-                       this.clickColumn = clickColumn;
-                       this.booleanColumn = booleanColumn;
-               }
-               
-               @Override
-               public void mouseClicked(MouseEvent e) {
-                       if (e.getButton() != MouseEvent.BUTTON1)
-                               return;
-                       
-                       Point p = e.getPoint();
-                       int col = table.columnAtPoint(p);
-                       if (col < 0)
-                               return;
-                       col = table.convertColumnIndexToModel(col);
-                       if (col != clickColumn)
-                               return;
-                       
-                       int row = table.rowAtPoint(p);
-                       if (row < 0)
-                               return;
-                       row = table.convertRowIndexToModel(row);
-                       if (row < 0)
-                               return;
-                       
-                       TableModel model = table.getModel();
-                       Object value = model.getValueAt(row, booleanColumn);
-                       
-                       if (!(value instanceof Boolean)) {
-                               throw new IllegalStateException("Table value at row=" + row + " col=" +
-                                               booleanColumn + " is not a Boolean, value=" + value);
-                       }
-                       
-                       Boolean b = (Boolean) value;
-                       b = !b;
-                       model.setValueAt(b, row, booleanColumn);
-                       if (model instanceof AbstractTableModel) {
-                               ((AbstractTableModel) model).fireTableCellUpdated(row, booleanColumn);
-                       }
-               }
-               
-       }
-       
-}
diff --git a/src/net/sf/openrocket/util/Icons.java b/src/net/sf/openrocket/util/Icons.java
deleted file mode 100644 (file)
index e5f4131..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-package net.sf.openrocket.util;
-
-import java.net.URL;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-
-import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.gui.main.ExceptionHandler;
-import net.sf.openrocket.l10n.Translator;
-import net.sf.openrocket.logging.LogHelper;
-import net.sf.openrocket.startup.Application;
-
-
-public class Icons {
-       private static final LogHelper log = Application.getLogger();
-       private static final Translator trans = Application.getTranslator();
-       
-       static {
-               log.debug("Starting to load icons");
-       }
-       
-       /**
-        * Icons used for showing the status of a simulation (up to date, out of date, etc).
-        */
-       public static final Map<Simulation.Status, Icon> SIMULATION_STATUS_ICON_MAP;
-       static {
-               HashMap<Simulation.Status, Icon> map = new HashMap<Simulation.Status, Icon>();
-               map.put(Simulation.Status.NOT_SIMULATED, loadImageIcon("pix/spheres/gray-16x16.png", "Not simulated"));
-               map.put(Simulation.Status.UPTODATE, loadImageIcon("pix/spheres/green-16x16.png", "Up to date"));
-               map.put(Simulation.Status.LOADED, loadImageIcon("pix/spheres/yellow-16x16.png", "Loaded from file"));
-               map.put(Simulation.Status.OUTDATED, loadImageIcon("pix/spheres/red-16x16.png", "Out-of-date"));
-               map.put(Simulation.Status.EXTERNAL, loadImageIcon("pix/spheres/blue-16x16.png", "Imported data"));
-               SIMULATION_STATUS_ICON_MAP = Collections.unmodifiableMap(map);
-       }
-       
-       public static final Icon SIMULATION_LISTENER_OK;
-       public static final Icon SIMULATION_LISTENER_ERROR;
-       static {
-               SIMULATION_LISTENER_OK = SIMULATION_STATUS_ICON_MAP.get(Simulation.Status.UPTODATE);
-               SIMULATION_LISTENER_ERROR = SIMULATION_STATUS_ICON_MAP.get(Simulation.Status.OUTDATED);
-       }
-       
-
-       public static final Icon FILE_NEW = loadImageIcon("pix/icons/document-new.png", "New document");
-       public static final Icon FILE_OPEN = loadImageIcon("pix/icons/document-open.png", "Open document");
-       public static final Icon FILE_OPEN_EXAMPLE = loadImageIcon("pix/icons/document-open-example.png", "Open example document");
-       public static final Icon FILE_SAVE = loadImageIcon("pix/icons/document-save.png", "Save document");
-       public static final Icon FILE_SAVE_AS = loadImageIcon("pix/icons/document-save-as.png", "Save document as");
-       public static final Icon FILE_PRINT = loadImageIcon("pix/icons/document-print.png", "Print document");
-       public static final Icon FILE_CLOSE = loadImageIcon("pix/icons/document-close.png", "Close document");
-       public static final Icon FILE_QUIT = loadImageIcon("pix/icons/application-exit.png", "Quit OpenRocket");
-       
-       public static final Icon EDIT_UNDO = loadImageIcon("pix/icons/edit-undo.png", trans.get("Icons.Undo"));
-       public static final Icon EDIT_REDO = loadImageIcon("pix/icons/edit-redo.png", trans.get("Icons.Redo"));
-       public static final Icon EDIT_CUT = loadImageIcon("pix/icons/edit-cut.png", "Cut");
-       public static final Icon EDIT_COPY = loadImageIcon("pix/icons/edit-copy.png", "Copy");
-       public static final Icon EDIT_PASTE = loadImageIcon("pix/icons/edit-paste.png", "Paste");
-       public static final Icon EDIT_DELETE = loadImageIcon("pix/icons/edit-delete.png", "Delete");
-       public static final Icon EDIT_SCALE = loadImageIcon("pix/icons/edit-scale.png", "Scale");
-       
-       public static final Icon HELP_ABOUT = loadImageIcon("pix/icons/help-about.png", "About");
-       public static final Icon HELP_BUG_REPORT = loadImageIcon("pix/icons/help-bug.png", "Bug report");
-       public static final Icon HELP_DEBUG_LOG = loadImageIcon("pix/icons/help-log.png", "Debug log");
-       public static final Icon HELP_LICENSE = loadImageIcon("pix/icons/help-license.png", "License");
-       
-       public static final Icon ZOOM_IN = loadImageIcon("pix/icons/zoom-in.png", "Zoom in");
-       public static final Icon ZOOM_OUT = loadImageIcon("pix/icons/zoom-out.png", "Zoom out");
-       
-       public static final Icon PREFERENCES = loadImageIcon("pix/icons/preferences.png", "Preferences");
-       
-       public static final Icon DELETE = loadImageIcon("pix/icons/delete.png", "Delete");
-       
-       static {
-               log.debug("Icons loaded");
-       }
-       
-       /**
-        * Load an ImageIcon from the specified file.  The file is obtained as a system
-        * resource from the normal classpath.  If the file cannot be loaded a bug dialog
-        * is opened and <code>null</code> is returned.
-        * 
-        * @param file  the file to load.
-        * @param name  the description of the icon.
-        * @return              the ImageIcon, or null if could not be loaded (after the user closes the dialog)
-        */
-       public static ImageIcon loadImageIcon(String file, String name) {
-               if (System.getProperty("openrocket.unittest") != null) {
-                       return new ImageIcon();
-               }
-               
-               URL url = ClassLoader.getSystemResource(file);
-               if (url == null) {
-                       ExceptionHandler.handleErrorCondition("Image file " + file + " not found, ignoring.");
-                       return null;
-               }
-               return new ImageIcon(url, name);
-       }
-}
diff --git a/src/net/sf/openrocket/util/OpenFileWorker.java b/src/net/sf/openrocket/util/OpenFileWorker.java
deleted file mode 100644 (file)
index a1d3106..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-package net.sf.openrocket.util;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InterruptedIOException;
-
-import javax.swing.SwingWorker;
-
-import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.file.RocketLoader;
-import net.sf.openrocket.gui.main.ExceptionHandler;
-import net.sf.openrocket.logging.LogHelper;
-import net.sf.openrocket.startup.Application;
-
-
-/**
- * A SwingWorker thread that opens a rocket design file.
- * 
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-public class OpenFileWorker extends SwingWorker<OpenRocketDocument, Void> {
-       private static final LogHelper log = Application.getLogger();
-       
-       private final File file;
-       private final InputStream stream;
-       private final RocketLoader loader;
-       
-       public OpenFileWorker(File file, RocketLoader loader) {
-               this.file = file;
-               this.stream = null;
-               this.loader = loader;
-       }
-       
-       
-       public OpenFileWorker(InputStream stream, RocketLoader loader) {
-               this.stream = stream;
-               this.file = null;
-               this.loader = loader;
-       }
-       
-       public RocketLoader getRocketLoader() {
-               return loader;
-       }
-       
-       @Override
-       protected OpenRocketDocument doInBackground() throws Exception {
-               InputStream is;
-               
-               // Get the correct input stream
-               if (file != null) {
-                       is = new FileInputStream(file);
-               } else {
-                       is = stream;
-               }
-               
-               // Buffer stream unless already buffered
-               if (!(is instanceof BufferedInputStream)) {
-                       is = new BufferedInputStream(is);
-               }
-               
-               // Encapsulate in a ProgressInputStream
-               is = new ProgressInputStream(is);
-               
-               try {
-                       return loader.load(is);
-               } finally {
-                       try {
-                               is.close();
-                       } catch (Exception e) {
-                               ExceptionHandler.handleErrorCondition("Error closing file", e);
-                       }
-               }
-       }
-       
-       
-
-
-       private class ProgressInputStream extends FilterInputStream {
-               
-               private final int size;
-               private int readBytes = 0;
-               private int progress = -1;
-               
-               protected ProgressInputStream(InputStream in) {
-                       super(in);
-                       int s;
-                       try {
-                               s = in.available();
-                       } catch (IOException e) {
-                               log.info("Exception while estimating available bytes!", e);
-                               s = 0;
-                       }
-                       size = Math.max(s, 1);
-               }
-               
-               
-
-               @Override
-               public int read() throws IOException {
-                       int c = in.read();
-                       if (c >= 0) {
-                               readBytes++;
-                               setProgress();
-                       }
-                       if (isCancelled()) {
-                               throw new InterruptedIOException("OpenFileWorker was cancelled");
-                       }
-                       return c;
-               }
-               
-               @Override
-               public int read(byte[] b, int off, int len) throws IOException {
-                       int n = in.read(b, off, len);
-                       if (n > 0) {
-                               readBytes += n;
-                               setProgress();
-                       }
-                       if (isCancelled()) {
-                               throw new InterruptedIOException("OpenFileWorker was cancelled");
-                       }
-                       return n;
-               }
-               
-               @Override
-               public int read(byte[] b) throws IOException {
-                       int n = in.read(b);
-                       if (n > 0) {
-                               readBytes += n;
-                               setProgress();
-                       }
-                       if (isCancelled()) {
-                               throw new InterruptedIOException("OpenFileWorker was cancelled");
-                       }
-                       return n;
-               }
-               
-               @Override
-               public long skip(long n) throws IOException {
-                       long nr = in.skip(n);
-                       if (nr > 0) {
-                               readBytes += nr;
-                               setProgress();
-                       }
-                       if (isCancelled()) {
-                               throw new InterruptedIOException("OpenFileWorker was cancelled");
-                       }
-                       return nr;
-               }
-               
-               @Override
-               public synchronized void reset() throws IOException {
-                       in.reset();
-                       readBytes = size - in.available();
-                       setProgress();
-                       if (isCancelled()) {
-                               throw new InterruptedIOException("OpenFileWorker was cancelled");
-                       }
-               }
-               
-               
-
-               private void setProgress() {
-                       int p = MathUtil.clamp(readBytes * 100 / size, 0, 100);
-                       if (progress != p) {
-                               progress = p;
-                               OpenFileWorker.this.setProgress(progress);
-                       }
-               }
-       }
-}
diff --git a/src/net/sf/openrocket/util/SaveCSVWorker.java b/src/net/sf/openrocket/util/SaveCSVWorker.java
deleted file mode 100644 (file)
index c948818..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-package net.sf.openrocket.util;
-
-import java.awt.Window;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.concurrent.ExecutionException;
-
-import javax.swing.JOptionPane;
-import javax.swing.SwingWorker;
-
-import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.file.CSVExport;
-import net.sf.openrocket.gui.dialogs.SwingWorkerDialog;
-import net.sf.openrocket.gui.main.ExceptionHandler;
-import net.sf.openrocket.simulation.FlightDataBranch;
-import net.sf.openrocket.simulation.FlightDataType;
-import net.sf.openrocket.unit.Unit;
-
-
-public class SaveCSVWorker extends SwingWorker<Void, Void> {
-       
-       private static final int BYTES_PER_FIELD_PER_POINT = 7;
-
-       private final File file;
-       private final Simulation simulation;
-       private final FlightDataBranch branch;
-       private final FlightDataType[] fields;
-       private final Unit[] units;
-       private final String fieldSeparator;
-       private final String commentStarter;
-       private final boolean simulationComments;
-       private final boolean fieldComments;
-       private final boolean eventComments;
-       
-       
-       public SaveCSVWorker(File file, Simulation simulation, FlightDataBranch branch,
-                       FlightDataType[] fields, Unit[] units, String fieldSeparator, String commentStarter,
-                       boolean simulationComments, boolean fieldComments, boolean eventComments) {
-               this.file = file;
-               this.simulation = simulation;
-               this.branch = branch;
-               this.fields = fields;
-               this.units = units;
-               this.fieldSeparator = fieldSeparator;
-               this.commentStarter = commentStarter;
-               this.simulationComments = simulationComments;
-               this.fieldComments = fieldComments;
-               this.eventComments = eventComments;
-       }
-
-
-       @Override
-       protected Void doInBackground() throws Exception {
-               
-               int estimate = BYTES_PER_FIELD_PER_POINT * fields.length * branch.getLength();
-               estimate = Math.max(estimate, 1000);
-               
-               // Create the ProgressOutputStream that provides progress estimates
-               ProgressOutputStream os = new ProgressOutputStream(
-                               new BufferedOutputStream(new FileOutputStream(file)), 
-                               estimate, this) {
-                       
-                       @Override
-                       protected void setProgress(int progress) {
-                               SaveCSVWorker.this.setProgress(progress);
-                       }
-                       
-               };
-               
-               try {
-                       CSVExport.exportCSV(os, simulation, branch, fields, units, fieldSeparator, 
-                                       commentStarter, simulationComments, fieldComments, eventComments);
-               } finally {
-                       try {
-                               os.close();
-                       } catch (Exception e) {
-                               ExceptionHandler.handleErrorCondition("Error closing file", e);
-                       }
-               }
-               return null;
-       }
-       
-       
-       
-       /**
-        * Exports a CSV file using a progress dialog if necessary.
-        *
-        * @return      <code>true</code> if the save was successful, <code>false</code> otherwise.
-        */
-       public static boolean export(File file, Simulation simulation, FlightDataBranch branch,
-                       FlightDataType[] fields, Unit[] units, String fieldSeparator, String commentStarter,
-                       boolean simulationComments, boolean fieldComments, boolean eventComments,
-                       Window parent) {
-               
-
-               SaveCSVWorker worker = new SaveCSVWorker(file, simulation, branch, fields, units,
-                               fieldSeparator, commentStarter, simulationComments, fieldComments, 
-                               eventComments);
-               
-           if (!SwingWorkerDialog.runWorker(parent, "Exporting flight data", 
-                       "Writing " + file.getName() + "...", worker)) {
-               
-               // User cancelled the save
-               file.delete();
-               return false;
-           }
-           
-           try {
-                       worker.get();
-               } catch (ExecutionException e) {
-                       Throwable cause = e.getCause();
-                       
-                       if (cause instanceof IOException) {
-                       JOptionPane.showMessageDialog(parent, new String[] { 
-                                       "An I/O error occurred while saving:",
-                                       e.getMessage() }, "Saving failed", JOptionPane.ERROR_MESSAGE);
-                       return false;
-                       } else {
-                               throw new BugException("Unknown error when saving file", e);
-                       }
-                       
-               } catch (InterruptedException e) {
-                       throw new BugException("EDT was interrupted", e);
-               }
-               
-               return true;
-       }
-}
diff --git a/src/net/sf/openrocket/util/SaveFileWorker.java b/src/net/sf/openrocket/util/SaveFileWorker.java
deleted file mode 100644 (file)
index fe5f70c..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-package net.sf.openrocket.util;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-
-import javax.swing.SwingWorker;
-
-import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.file.RocketSaver;
-import net.sf.openrocket.gui.main.ExceptionHandler;
-
-public class SaveFileWorker extends SwingWorker<Void, Void> {
-
-       private final OpenRocketDocument document;
-       private final File file;
-       private final RocketSaver saver;
-       
-       public SaveFileWorker(OpenRocketDocument document, File file, RocketSaver saver) {
-               this.document = document;
-               this.file = file;
-               this.saver = saver;
-       }
-       
-       
-       @Override
-       protected Void doInBackground() throws Exception {
-               
-               int estimate = (int)saver.estimateFileSize(document, 
-                               document.getDefaultStorageOptions());
-               
-               // Create the ProgressOutputStream that provides progress estimates
-               ProgressOutputStream os = new ProgressOutputStream(
-                               new BufferedOutputStream(new FileOutputStream(file)), 
-                               estimate, this) {
-                       
-                       @Override
-                       protected void setProgress(int progress) {
-                               SaveFileWorker.this.setProgress(progress);
-                       }
-                       
-               };
-               
-               try {
-                       saver.save(os, document);
-               } finally {
-                       try {
-                               os.close();
-                       } catch (Exception e) {
-                               ExceptionHandler.handleErrorCondition("Error closing file", e);
-                       }
-               }
-               return null;
-       }
-       
-}
diff --git a/src/net/sf/openrocket/util/SimpleFileFilter.java b/src/net/sf/openrocket/util/SimpleFileFilter.java
deleted file mode 100644 (file)
index 008592a..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-package net.sf.openrocket.util;
-
-import java.io.File;
-
-import javax.swing.filechooser.FileFilter;
-
-/**
- * A FileFilter similar to FileNameExtensionFilter except that
- * it allows multipart extensions (.ork.gz), and also implements
- * the java.io.FileFilter interface.
- * 
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-public class SimpleFileFilter extends FileFilter implements java.io.FileFilter {
-
-       private final String description;
-       private final boolean acceptDir;
-       private final String[] extensions;
-       
-       
-       /**
-        * Create filter that accepts files with the provided extensions that
-        * accepts directories as well.
-        * 
-        * @param description   the description of this file filter.
-        * @param extensions    an array of extensions that match this filter.
-        */
-       public SimpleFileFilter(String description, String ... extensions) {
-               this(description, true, extensions);
-       }
-       
-
-       /**
-        * Create filter that accepts files with the provided extensions.
-        * 
-        * @param description   the description of this file filter.
-        * @param acceptDir             whether to accept directories
-        * @param extensions    an array of extensions that match this filter.
-        */
-       public SimpleFileFilter(String description, boolean acceptDir, String ... extensions) {
-               this.description = description;
-               this.acceptDir = acceptDir;
-               this.extensions = new String[extensions.length];
-               for (int i=0; i<extensions.length; i++) {
-                       String ext = extensions[i].toLowerCase();
-                       if (ext.charAt(0) == '.') {
-                               this.extensions[i] = ext;
-                       } else {
-                               this.extensions[i] = '.' + ext;
-                       }
-               }
-       }
-       
-       
-       @Override
-       public boolean accept(File file) {
-               if (file == null)
-                       return false;
-               if (file.isDirectory())
-                       return acceptDir;
-               
-               String filename = file.getName();
-               filename = filename.toLowerCase();
-               for (String ext: extensions) {
-                       if (filename.endsWith(ext))
-                               return true;
-               }
-               
-               return false;
-       }
-
-       @Override
-       public String getDescription() {
-               return description;
-       }
-
-}
index 9681469534e8bddc5c8d537c571b1a58b39300e4..f3b7431055818f20be717a38fa19edfef1e48c70 100644 (file)
@@ -20,11 +20,11 @@ import javax.swing.SwingUtilities;
 
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.file.motor.GeneralMotorLoader;
+import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.motor.ThrustCurveMotor;
 import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.GUIUtil;
 
 import org.jfree.chart.ChartFactory;
 import org.jfree.chart.ChartPanel;