From: kruland2607 Date: Thu, 1 Dec 2011 19:16:22 +0000 (+0000) Subject: Refactored some gui specific utility classes from net.sf.openrocket.util to net.sf... X-Git-Tag: upstream/12.03~1^2~257 X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=4e02be8874f0e95fe048222e7f174ef84272f795;p=debian%2Fopenrocket Refactored some gui specific utility classes from net.sf.openrocket.util to net.sf.openrocket.gui.util. The following classes were moved: ConcurrentProgressMonitor, ConcurrentProgressMonitorInputStream, FileHelper, GUIUtil, Icons, OpenFileWorker, SaveCSVWorker, SaveFileWorker, SimpleFileFilter. git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@213 180e2498-e6e9-4542-8430-84ac67f01cd8 --- diff --git a/src/net/sf/openrocket/document/OpenRocketDocument.java b/src/net/sf/openrocket/document/OpenRocketDocument.java index c935bd29..3853f4ab 100644 --- a/src/net/sf/openrocket/document/OpenRocketDocument.java +++ b/src/net/sf/openrocket/document/OpenRocketDocument.java @@ -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 diff --git a/src/net/sf/openrocket/file/motor/MotorLoaderHelper.java b/src/net/sf/openrocket/file/motor/MotorLoaderHelper.java index d3bbc3dc..049738a4 100644 --- a/src/net/sf/openrocket/file/motor/MotorLoaderHelper.java +++ b/src/net/sf/openrocket/file/motor/MotorLoaderHelper.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/components/SimulationExportPanel.java b/src/net/sf/openrocket/gui/components/SimulationExportPanel.java index cd73c5f9..30ef196b 100644 --- a/src/net/sf/openrocket/gui/components/SimulationExportPanel.java +++ b/src/net/sf/openrocket/gui/components/SimulationExportPanel.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/components/compass/Tester.java b/src/net/sf/openrocket/gui/components/compass/Tester.java index eda95f56..86a82a49 100644 --- a/src/net/sf/openrocket/gui/components/compass/Tester.java +++ b/src/net/sf/openrocket/gui/components/compass/Tester.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java b/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java index 5bb3448b..a669b2dc 100644 --- a/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java +++ b/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java @@ -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; /** diff --git a/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java b/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java index 802434d7..1ed1ccec 100644 --- a/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/RocketConfig.java b/src/net/sf/openrocket/gui/configdialog/RocketConfig.java index 701295c2..c692f498 100644 --- a/src/net/sf/openrocket/gui/configdialog/RocketConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/RocketConfig.java @@ -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(); diff --git a/src/net/sf/openrocket/gui/dialogs/AboutDialog.java b/src/net/sf/openrocket/gui/dialogs/AboutDialog.java index 5f42865b..e02a3c26 100644 --- a/src/net/sf/openrocket/gui/dialogs/AboutDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/AboutDialog.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/dialogs/BugReportDialog.java b/src/net/sf/openrocket/gui/dialogs/BugReportDialog.java index f9001bf2..27ae214c 100644 --- a/src/net/sf/openrocket/gui/dialogs/BugReportDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/BugReportDialog.java @@ -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; diff --git a/src/net/sf/openrocket/gui/dialogs/ComponentAnalysisDialog.java b/src/net/sf/openrocket/gui/dialogs/ComponentAnalysisDialog.java index 7318d5c7..8fba84e1 100644 --- a/src/net/sf/openrocket/gui/dialogs/ComponentAnalysisDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/ComponentAnalysisDialog.java @@ -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; diff --git a/src/net/sf/openrocket/gui/dialogs/CustomMaterialDialog.java b/src/net/sf/openrocket/gui/dialogs/CustomMaterialDialog.java index aad2f47e..5e5aece8 100644 --- a/src/net/sf/openrocket/gui/dialogs/CustomMaterialDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/CustomMaterialDialog.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/dialogs/DebugLogDialog.java b/src/net/sf/openrocket/gui/dialogs/DebugLogDialog.java index 53742c16..5c36f5d8 100644 --- a/src/net/sf/openrocket/gui/dialogs/DebugLogDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/DebugLogDialog.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/dialogs/DetailDialog.java b/src/net/sf/openrocket/gui/dialogs/DetailDialog.java index 87e36e67..d1f0f547 100644 --- a/src/net/sf/openrocket/gui/dialogs/DetailDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/DetailDialog.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/dialogs/EditMotorConfigurationDialog.java b/src/net/sf/openrocket/gui/dialogs/EditMotorConfigurationDialog.java index b1ef4a9c..0a41ce66 100644 --- a/src/net/sf/openrocket/gui/dialogs/EditMotorConfigurationDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/EditMotorConfigurationDialog.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/dialogs/ExampleDesignDialog.java b/src/net/sf/openrocket/gui/dialogs/ExampleDesignDialog.java index 069791ab..95ad56df 100644 --- a/src/net/sf/openrocket/gui/dialogs/ExampleDesignDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/ExampleDesignDialog.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/dialogs/LicenseDialog.java b/src/net/sf/openrocket/gui/dialogs/LicenseDialog.java index 920e0b47..c3e6141e 100644 --- a/src/net/sf/openrocket/gui/dialogs/LicenseDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/LicenseDialog.java @@ -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"; diff --git a/src/net/sf/openrocket/gui/dialogs/MotorDatabaseLoadingDialog.java b/src/net/sf/openrocket/gui/dialogs/MotorDatabaseLoadingDialog.java index 006b30f4..203a903b 100644 --- a/src/net/sf/openrocket/gui/dialogs/MotorDatabaseLoadingDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/MotorDatabaseLoadingDialog.java @@ -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. diff --git a/src/net/sf/openrocket/gui/dialogs/PrintDialog.java b/src/net/sf/openrocket/gui/dialogs/PrintDialog.java index 924baace..8d8721ef 100644 --- a/src/net/sf/openrocket/gui/dialogs/PrintDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/PrintDialog.java @@ -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; /** diff --git a/src/net/sf/openrocket/gui/dialogs/PrintSettingsDialog.java b/src/net/sf/openrocket/gui/dialogs/PrintSettingsDialog.java index 183ee7a1..53411709 100644 --- a/src/net/sf/openrocket/gui/dialogs/PrintSettingsDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/PrintSettingsDialog.java @@ -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. diff --git a/src/net/sf/openrocket/gui/dialogs/ScaleDialog.java b/src/net/sf/openrocket/gui/dialogs/ScaleDialog.java index c6ccc239..fb8b32fd 100644 --- a/src/net/sf/openrocket/gui/dialogs/ScaleDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/ScaleDialog.java @@ -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; diff --git a/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java b/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java index 08f72089..3ec6d6a1 100644 --- a/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java b/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java index 8c6849e9..eeb939c7 100644 --- a/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorPlotDialog.java b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorPlotDialog.java index 22238caa..c1ecb7cf 100644 --- a/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorPlotDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorPlotDialog.java @@ -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; diff --git a/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java index ca0fb811..28749156 100644 --- a/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java +++ b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java @@ -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; diff --git a/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java b/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java index 1478a2b1..66688bf5 100644 --- a/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java @@ -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; diff --git a/src/net/sf/openrocket/gui/dialogs/optimization/OptimizationPlotDialog.java b/src/net/sf/openrocket/gui/dialogs/optimization/OptimizationPlotDialog.java index c90c31ab..1df3214e 100644 --- a/src/net/sf/openrocket/gui/dialogs/optimization/OptimizationPlotDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/optimization/OptimizationPlotDialog.java @@ -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; diff --git a/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java b/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java index a13be044..4c3f0fd6 100644 --- a/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java @@ -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; diff --git a/src/net/sf/openrocket/gui/main/BasicFrame.java b/src/net/sf/openrocket/gui/main/BasicFrame.java index 5f2d92e0..fb86fbb1 100644 --- a/src/net/sf/openrocket/gui/main/BasicFrame.java +++ b/src/net/sf/openrocket/gui/main/BasicFrame.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/main/RocketActions.java b/src/net/sf/openrocket/gui/main/RocketActions.java index 625afdab..4bd754a9 100644 --- a/src/net/sf/openrocket/gui/main/RocketActions.java +++ b/src/net/sf/openrocket/gui/main/RocketActions.java @@ -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; diff --git a/src/net/sf/openrocket/gui/main/SimulationEditDialog.java b/src/net/sf/openrocket/gui/main/SimulationEditDialog.java index 92c2dac8..39b5fbea 100644 --- a/src/net/sf/openrocket/gui/main/SimulationEditDialog.java +++ b/src/net/sf/openrocket/gui/main/SimulationEditDialog.java @@ -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; diff --git a/src/net/sf/openrocket/gui/main/SimulationPanel.java b/src/net/sf/openrocket/gui/main/SimulationPanel.java index 6a4bef03..36b5a608 100644 --- a/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/main/SimulationRunDialog.java b/src/net/sf/openrocket/gui/main/SimulationRunDialog.java index 9ac4a369..cc1be696 100644 --- a/src/net/sf/openrocket/gui/main/SimulationRunDialog.java +++ b/src/net/sf/openrocket/gui/main/SimulationRunDialog.java @@ -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; diff --git a/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java b/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java index e1e1b2d7..0cd08ff1 100644 --- a/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java +++ b/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java @@ -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; diff --git a/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java b/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java index f2afcae6..06544f52 100644 --- a/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java +++ b/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java @@ -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; /** diff --git a/src/net/sf/openrocket/gui/print/ConceptPrintDialog.java b/src/net/sf/openrocket/gui/print/ConceptPrintDialog.java index 9347ecbf..9a07efa0 100644 --- a/src/net/sf/openrocket/gui/print/ConceptPrintDialog.java +++ b/src/net/sf/openrocket/gui/print/ConceptPrintDialog.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/scalefigure/ScaleSelector.java b/src/net/sf/openrocket/gui/scalefigure/ScaleSelector.java index d4452d6c..a93847d3 100644 --- a/src/net/sf/openrocket/gui/scalefigure/ScaleSelector.java +++ b/src/net/sf/openrocket/gui/scalefigure/ScaleSelector.java @@ -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 index 00000000..b6aa6ea3 --- /dev/null +++ b/src/net/sf/openrocket/gui/util/ConcurrentProgressMonitor.java @@ -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 ProgressMonitor. This class may be instantiated + * and the method {@link #setProgress(int)} called safely from any thread. + *

+ * Why the FSCK&!#&% isn't the default API version thread-safe?!?! + * + * @author Sampo Niskanen + */ +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 index 00000000..ccc0d799 --- /dev/null +++ b/src/net/sf/openrocket/gui/util/ConcurrentProgressMonitorInputStream.java @@ -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 ProgressMonitorInputStream 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 FilterInputStream.read + * 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 FilterInputStream.read + * 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 FilterInputStream.read + * 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 FilterInputStream.skip + * 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 FilterInputStream.close + * to close the progress monitor as well as the stream. + */ + @Override + public void close() throws IOException { + in.close(); + monitor.close(); + } + + + /** + * Overrides FilterInputStream.reset + * 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 index 00000000..8c496393 --- /dev/null +++ b/src/net/sf/openrocket/gui/util/FileHelper.java @@ -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. + *

+ * These methods log the necessary information to the debug log. +* + * @author Sampo Niskanen + */ +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 true to write, false 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 index 00000000..34258d58 --- /dev/null +++ b/src/net/sf/openrocket/gui/util/GUIUtil.java @@ -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 images = new ArrayList(); + 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. + *

+ * The default button must be already attached to the dialog. + * + * @param dialog the dialog. + * @param defaultButton the default button of the dialog, or null. + */ + 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. JTextArea. + * + * @param c the component to modify + */ + public static void setTabToFocusing(Component c) { + Set strokes = new HashSet(Arrays.asList(KeyStroke.getKeyStroke("pressed TAB"))); + c.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, strokes); + strokes = new HashSet(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. + *

+ * 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 (null 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. + *

+ * 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 + */ + 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 index 00000000..8adf191d --- /dev/null +++ b/src/net/sf/openrocket/gui/util/Icons.java @@ -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_MAP; + static { + HashMap map = new HashMap(); + 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 null 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 index 00000000..a52692e5 --- /dev/null +++ b/src/net/sf/openrocket/gui/util/OpenFileWorker.java @@ -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 + */ +public class OpenFileWorker extends SwingWorker { + 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 index 00000000..585a63ac --- /dev/null +++ b/src/net/sf/openrocket/gui/util/SaveCSVWorker.java @@ -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 { + + 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 true if the save was successful, false 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 index 00000000..b9191c4a --- /dev/null +++ b/src/net/sf/openrocket/gui/util/SaveFileWorker.java @@ -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 { + + 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 index 00000000..39ded917 --- /dev/null +++ b/src/net/sf/openrocket/gui/util/SimpleFileFilter.java @@ -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 + */ +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; iProgressMonitor. This class may be instantiated - * and the method {@link #setProgress(int)} called safely from any thread. - *

- * Why the FSCK&!#&% isn't the default API version thread-safe?!?! - * - * @author Sampo Niskanen - */ -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 index 6c45a6cc..00000000 --- a/src/net/sf/openrocket/util/ConcurrentProgressMonitorInputStream.java +++ /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 ProgressMonitorInputStream 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 FilterInputStream.read - * 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 FilterInputStream.read - * 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 FilterInputStream.read - * 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 FilterInputStream.skip - * 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 FilterInputStream.close - * to close the progress monitor as well as the stream. - */ - @Override - public void close() throws IOException { - in.close(); - monitor.close(); - } - - - /** - * Overrides FilterInputStream.reset - * 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 index 0929c328..00000000 --- a/src/net/sf/openrocket/util/FileHelper.java +++ /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. - *

- * These methods log the necessary information to the debug log. -* - * @author Sampo Niskanen - */ -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 true to write, false 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 index e74dbc19..00000000 --- a/src/net/sf/openrocket/util/GUIUtil.java +++ /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 images = new ArrayList(); - 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. - *

- * The default button must be already attached to the dialog. - * - * @param dialog the dialog. - * @param defaultButton the default button of the dialog, or null. - */ - 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. JTextArea. - * - * @param c the component to modify - */ - public static void setTabToFocusing(Component c) { - Set strokes = new HashSet(Arrays.asList(KeyStroke.getKeyStroke("pressed TAB"))); - c.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, strokes); - strokes = new HashSet(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. - *

- * 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 (null 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. - *

- * 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 - */ - 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 index e5f41317..00000000 --- a/src/net/sf/openrocket/util/Icons.java +++ /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_MAP; - static { - HashMap map = new HashMap(); - 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 null 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 index a1d3106d..00000000 --- a/src/net/sf/openrocket/util/OpenFileWorker.java +++ /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 - */ -public class OpenFileWorker extends SwingWorker { - 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 index c9488183..00000000 --- a/src/net/sf/openrocket/util/SaveCSVWorker.java +++ /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 { - - 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 true if the save was successful, false 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 index fe5f70cf..00000000 --- a/src/net/sf/openrocket/util/SaveFileWorker.java +++ /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 { - - 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 index 008592a7..00000000 --- a/src/net/sf/openrocket/util/SimpleFileFilter.java +++ /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 - */ -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