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;
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
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 {
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;
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 {
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 {
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;
/**
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;
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;
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();
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 {
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;
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;
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;
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 {
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;
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 {
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
-import net.sf.openrocket.util.GUIUtil;
+import net.sf.openrocket.gui.util.GUIUtil;
public class DetailDialog {
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;
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 {
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 {
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";
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.
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;
/**
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.
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;
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;
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 {
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 {
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;
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;
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;
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;
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;
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;
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;
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;
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;
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 {
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;
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;
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;
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;
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;
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 {
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;
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;
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;
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;
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;
/**
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 {
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 {
--- /dev/null
+package net.sf.openrocket.gui.util;
+
+import java.awt.Component;
+
+import javax.swing.ProgressMonitor;
+import javax.swing.SwingUtilities;
+
+
+/**
+ * A thread-safe <code>ProgressMonitor</code>. This class may be instantiated
+ * and the method {@link #setProgress(int)} called safely from any thread.
+ * <p>
+ * Why the FSCK&!#&% isn't the default API version thread-safe?!?!
+ *
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class ConcurrentProgressMonitor extends ProgressMonitor {
+
+ public ConcurrentProgressMonitor(Component parentComponent, Object message,
+ String note, int min, int max) {
+ super(parentComponent, message, note, min, max);
+ }
+
+ @Override
+ public void setProgress(final int nv) {
+
+ if (SwingUtilities.isEventDispatchThread()) {
+ super.setProgress(nv);
+ } else {
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+ ConcurrentProgressMonitor.super.setProgress(nv);
+ }
+
+ });
+ }
+ }
+
+
+ @Override
+ public void close() {
+ if (SwingUtilities.isEventDispatchThread()) {
+ super.close();
+ } else {
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+ ConcurrentProgressMonitor.super.close();
+ }
+
+ });
+ }
+ }
+
+
+}
--- /dev/null
+package net.sf.openrocket.gui.util;
+
+import java.awt.Component;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+
+
+
+/**
+ * A functional equivalent of <code>ProgressMonitorInputStream</code> which
+ * uses {@link ConcurrentProgressMonitor} and leaves the progress dialog open
+ * to be manually closed later on.
+ */
+
+public class ConcurrentProgressMonitorInputStream extends FilterInputStream {
+ private ConcurrentProgressMonitor monitor;
+ private int nread = 0;
+ private int size = 0;
+
+
+ /**
+ * Constructs an object to monitor the progress of an input stream.
+ *
+ * @param message Descriptive text to be placed in the dialog box
+ * if one is popped up.
+ * @param parentComponent The component triggering the operation
+ * being monitored.
+ * @param in The input stream to be monitored.
+ */
+ public ConcurrentProgressMonitorInputStream(Component parentComponent,
+ Object message, InputStream in) {
+ super(in);
+ try {
+ size = in.available();
+ } catch (IOException ioe) {
+ size = 0;
+ }
+ monitor = new ConcurrentProgressMonitor(parentComponent, message, null, 0,
+ size + 1);
+ }
+
+
+ /**
+ * Get the ProgressMonitor object being used by this stream. Normally
+ * this isn't needed unless you want to do something like change the
+ * descriptive text partway through reading the file.
+ * @return the ProgressMonitor object used by this object
+ */
+ public ConcurrentProgressMonitor getProgressMonitor() {
+ return monitor;
+ }
+
+
+ /**
+ * Overrides <code>FilterInputStream.read</code>
+ * to update the progress monitor after the read.
+ */
+ @Override
+ public int read() throws IOException {
+ int c = in.read();
+ if (c >= 0)
+ monitor.setProgress(++nread);
+ if (monitor.isCanceled()) {
+ InterruptedIOException exc = new InterruptedIOException("progress");
+ exc.bytesTransferred = nread;
+ throw exc;
+ }
+ return c;
+ }
+
+
+ /**
+ * Overrides <code>FilterInputStream.read</code>
+ * to update the progress monitor after the read.
+ */
+ @Override
+ public int read(byte b[]) throws IOException {
+ int nr = in.read(b);
+ if (nr > 0)
+ monitor.setProgress(nread += nr);
+ if (monitor.isCanceled()) {
+ InterruptedIOException exc = new InterruptedIOException("progress");
+ exc.bytesTransferred = nread;
+ throw exc;
+ }
+ return nr;
+ }
+
+
+ /**
+ * Overrides <code>FilterInputStream.read</code>
+ * to update the progress monitor after the read.
+ */
+ @Override
+ public int read(byte b[], int off, int len) throws IOException {
+ int nr = in.read(b, off, len);
+ if (nr > 0)
+ monitor.setProgress(nread += nr);
+ if (monitor.isCanceled()) {
+ InterruptedIOException exc = new InterruptedIOException("progress");
+ exc.bytesTransferred = nread;
+ throw exc;
+ }
+ return nr;
+ }
+
+
+ /**
+ * Overrides <code>FilterInputStream.skip</code>
+ * to update the progress monitor after the skip.
+ */
+ @Override
+ public long skip(long n) throws IOException {
+ long nr = in.skip(n);
+ if (nr > 0)
+ monitor.setProgress(nread += nr);
+ return nr;
+ }
+
+
+ /**
+ * Overrides <code>FilterInputStream.close</code>
+ * to close the progress monitor as well as the stream.
+ */
+ @Override
+ public void close() throws IOException {
+ in.close();
+ monitor.close();
+ }
+
+
+ /**
+ * Overrides <code>FilterInputStream.reset</code>
+ * to reset the progress monitor as well as the stream.
+ */
+ @Override
+ public synchronized void reset() throws IOException {
+ in.reset();
+ nread = size - in.available();
+ monitor.setProgress(nread);
+ }
+}
--- /dev/null
+package net.sf.openrocket.gui.util;
+
+import java.awt.Component;
+import java.io.File;
+import java.io.IOException;
+
+import javax.swing.JOptionPane;
+import javax.swing.filechooser.FileFilter;
+
+import net.sf.openrocket.l10n.L10N;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
+
+/**
+ * Helper methods related to user-initiated file manipulation.
+ * <p>
+ * These methods log the necessary information to the debug log.
+*
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public final class FileHelper {
+ private static final LogHelper log = Application.getLogger();
+ private static final Translator trans = Application.getTranslator();
+
+
+ // TODO: HIGH: Rename translation keys
+
+ /** File filter for any rocket designs (*.ork, *.rkt) */
+ public static final FileFilter ALL_DESIGNS_FILTER =
+ new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter1"),
+ ".ork", ".ork.gz", ".rkt", ".rkt.gz");
+
+ /** File filter for OpenRocket designs (*.ork) */
+ public static final FileFilter OPENROCKET_DESIGN_FILTER =
+ new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter2"), ".ork", ".ork.gz");
+
+ /** File filter for RockSim designs (*.rkt) */
+ public static final FileFilter ROCKSIM_DESIGN_FILTER =
+ new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter3"), ".rkt", ".rkt.gz");
+
+ /** File filter for PDF files (*.pdf) */
+ public static final FileFilter PDF_FILTER =
+ new SimpleFileFilter(trans.get("filetypes.pdf"), ".pdf");
+
+ /** File filter for CSV files (*.csv) */
+ public static final FileFilter CSV_FILE_FILTER =
+ new SimpleFileFilter(trans.get("SimExpPan.desc"), ".csv");
+
+
+
+
+
+ private FileHelper() {
+ // Prevent instantiation
+ }
+
+ /**
+ * Ensure that the provided file has a file extension. If the file does not have
+ * any extension, append the provided extension to it.
+ *
+ * @param original the original file
+ * @param extension the extension to append if none exists (without preceding dot)
+ * @return the resulting filen
+ */
+ public static File ensureExtension(File original, String extension) {
+
+ if (original.getName().indexOf('.') < 0) {
+ log.debug(1, "File name does not contain extension, adding '" + extension + "'");
+ String name = original.getAbsolutePath();
+ name = name + "." + extension;
+ return new File(name);
+ }
+
+ return original;
+ }
+
+
+ /**
+ * Confirm that it is allowed to write to a file. If the file exists,
+ * a confirmation dialog will be presented to the user to ensure overwriting is ok.
+ *
+ * @param file the file that is going to be written.
+ * @param parent the parent component for the dialog.
+ * @return <code>true</code> to write, <code>false</code> to abort.
+ */
+ public static boolean confirmWrite(File file, Component parent) {
+ if (file.exists()) {
+ log.info(1, "File " + file + " exists, confirming overwrite from user");
+ int result = JOptionPane.showConfirmDialog(parent,
+ L10N.replace(trans.get("error.fileExists.desc"), "{filename}", file.getName()),
+ trans.get("error.fileExists.title"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
+ if (result != JOptionPane.YES_OPTION) {
+ log.user(1, "User decided not to overwrite the file");
+ return false;
+ }
+ log.user(1, "User decided to overwrite the file");
+ }
+ return true;
+ }
+
+
+ /**
+ * Display an error message to the user that writing a file failed.
+ *
+ * @param e the I/O exception that caused the error.
+ * @param parent the parent component for the dialog.
+ */
+ public static void errorWriting(IOException e, Component parent) {
+
+ log.warn(1, "Error writing to file", e);
+ JOptionPane.showMessageDialog(parent,
+ new Object[] {
+ trans.get("error.writing.desc"),
+ e.getLocalizedMessage()
+ }, trans.get("error.writing.title"), JOptionPane.ERROR_MESSAGE);
+
+ }
+
+}
--- /dev/null
+package net.sf.openrocket.gui.util;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Image;
+import java.awt.KeyboardFocusManager;
+import java.awt.Point;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.beans.PropertyChangeListener;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.imageio.ImageIO;
+import javax.swing.AbstractAction;
+import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.BoundedRangeModel;
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultBoundedRangeModel;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.DefaultListSelectionModel;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JRootPane;
+import javax.swing.JSlider;
+import javax.swing.JSpinner;
+import javax.swing.JTable;
+import javax.swing.JTree;
+import javax.swing.KeyStroke;
+import javax.swing.ListSelectionModel;
+import javax.swing.LookAndFeel;
+import javax.swing.RootPaneContainer;
+import javax.swing.SpinnerModel;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ChangeListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.DefaultTableColumnModel;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableModel;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.DefaultTreeSelectionModel;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreeSelectionModel;
+
+import net.sf.openrocket.gui.Resettable;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.BugException;
+import net.sf.openrocket.util.Invalidatable;
+import net.sf.openrocket.util.MemoryManagement;
+import net.sf.openrocket.util.Prefs;
+
+public class GUIUtil {
+ private static final LogHelper log = Application.getLogger();
+
+ private static final KeyStroke ESCAPE = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+ private static final String CLOSE_ACTION_KEY = "escape:WINDOW_CLOSING";
+
+ private static final List<Image> images = new ArrayList<Image>();
+ static {
+ loadImage("pix/icon/icon-256.png");
+ loadImage("pix/icon/icon-064.png");
+ loadImage("pix/icon/icon-048.png");
+ loadImage("pix/icon/icon-032.png");
+ loadImage("pix/icon/icon-016.png");
+ }
+
+ private static void loadImage(String file) {
+ InputStream is;
+
+ is = ClassLoader.getSystemResourceAsStream(file);
+ if (is == null)
+ return;
+
+ try {
+ Image image = ImageIO.read(is);
+ images.add(image);
+ } catch (IOException ignore) {
+ ignore.printStackTrace();
+ }
+ }
+
+
+
+ /**
+ * Set suitable options for a single-use disposable dialog. This includes
+ * setting ESC to close the dialog, adding the appropriate window icons and
+ * setting the location based on the platform. If defaultButton is provided,
+ * it is set to the default button action.
+ * <p>
+ * The default button must be already attached to the dialog.
+ *
+ * @param dialog the dialog.
+ * @param defaultButton the default button of the dialog, or <code>null</code>.
+ */
+ public static void setDisposableDialogOptions(JDialog dialog, JButton defaultButton) {
+ installEscapeCloseOperation(dialog);
+ setWindowIcons(dialog);
+ addModelNullingListener(dialog);
+ dialog.setLocationByPlatform(true);
+ dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ dialog.pack();
+ if (defaultButton != null) {
+ setDefaultButton(defaultButton);
+ }
+ }
+
+
+
+ /**
+ * Add the correct action to close a JDialog when the ESC key is pressed.
+ * The dialog is closed by sending is a WINDOW_CLOSING event.
+ *
+ * @param dialog the dialog for which to install the action.
+ */
+ public static void installEscapeCloseOperation(final JDialog dialog) {
+ Action dispatchClosing = new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ log.user("Closing dialog " + dialog);
+ dialog.dispatchEvent(new WindowEvent(dialog, WindowEvent.WINDOW_CLOSING));
+ }
+ };
+ JRootPane root = dialog.getRootPane();
+ root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ESCAPE, CLOSE_ACTION_KEY);
+ root.getActionMap().put(CLOSE_ACTION_KEY, dispatchClosing);
+ }
+
+
+ /**
+ * Set the given button as the default button of the frame/dialog it is in. The button
+ * must be first attached to the window component hierarchy.
+ *
+ * @param button the button to set as the default button.
+ */
+ public static void setDefaultButton(JButton button) {
+ Window w = SwingUtilities.windowForComponent(button);
+ if (w == null) {
+ throw new IllegalArgumentException("Attach button to a window first.");
+ }
+ if (!(w instanceof RootPaneContainer)) {
+ throw new IllegalArgumentException("Button not attached to RootPaneContainer, w=" + w);
+ }
+ ((RootPaneContainer) w).getRootPane().setDefaultButton(button);
+ }
+
+
+
+ /**
+ * Change the behavior of a component so that TAB and Shift-TAB cycles the focus of
+ * the components. This is necessary for e.g. <code>JTextArea</code>.
+ *
+ * @param c the component to modify
+ */
+ public static void setTabToFocusing(Component c) {
+ Set<KeyStroke> strokes = new HashSet<KeyStroke>(Arrays.asList(KeyStroke.getKeyStroke("pressed TAB")));
+ c.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, strokes);
+ strokes = new HashSet<KeyStroke>(Arrays.asList(KeyStroke.getKeyStroke("shift pressed TAB")));
+ c.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, strokes);
+ }
+
+
+
+ /**
+ * Set the OpenRocket icons to the window icons.
+ *
+ * @param window the window to set.
+ */
+ public static void setWindowIcons(Window window) {
+ window.setIconImages(images);
+ }
+
+ /**
+ * Add a listener to the provided window that will call {@link #setNullModels(Component)}
+ * on the window once it is closed. This method may only be used on single-use
+ * windows and dialogs, that will never be shown again once closed!
+ *
+ * @param window the window to add the listener to.
+ */
+ public static void addModelNullingListener(final Window window) {
+ window.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosed(WindowEvent e) {
+ log.debug("Clearing all models of window " + window);
+ setNullModels(window);
+ MemoryManagement.collectable(window);
+ }
+ });
+ }
+
+
+
+ /**
+ * Set the best available look-and-feel into use.
+ */
+ public static void setBestLAF() {
+ /*
+ * Set the look-and-feel. On Linux, Motif/Metal is sometimes incorrectly used
+ * which is butt-ugly, so if the system l&f is Motif/Metal, we search for a few
+ * other alternatives.
+ */
+ try {
+ // Set system L&F
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+
+ // Check whether we have an ugly L&F
+ LookAndFeel laf = UIManager.getLookAndFeel();
+ if (laf == null ||
+ laf.getName().matches(".*[mM][oO][tT][iI][fF].*") ||
+ laf.getName().matches(".*[mM][eE][tT][aA][lL].*")) {
+
+ // Search for better LAF
+ UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
+ String lafNames[] = {
+ ".*[gG][tT][kK].*",
+ ".*[wW][iI][nN].*",
+ ".*[mM][aA][cC].*",
+ ".*[aA][qQ][uU][aA].*",
+ ".*[nN][iI][mM][bB].*"
+ };
+
+ lf: for (String lafName : lafNames) {
+ for (UIManager.LookAndFeelInfo l : info) {
+ if (l.getName().matches(lafName)) {
+ UIManager.setLookAndFeel(l.getClassName());
+ break lf;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ log.warn("Error setting LAF: " + e);
+ }
+ }
+
+
+ /**
+ * Changes the size of the font of the specified component by the given amount.
+ *
+ * @param component the component for which to change the font
+ * @param size the change in the font size
+ */
+ public static void changeFontSize(JComponent component, float size) {
+ Font font = component.getFont();
+ font = font.deriveFont(font.getSize2D() + size);
+ component.setFont(font);
+ }
+
+
+
+ /**
+ * Automatically remember the size of a window. This stores the window size in the user
+ * preferences when resizing/maximizing the window and sets the state on the first call.
+ */
+ public static void rememberWindowSize(final Window window) {
+ window.addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentResized(ComponentEvent e) {
+ log.debug("Storing size of " + window.getClass().getName() + ": " + window.getSize());
+ Prefs.setWindowSize(window.getClass(), window.getSize());
+ if (window instanceof JFrame) {
+ if ((((JFrame) window).getExtendedState() & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH) {
+ log.debug("Storing maximized state of " + window.getClass().getName());
+ Prefs.setWindowMaximized(window.getClass());
+ }
+ }
+ }
+ });
+
+ if (Prefs.isWindowMaximized(window.getClass())) {
+ if (window instanceof JFrame) {
+ ((JFrame) window).setExtendedState(JFrame.MAXIMIZED_BOTH);
+ }
+ } else {
+ Dimension dim = Prefs.getWindowSize(window.getClass());
+ if (dim != null) {
+ window.setSize(dim);
+ }
+ }
+ }
+
+
+ /**
+ * Automatically remember the position of a window. The position is stored in the user preferences
+ * every time the window is moved and set from there when first calling this method.
+ */
+ public static void rememberWindowPosition(final Window window) {
+ window.addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentMoved(ComponentEvent e) {
+ Prefs.setWindowPosition(window.getClass(), window.getLocation());
+ }
+ });
+
+ // Set window position according to preferences, and set prefs when moving
+ Point position = Prefs.getWindowPosition(window.getClass());
+ if (position != null) {
+ window.setLocationByPlatform(false);
+ window.setLocation(position);
+ }
+ }
+
+
+ /**
+ * Changes the style of the font of the specified border.
+ *
+ * @param border the component for which to change the font
+ * @param style the change in the font style
+ */
+ public static void changeFontStyle(TitledBorder border, int style) {
+ /*
+ * The fix of JRE bug #4129681 causes a TitledBorder occasionally to
+ * return a null font. We try to work around the issue by detecting it
+ * and reverting to the font of a JLabel instead.
+ */
+ Font font = border.getTitleFont();
+ if (font == null) {
+ log.error("Border font is null, reverting to JLabel font");
+ font = new JLabel().getFont();
+ if (font == null) {
+ log.error("JLabel font is null, not modifying font");
+ return;
+ }
+ }
+ font = font.deriveFont(style);
+ if (font == null) {
+ throw new BugException("Derived font is null");
+ }
+ border.setTitleFont(font);
+ }
+
+
+
+ /**
+ * Traverses recursively the component tree, and sets all applicable component
+ * models to null, so as to remove the listener connections. After calling this
+ * method the component hierarchy should no longed be used.
+ * <p>
+ * All components that use custom models should be added to this method, as
+ * there exists no standard way of removing the model from a component.
+ *
+ * @param c the component (<code>null</code> is ok)
+ */
+ public static void setNullModels(Component c) {
+ if (c == null)
+ return;
+
+ // Remove various listeners
+ for (ComponentListener l : c.getComponentListeners()) {
+ c.removeComponentListener(l);
+ }
+ for (FocusListener l : c.getFocusListeners()) {
+ c.removeFocusListener(l);
+ }
+ for (MouseListener l : c.getMouseListeners()) {
+ c.removeMouseListener(l);
+ }
+ for (PropertyChangeListener l : c.getPropertyChangeListeners()) {
+ c.removePropertyChangeListener(l);
+ }
+ for (PropertyChangeListener l : c.getPropertyChangeListeners("model")) {
+ c.removePropertyChangeListener("model", l);
+ }
+ for (PropertyChangeListener l : c.getPropertyChangeListeners("action")) {
+ c.removePropertyChangeListener("action", l);
+ }
+
+ // Remove models for known components
+ // Why the FSCK must this be so hard?!?!?
+
+ if (c instanceof JSpinner) {
+
+ JSpinner spinner = (JSpinner) c;
+ for (ChangeListener l : spinner.getChangeListeners()) {
+ spinner.removeChangeListener(l);
+ }
+ SpinnerModel model = spinner.getModel();
+ spinner.setModel(new SpinnerNumberModel());
+ if (model instanceof Invalidatable) {
+ ((Invalidatable) model).invalidate();
+ }
+
+ } else if (c instanceof JSlider) {
+
+ JSlider slider = (JSlider) c;
+ for (ChangeListener l : slider.getChangeListeners()) {
+ slider.removeChangeListener(l);
+ }
+ BoundedRangeModel model = slider.getModel();
+ slider.setModel(new DefaultBoundedRangeModel());
+ if (model instanceof Invalidatable) {
+ ((Invalidatable) model).invalidate();
+ }
+
+ } else if (c instanceof JComboBox) {
+
+ JComboBox combo = (JComboBox) c;
+ for (ActionListener l : combo.getActionListeners()) {
+ combo.removeActionListener(l);
+ }
+ ComboBoxModel model = combo.getModel();
+ combo.setModel(new DefaultComboBoxModel());
+ if (model instanceof Invalidatable) {
+ ((Invalidatable) model).invalidate();
+ }
+
+ } else if (c instanceof AbstractButton) {
+
+ AbstractButton button = (AbstractButton) c;
+ for (ActionListener l : button.getActionListeners()) {
+ button.removeActionListener(l);
+ }
+ Action model = button.getAction();
+ button.setAction(new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ }
+ });
+ if (model instanceof Invalidatable) {
+ ((Invalidatable) model).invalidate();
+ }
+
+ } else if (c instanceof JTable) {
+
+ JTable table = (JTable) c;
+ TableModel model1 = table.getModel();
+ table.setModel(new DefaultTableModel());
+ if (model1 instanceof Invalidatable) {
+ ((Invalidatable) model1).invalidate();
+ }
+
+ TableColumnModel model2 = table.getColumnModel();
+ table.setColumnModel(new DefaultTableColumnModel());
+ if (model2 instanceof Invalidatable) {
+ ((Invalidatable) model2).invalidate();
+ }
+
+ ListSelectionModel model3 = table.getSelectionModel();
+ table.setSelectionModel(new DefaultListSelectionModel());
+ if (model3 instanceof Invalidatable) {
+ ((Invalidatable) model3).invalidate();
+ }
+
+ } else if (c instanceof JTree) {
+
+ JTree tree = (JTree) c;
+ TreeModel model1 = tree.getModel();
+ tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
+ if (model1 instanceof Invalidatable) {
+ ((Invalidatable) model1).invalidate();
+ }
+
+ TreeSelectionModel model2 = tree.getSelectionModel();
+ tree.setSelectionModel(new DefaultTreeSelectionModel());
+ if (model2 instanceof Invalidatable) {
+ ((Invalidatable) model2).invalidate();
+ }
+
+ } else if (c instanceof Resettable) {
+
+ ((Resettable) c).resetModel();
+
+ }
+
+ // Recurse the component
+ if (c instanceof Container) {
+ Component[] cs = ((Container) c).getComponents();
+ for (Component sub : cs)
+ setNullModels(sub);
+ }
+
+ }
+
+
+
+ /**
+ * A mouse listener that toggles the state of a boolean value in a table model
+ * when clicked on another column of the table.
+ * <p>
+ * NOTE: If the table model does not extend AbstractTableModel, the model must
+ * fire a change event (which in normal table usage is not necessary).
+ *
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+ public static class BooleanTableClickListener extends MouseAdapter {
+
+ private final JTable table;
+ private final int clickColumn;
+ private final int booleanColumn;
+
+
+ public BooleanTableClickListener(JTable table) {
+ this(table, 1, 0);
+ }
+
+
+ public BooleanTableClickListener(JTable table, int clickColumn, int booleanColumn) {
+ this.table = table;
+ this.clickColumn = clickColumn;
+ this.booleanColumn = booleanColumn;
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if (e.getButton() != MouseEvent.BUTTON1)
+ return;
+
+ Point p = e.getPoint();
+ int col = table.columnAtPoint(p);
+ if (col < 0)
+ return;
+ col = table.convertColumnIndexToModel(col);
+ if (col != clickColumn)
+ return;
+
+ int row = table.rowAtPoint(p);
+ if (row < 0)
+ return;
+ row = table.convertRowIndexToModel(row);
+ if (row < 0)
+ return;
+
+ TableModel model = table.getModel();
+ Object value = model.getValueAt(row, booleanColumn);
+
+ if (!(value instanceof Boolean)) {
+ throw new IllegalStateException("Table value at row=" + row + " col=" +
+ booleanColumn + " is not a Boolean, value=" + value);
+ }
+
+ Boolean b = (Boolean) value;
+ b = !b;
+ model.setValueAt(b, row, booleanColumn);
+ if (model instanceof AbstractTableModel) {
+ ((AbstractTableModel) model).fireTableCellUpdated(row, booleanColumn);
+ }
+ }
+
+ }
+
+}
--- /dev/null
+package net.sf.openrocket.gui.util;
+
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
+
+
+public class Icons {
+ private static final LogHelper log = Application.getLogger();
+ private static final Translator trans = Application.getTranslator();
+
+ static {
+ log.debug("Starting to load icons");
+ }
+
+ /**
+ * Icons used for showing the status of a simulation (up to date, out of date, etc).
+ */
+ public static final Map<Simulation.Status, Icon> SIMULATION_STATUS_ICON_MAP;
+ static {
+ HashMap<Simulation.Status, Icon> map = new HashMap<Simulation.Status, Icon>();
+ map.put(Simulation.Status.NOT_SIMULATED, loadImageIcon("pix/spheres/gray-16x16.png", "Not simulated"));
+ map.put(Simulation.Status.UPTODATE, loadImageIcon("pix/spheres/green-16x16.png", "Up to date"));
+ map.put(Simulation.Status.LOADED, loadImageIcon("pix/spheres/yellow-16x16.png", "Loaded from file"));
+ map.put(Simulation.Status.OUTDATED, loadImageIcon("pix/spheres/red-16x16.png", "Out-of-date"));
+ map.put(Simulation.Status.EXTERNAL, loadImageIcon("pix/spheres/blue-16x16.png", "Imported data"));
+ SIMULATION_STATUS_ICON_MAP = Collections.unmodifiableMap(map);
+ }
+
+ public static final Icon SIMULATION_LISTENER_OK;
+ public static final Icon SIMULATION_LISTENER_ERROR;
+ static {
+ SIMULATION_LISTENER_OK = SIMULATION_STATUS_ICON_MAP.get(Simulation.Status.UPTODATE);
+ SIMULATION_LISTENER_ERROR = SIMULATION_STATUS_ICON_MAP.get(Simulation.Status.OUTDATED);
+ }
+
+
+ public static final Icon FILE_NEW = loadImageIcon("pix/icons/document-new.png", "New document");
+ public static final Icon FILE_OPEN = loadImageIcon("pix/icons/document-open.png", "Open document");
+ public static final Icon FILE_OPEN_EXAMPLE = loadImageIcon("pix/icons/document-open-example.png", "Open example document");
+ public static final Icon FILE_SAVE = loadImageIcon("pix/icons/document-save.png", "Save document");
+ public static final Icon FILE_SAVE_AS = loadImageIcon("pix/icons/document-save-as.png", "Save document as");
+ public static final Icon FILE_PRINT = loadImageIcon("pix/icons/document-print.png", "Print document");
+ public static final Icon FILE_CLOSE = loadImageIcon("pix/icons/document-close.png", "Close document");
+ public static final Icon FILE_QUIT = loadImageIcon("pix/icons/application-exit.png", "Quit OpenRocket");
+
+ public static final Icon EDIT_UNDO = loadImageIcon("pix/icons/edit-undo.png", trans.get("Icons.Undo"));
+ public static final Icon EDIT_REDO = loadImageIcon("pix/icons/edit-redo.png", trans.get("Icons.Redo"));
+ public static final Icon EDIT_CUT = loadImageIcon("pix/icons/edit-cut.png", "Cut");
+ public static final Icon EDIT_COPY = loadImageIcon("pix/icons/edit-copy.png", "Copy");
+ public static final Icon EDIT_PASTE = loadImageIcon("pix/icons/edit-paste.png", "Paste");
+ public static final Icon EDIT_DELETE = loadImageIcon("pix/icons/edit-delete.png", "Delete");
+ public static final Icon EDIT_SCALE = loadImageIcon("pix/icons/edit-scale.png", "Scale");
+
+ public static final Icon HELP_ABOUT = loadImageIcon("pix/icons/help-about.png", "About");
+ public static final Icon HELP_BUG_REPORT = loadImageIcon("pix/icons/help-bug.png", "Bug report");
+ public static final Icon HELP_DEBUG_LOG = loadImageIcon("pix/icons/help-log.png", "Debug log");
+ public static final Icon HELP_LICENSE = loadImageIcon("pix/icons/help-license.png", "License");
+
+ public static final Icon ZOOM_IN = loadImageIcon("pix/icons/zoom-in.png", "Zoom in");
+ public static final Icon ZOOM_OUT = loadImageIcon("pix/icons/zoom-out.png", "Zoom out");
+
+ public static final Icon PREFERENCES = loadImageIcon("pix/icons/preferences.png", "Preferences");
+
+ public static final Icon DELETE = loadImageIcon("pix/icons/delete.png", "Delete");
+
+ static {
+ log.debug("Icons loaded");
+ }
+
+ /**
+ * Load an ImageIcon from the specified file. The file is obtained as a system
+ * resource from the normal classpath. If the file cannot be loaded a bug dialog
+ * is opened and <code>null</code> is returned.
+ *
+ * @param file the file to load.
+ * @param name the description of the icon.
+ * @return the ImageIcon, or null if could not be loaded (after the user closes the dialog)
+ */
+ public static ImageIcon loadImageIcon(String file, String name) {
+ if (System.getProperty("openrocket.unittest") != null) {
+ return new ImageIcon();
+ }
+
+ URL url = ClassLoader.getSystemResource(file);
+ if (url == null) {
+ ExceptionHandler.handleErrorCondition("Image file " + file + " not found, ignoring.");
+ return null;
+ }
+ return new ImageIcon(url, name);
+ }
+}
--- /dev/null
+package net.sf.openrocket.gui.util;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+
+import javax.swing.SwingWorker;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.file.RocketLoader;
+import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.MathUtil;
+
+
+/**
+ * A SwingWorker thread that opens a rocket design file.
+ *
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class OpenFileWorker extends SwingWorker<OpenRocketDocument, Void> {
+ private static final LogHelper log = Application.getLogger();
+
+ private final File file;
+ private final InputStream stream;
+ private final RocketLoader loader;
+
+ public OpenFileWorker(File file, RocketLoader loader) {
+ this.file = file;
+ this.stream = null;
+ this.loader = loader;
+ }
+
+
+ public OpenFileWorker(InputStream stream, RocketLoader loader) {
+ this.stream = stream;
+ this.file = null;
+ this.loader = loader;
+ }
+
+ public RocketLoader getRocketLoader() {
+ return loader;
+ }
+
+ @Override
+ protected OpenRocketDocument doInBackground() throws Exception {
+ InputStream is;
+
+ // Get the correct input stream
+ if (file != null) {
+ is = new FileInputStream(file);
+ } else {
+ is = stream;
+ }
+
+ // Buffer stream unless already buffered
+ if (!(is instanceof BufferedInputStream)) {
+ is = new BufferedInputStream(is);
+ }
+
+ // Encapsulate in a ProgressInputStream
+ is = new ProgressInputStream(is);
+
+ try {
+ return loader.load(is);
+ } finally {
+ try {
+ is.close();
+ } catch (Exception e) {
+ ExceptionHandler.handleErrorCondition("Error closing file", e);
+ }
+ }
+ }
+
+
+
+
+ private class ProgressInputStream extends FilterInputStream {
+
+ private final int size;
+ private int readBytes = 0;
+ private int progress = -1;
+
+ protected ProgressInputStream(InputStream in) {
+ super(in);
+ int s;
+ try {
+ s = in.available();
+ } catch (IOException e) {
+ log.info("Exception while estimating available bytes!", e);
+ s = 0;
+ }
+ size = Math.max(s, 1);
+ }
+
+
+
+ @Override
+ public int read() throws IOException {
+ int c = in.read();
+ if (c >= 0) {
+ readBytes++;
+ setProgress();
+ }
+ if (isCancelled()) {
+ throw new InterruptedIOException("OpenFileWorker was cancelled");
+ }
+ return c;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int n = in.read(b, off, len);
+ if (n > 0) {
+ readBytes += n;
+ setProgress();
+ }
+ if (isCancelled()) {
+ throw new InterruptedIOException("OpenFileWorker was cancelled");
+ }
+ return n;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ int n = in.read(b);
+ if (n > 0) {
+ readBytes += n;
+ setProgress();
+ }
+ if (isCancelled()) {
+ throw new InterruptedIOException("OpenFileWorker was cancelled");
+ }
+ return n;
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ long nr = in.skip(n);
+ if (nr > 0) {
+ readBytes += nr;
+ setProgress();
+ }
+ if (isCancelled()) {
+ throw new InterruptedIOException("OpenFileWorker was cancelled");
+ }
+ return nr;
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ in.reset();
+ readBytes = size - in.available();
+ setProgress();
+ if (isCancelled()) {
+ throw new InterruptedIOException("OpenFileWorker was cancelled");
+ }
+ }
+
+
+
+ private void setProgress() {
+ int p = MathUtil.clamp(readBytes * 100 / size, 0, 100);
+ if (progress != p) {
+ progress = p;
+ OpenFileWorker.this.setProgress(progress);
+ }
+ }
+ }
+}
--- /dev/null
+package net.sf.openrocket.gui.util;
+
+import java.awt.Window;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+
+import javax.swing.JOptionPane;
+import javax.swing.SwingWorker;
+
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.file.CSVExport;
+import net.sf.openrocket.gui.dialogs.SwingWorkerDialog;
+import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.simulation.FlightDataBranch;
+import net.sf.openrocket.simulation.FlightDataType;
+import net.sf.openrocket.unit.Unit;
+import net.sf.openrocket.util.BugException;
+import net.sf.openrocket.util.ProgressOutputStream;
+
+
+public class SaveCSVWorker extends SwingWorker<Void, Void> {
+
+ private static final int BYTES_PER_FIELD_PER_POINT = 7;
+
+ private final File file;
+ private final Simulation simulation;
+ private final FlightDataBranch branch;
+ private final FlightDataType[] fields;
+ private final Unit[] units;
+ private final String fieldSeparator;
+ private final String commentStarter;
+ private final boolean simulationComments;
+ private final boolean fieldComments;
+ private final boolean eventComments;
+
+
+ public SaveCSVWorker(File file, Simulation simulation, FlightDataBranch branch,
+ FlightDataType[] fields, Unit[] units, String fieldSeparator, String commentStarter,
+ boolean simulationComments, boolean fieldComments, boolean eventComments) {
+ this.file = file;
+ this.simulation = simulation;
+ this.branch = branch;
+ this.fields = fields;
+ this.units = units;
+ this.fieldSeparator = fieldSeparator;
+ this.commentStarter = commentStarter;
+ this.simulationComments = simulationComments;
+ this.fieldComments = fieldComments;
+ this.eventComments = eventComments;
+ }
+
+
+ @Override
+ protected Void doInBackground() throws Exception {
+
+ int estimate = BYTES_PER_FIELD_PER_POINT * fields.length * branch.getLength();
+ estimate = Math.max(estimate, 1000);
+
+ // Create the ProgressOutputStream that provides progress estimates
+ ProgressOutputStream os = new ProgressOutputStream(
+ new BufferedOutputStream(new FileOutputStream(file)),
+ estimate, this) {
+
+ @Override
+ protected void setProgress(int progress) {
+ SaveCSVWorker.this.setProgress(progress);
+ }
+
+ };
+
+ try {
+ CSVExport.exportCSV(os, simulation, branch, fields, units, fieldSeparator,
+ commentStarter, simulationComments, fieldComments, eventComments);
+ } finally {
+ try {
+ os.close();
+ } catch (Exception e) {
+ ExceptionHandler.handleErrorCondition("Error closing file", e);
+ }
+ }
+ return null;
+ }
+
+
+
+ /**
+ * Exports a CSV file using a progress dialog if necessary.
+ *
+ * @return <code>true</code> if the save was successful, <code>false</code> otherwise.
+ */
+ public static boolean export(File file, Simulation simulation, FlightDataBranch branch,
+ FlightDataType[] fields, Unit[] units, String fieldSeparator, String commentStarter,
+ boolean simulationComments, boolean fieldComments, boolean eventComments,
+ Window parent) {
+
+
+ SaveCSVWorker worker = new SaveCSVWorker(file, simulation, branch, fields, units,
+ fieldSeparator, commentStarter, simulationComments, fieldComments,
+ eventComments);
+
+ if (!SwingWorkerDialog.runWorker(parent, "Exporting flight data",
+ "Writing " + file.getName() + "...", worker)) {
+
+ // User cancelled the save
+ file.delete();
+ return false;
+ }
+
+ try {
+ worker.get();
+ } catch (ExecutionException e) {
+ Throwable cause = e.getCause();
+
+ if (cause instanceof IOException) {
+ JOptionPane.showMessageDialog(parent, new String[] {
+ "An I/O error occurred while saving:",
+ e.getMessage() }, "Saving failed", JOptionPane.ERROR_MESSAGE);
+ return false;
+ } else {
+ throw new BugException("Unknown error when saving file", e);
+ }
+
+ } catch (InterruptedException e) {
+ throw new BugException("EDT was interrupted", e);
+ }
+
+ return true;
+ }
+}
--- /dev/null
+package net.sf.openrocket.gui.util;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+
+import javax.swing.SwingWorker;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.file.RocketSaver;
+import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.util.ProgressOutputStream;
+
+public class SaveFileWorker extends SwingWorker<Void, Void> {
+
+ private final OpenRocketDocument document;
+ private final File file;
+ private final RocketSaver saver;
+
+ public SaveFileWorker(OpenRocketDocument document, File file, RocketSaver saver) {
+ this.document = document;
+ this.file = file;
+ this.saver = saver;
+ }
+
+
+ @Override
+ protected Void doInBackground() throws Exception {
+
+ int estimate = (int)saver.estimateFileSize(document,
+ document.getDefaultStorageOptions());
+
+ // Create the ProgressOutputStream that provides progress estimates
+ ProgressOutputStream os = new ProgressOutputStream(
+ new BufferedOutputStream(new FileOutputStream(file)),
+ estimate, this) {
+
+ @Override
+ protected void setProgress(int progress) {
+ SaveFileWorker.this.setProgress(progress);
+ }
+
+ };
+
+ try {
+ saver.save(os, document);
+ } finally {
+ try {
+ os.close();
+ } catch (Exception e) {
+ ExceptionHandler.handleErrorCondition("Error closing file", e);
+ }
+ }
+ return null;
+ }
+
+}
--- /dev/null
+package net.sf.openrocket.gui.util;
+
+import java.io.File;
+
+import javax.swing.filechooser.FileFilter;
+
+/**
+ * A FileFilter similar to FileNameExtensionFilter except that
+ * it allows multipart extensions (.ork.gz), and also implements
+ * the java.io.FileFilter interface.
+ *
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class SimpleFileFilter extends FileFilter implements java.io.FileFilter {
+
+ private final String description;
+ private final boolean acceptDir;
+ private final String[] extensions;
+
+
+ /**
+ * Create filter that accepts files with the provided extensions that
+ * accepts directories as well.
+ *
+ * @param description the description of this file filter.
+ * @param extensions an array of extensions that match this filter.
+ */
+ public SimpleFileFilter(String description, String ... extensions) {
+ this(description, true, extensions);
+ }
+
+
+ /**
+ * Create filter that accepts files with the provided extensions.
+ *
+ * @param description the description of this file filter.
+ * @param acceptDir whether to accept directories
+ * @param extensions an array of extensions that match this filter.
+ */
+ public SimpleFileFilter(String description, boolean acceptDir, String ... extensions) {
+ this.description = description;
+ this.acceptDir = acceptDir;
+ this.extensions = new String[extensions.length];
+ for (int i=0; i<extensions.length; i++) {
+ String ext = extensions[i].toLowerCase();
+ if (ext.charAt(0) == '.') {
+ this.extensions[i] = ext;
+ } else {
+ this.extensions[i] = '.' + ext;
+ }
+ }
+ }
+
+
+ @Override
+ public boolean accept(File file) {
+ if (file == null)
+ return false;
+ if (file.isDirectory())
+ return acceptDir;
+
+ String filename = file.getName();
+ filename = filename.toLowerCase();
+ for (String ext: extensions) {
+ if (filename.endsWith(ext))
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+}
import net.sf.openrocket.gui.main.BasicFrame;
import net.sf.openrocket.gui.main.ExceptionHandler;
import net.sf.openrocket.gui.main.Splash;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.SimpleFileFilter;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.ThrustCurveMotor;
-import net.sf.openrocket.util.GUIUtil;
import net.sf.openrocket.util.Prefs;
-import net.sf.openrocket.util.SimpleFileFilter;
/**
* The second class in the OpenRocket startup sequence. This class can assume the
+++ /dev/null
-package net.sf.openrocket.util;
-
-import java.awt.Component;
-
-import javax.swing.ProgressMonitor;
-import javax.swing.SwingUtilities;
-
-
-/**
- * A thread-safe <code>ProgressMonitor</code>. This class may be instantiated
- * and the method {@link #setProgress(int)} called safely from any thread.
- * <p>
- * Why the FSCK&!#&% isn't the default API version thread-safe?!?!
- *
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-public class ConcurrentProgressMonitor extends ProgressMonitor {
-
- public ConcurrentProgressMonitor(Component parentComponent, Object message,
- String note, int min, int max) {
- super(parentComponent, message, note, min, max);
- }
-
- @Override
- public void setProgress(final int nv) {
-
- if (SwingUtilities.isEventDispatchThread()) {
- super.setProgress(nv);
- } else {
-
- SwingUtilities.invokeLater(new Runnable() {
-
- @Override
- public void run() {
- ConcurrentProgressMonitor.super.setProgress(nv);
- }
-
- });
- }
- }
-
-
- @Override
- public void close() {
- if (SwingUtilities.isEventDispatchThread()) {
- super.close();
- } else {
-
- SwingUtilities.invokeLater(new Runnable() {
-
- @Override
- public void run() {
- ConcurrentProgressMonitor.super.close();
- }
-
- });
- }
- }
-
-
-}
+++ /dev/null
-package net.sf.openrocket.util;
-
-import java.awt.Component;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InterruptedIOException;
-
-
-/**
- * A functional equivalent of <code>ProgressMonitorInputStream</code> which
- * uses {@link ConcurrentProgressMonitor} and leaves the progress dialog open
- * to be manually closed later on.
- */
-
-public class ConcurrentProgressMonitorInputStream extends FilterInputStream {
- private ConcurrentProgressMonitor monitor;
- private int nread = 0;
- private int size = 0;
-
-
- /**
- * Constructs an object to monitor the progress of an input stream.
- *
- * @param message Descriptive text to be placed in the dialog box
- * if one is popped up.
- * @param parentComponent The component triggering the operation
- * being monitored.
- * @param in The input stream to be monitored.
- */
- public ConcurrentProgressMonitorInputStream(Component parentComponent,
- Object message, InputStream in) {
- super(in);
- try {
- size = in.available();
- } catch (IOException ioe) {
- size = 0;
- }
- monitor = new ConcurrentProgressMonitor(parentComponent, message, null, 0,
- size + 1);
- }
-
-
- /**
- * Get the ProgressMonitor object being used by this stream. Normally
- * this isn't needed unless you want to do something like change the
- * descriptive text partway through reading the file.
- * @return the ProgressMonitor object used by this object
- */
- public ConcurrentProgressMonitor getProgressMonitor() {
- return monitor;
- }
-
-
- /**
- * Overrides <code>FilterInputStream.read</code>
- * to update the progress monitor after the read.
- */
- @Override
- public int read() throws IOException {
- int c = in.read();
- if (c >= 0)
- monitor.setProgress(++nread);
- if (monitor.isCanceled()) {
- InterruptedIOException exc = new InterruptedIOException("progress");
- exc.bytesTransferred = nread;
- throw exc;
- }
- return c;
- }
-
-
- /**
- * Overrides <code>FilterInputStream.read</code>
- * to update the progress monitor after the read.
- */
- @Override
- public int read(byte b[]) throws IOException {
- int nr = in.read(b);
- if (nr > 0)
- monitor.setProgress(nread += nr);
- if (monitor.isCanceled()) {
- InterruptedIOException exc = new InterruptedIOException("progress");
- exc.bytesTransferred = nread;
- throw exc;
- }
- return nr;
- }
-
-
- /**
- * Overrides <code>FilterInputStream.read</code>
- * to update the progress monitor after the read.
- */
- @Override
- public int read(byte b[], int off, int len) throws IOException {
- int nr = in.read(b, off, len);
- if (nr > 0)
- monitor.setProgress(nread += nr);
- if (monitor.isCanceled()) {
- InterruptedIOException exc = new InterruptedIOException("progress");
- exc.bytesTransferred = nread;
- throw exc;
- }
- return nr;
- }
-
-
- /**
- * Overrides <code>FilterInputStream.skip</code>
- * to update the progress monitor after the skip.
- */
- @Override
- public long skip(long n) throws IOException {
- long nr = in.skip(n);
- if (nr > 0)
- monitor.setProgress(nread += nr);
- return nr;
- }
-
-
- /**
- * Overrides <code>FilterInputStream.close</code>
- * to close the progress monitor as well as the stream.
- */
- @Override
- public void close() throws IOException {
- in.close();
- monitor.close();
- }
-
-
- /**
- * Overrides <code>FilterInputStream.reset</code>
- * to reset the progress monitor as well as the stream.
- */
- @Override
- public synchronized void reset() throws IOException {
- in.reset();
- nread = size - in.available();
- monitor.setProgress(nread);
- }
-}
+++ /dev/null
-package net.sf.openrocket.util;
-
-import java.awt.Component;
-import java.io.File;
-import java.io.IOException;
-
-import javax.swing.JOptionPane;
-import javax.swing.filechooser.FileFilter;
-
-import net.sf.openrocket.l10n.L10N;
-import net.sf.openrocket.l10n.Translator;
-import net.sf.openrocket.logging.LogHelper;
-import net.sf.openrocket.startup.Application;
-
-/**
- * Helper methods related to user-initiated file manipulation.
- * <p>
- * These methods log the necessary information to the debug log.
-*
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-public final class FileHelper {
- private static final LogHelper log = Application.getLogger();
- private static final Translator trans = Application.getTranslator();
-
-
- // TODO: HIGH: Rename translation keys
-
- /** File filter for any rocket designs (*.ork, *.rkt) */
- public static final FileFilter ALL_DESIGNS_FILTER =
- new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter1"),
- ".ork", ".ork.gz", ".rkt", ".rkt.gz");
-
- /** File filter for OpenRocket designs (*.ork) */
- public static final FileFilter OPENROCKET_DESIGN_FILTER =
- new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter2"), ".ork", ".ork.gz");
-
- /** File filter for RockSim designs (*.rkt) */
- public static final FileFilter ROCKSIM_DESIGN_FILTER =
- new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter3"), ".rkt", ".rkt.gz");
-
- /** File filter for PDF files (*.pdf) */
- public static final FileFilter PDF_FILTER =
- new SimpleFileFilter(trans.get("filetypes.pdf"), ".pdf");
-
- /** File filter for CSV files (*.csv) */
- public static final FileFilter CSV_FILE_FILTER =
- new SimpleFileFilter(trans.get("SimExpPan.desc"), ".csv");
-
-
-
-
-
- private FileHelper() {
- // Prevent instantiation
- }
-
- /**
- * Ensure that the provided file has a file extension. If the file does not have
- * any extension, append the provided extension to it.
- *
- * @param original the original file
- * @param extension the extension to append if none exists (without preceding dot)
- * @return the resulting filen
- */
- public static File ensureExtension(File original, String extension) {
-
- if (original.getName().indexOf('.') < 0) {
- log.debug(1, "File name does not contain extension, adding '" + extension + "'");
- String name = original.getAbsolutePath();
- name = name + "." + extension;
- return new File(name);
- }
-
- return original;
- }
-
-
- /**
- * Confirm that it is allowed to write to a file. If the file exists,
- * a confirmation dialog will be presented to the user to ensure overwriting is ok.
- *
- * @param file the file that is going to be written.
- * @param parent the parent component for the dialog.
- * @return <code>true</code> to write, <code>false</code> to abort.
- */
- public static boolean confirmWrite(File file, Component parent) {
- if (file.exists()) {
- log.info(1, "File " + file + " exists, confirming overwrite from user");
- int result = JOptionPane.showConfirmDialog(parent,
- L10N.replace(trans.get("error.fileExists.desc"), "{filename}", file.getName()),
- trans.get("error.fileExists.title"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
- if (result != JOptionPane.YES_OPTION) {
- log.user(1, "User decided not to overwrite the file");
- return false;
- }
- log.user(1, "User decided to overwrite the file");
- }
- return true;
- }
-
-
- /**
- * Display an error message to the user that writing a file failed.
- *
- * @param e the I/O exception that caused the error.
- * @param parent the parent component for the dialog.
- */
- public static void errorWriting(IOException e, Component parent) {
-
- log.warn(1, "Error writing to file", e);
- JOptionPane.showMessageDialog(parent,
- new Object[] {
- trans.get("error.writing.desc"),
- e.getLocalizedMessage()
- }, trans.get("error.writing.title"), JOptionPane.ERROR_MESSAGE);
-
- }
-
-}
+++ /dev/null
-package net.sf.openrocket.util;
-
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.Image;
-import java.awt.KeyboardFocusManager;
-import java.awt.Point;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ComponentAdapter;
-import java.awt.event.ComponentEvent;
-import java.awt.event.ComponentListener;
-import java.awt.event.FocusListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.beans.PropertyChangeListener;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.imageio.ImageIO;
-import javax.swing.AbstractAction;
-import javax.swing.AbstractButton;
-import javax.swing.Action;
-import javax.swing.BoundedRangeModel;
-import javax.swing.ComboBoxModel;
-import javax.swing.DefaultBoundedRangeModel;
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.DefaultListSelectionModel;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JComponent;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JRootPane;
-import javax.swing.JSlider;
-import javax.swing.JSpinner;
-import javax.swing.JTable;
-import javax.swing.JTree;
-import javax.swing.KeyStroke;
-import javax.swing.ListSelectionModel;
-import javax.swing.LookAndFeel;
-import javax.swing.RootPaneContainer;
-import javax.swing.SpinnerModel;
-import javax.swing.SpinnerNumberModel;
-import javax.swing.SwingUtilities;
-import javax.swing.UIManager;
-import javax.swing.border.TitledBorder;
-import javax.swing.event.ChangeListener;
-import javax.swing.table.AbstractTableModel;
-import javax.swing.table.DefaultTableColumnModel;
-import javax.swing.table.DefaultTableModel;
-import javax.swing.table.TableColumnModel;
-import javax.swing.table.TableModel;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.DefaultTreeSelectionModel;
-import javax.swing.tree.TreeModel;
-import javax.swing.tree.TreeSelectionModel;
-
-import net.sf.openrocket.gui.Resettable;
-import net.sf.openrocket.logging.LogHelper;
-import net.sf.openrocket.startup.Application;
-
-public class GUIUtil {
- private static final LogHelper log = Application.getLogger();
-
- private static final KeyStroke ESCAPE = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
- private static final String CLOSE_ACTION_KEY = "escape:WINDOW_CLOSING";
-
- private static final List<Image> images = new ArrayList<Image>();
- static {
- loadImage("pix/icon/icon-256.png");
- loadImage("pix/icon/icon-064.png");
- loadImage("pix/icon/icon-048.png");
- loadImage("pix/icon/icon-032.png");
- loadImage("pix/icon/icon-016.png");
- }
-
- private static void loadImage(String file) {
- InputStream is;
-
- is = ClassLoader.getSystemResourceAsStream(file);
- if (is == null)
- return;
-
- try {
- Image image = ImageIO.read(is);
- images.add(image);
- } catch (IOException ignore) {
- ignore.printStackTrace();
- }
- }
-
-
-
- /**
- * Set suitable options for a single-use disposable dialog. This includes
- * setting ESC to close the dialog, adding the appropriate window icons and
- * setting the location based on the platform. If defaultButton is provided,
- * it is set to the default button action.
- * <p>
- * The default button must be already attached to the dialog.
- *
- * @param dialog the dialog.
- * @param defaultButton the default button of the dialog, or <code>null</code>.
- */
- public static void setDisposableDialogOptions(JDialog dialog, JButton defaultButton) {
- installEscapeCloseOperation(dialog);
- setWindowIcons(dialog);
- addModelNullingListener(dialog);
- dialog.setLocationByPlatform(true);
- dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- dialog.pack();
- if (defaultButton != null) {
- setDefaultButton(defaultButton);
- }
- }
-
-
-
- /**
- * Add the correct action to close a JDialog when the ESC key is pressed.
- * The dialog is closed by sending is a WINDOW_CLOSING event.
- *
- * @param dialog the dialog for which to install the action.
- */
- public static void installEscapeCloseOperation(final JDialog dialog) {
- Action dispatchClosing = new AbstractAction() {
- @Override
- public void actionPerformed(ActionEvent event) {
- log.user("Closing dialog " + dialog);
- dialog.dispatchEvent(new WindowEvent(dialog, WindowEvent.WINDOW_CLOSING));
- }
- };
- JRootPane root = dialog.getRootPane();
- root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ESCAPE, CLOSE_ACTION_KEY);
- root.getActionMap().put(CLOSE_ACTION_KEY, dispatchClosing);
- }
-
-
- /**
- * Set the given button as the default button of the frame/dialog it is in. The button
- * must be first attached to the window component hierarchy.
- *
- * @param button the button to set as the default button.
- */
- public static void setDefaultButton(JButton button) {
- Window w = SwingUtilities.windowForComponent(button);
- if (w == null) {
- throw new IllegalArgumentException("Attach button to a window first.");
- }
- if (!(w instanceof RootPaneContainer)) {
- throw new IllegalArgumentException("Button not attached to RootPaneContainer, w=" + w);
- }
- ((RootPaneContainer) w).getRootPane().setDefaultButton(button);
- }
-
-
-
- /**
- * Change the behavior of a component so that TAB and Shift-TAB cycles the focus of
- * the components. This is necessary for e.g. <code>JTextArea</code>.
- *
- * @param c the component to modify
- */
- public static void setTabToFocusing(Component c) {
- Set<KeyStroke> strokes = new HashSet<KeyStroke>(Arrays.asList(KeyStroke.getKeyStroke("pressed TAB")));
- c.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, strokes);
- strokes = new HashSet<KeyStroke>(Arrays.asList(KeyStroke.getKeyStroke("shift pressed TAB")));
- c.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, strokes);
- }
-
-
-
- /**
- * Set the OpenRocket icons to the window icons.
- *
- * @param window the window to set.
- */
- public static void setWindowIcons(Window window) {
- window.setIconImages(images);
- }
-
- /**
- * Add a listener to the provided window that will call {@link #setNullModels(Component)}
- * on the window once it is closed. This method may only be used on single-use
- * windows and dialogs, that will never be shown again once closed!
- *
- * @param window the window to add the listener to.
- */
- public static void addModelNullingListener(final Window window) {
- window.addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosed(WindowEvent e) {
- log.debug("Clearing all models of window " + window);
- setNullModels(window);
- MemoryManagement.collectable(window);
- }
- });
- }
-
-
-
- /**
- * Set the best available look-and-feel into use.
- */
- public static void setBestLAF() {
- /*
- * Set the look-and-feel. On Linux, Motif/Metal is sometimes incorrectly used
- * which is butt-ugly, so if the system l&f is Motif/Metal, we search for a few
- * other alternatives.
- */
- try {
- // Set system L&F
- UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
-
- // Check whether we have an ugly L&F
- LookAndFeel laf = UIManager.getLookAndFeel();
- if (laf == null ||
- laf.getName().matches(".*[mM][oO][tT][iI][fF].*") ||
- laf.getName().matches(".*[mM][eE][tT][aA][lL].*")) {
-
- // Search for better LAF
- UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
- String lafNames[] = {
- ".*[gG][tT][kK].*",
- ".*[wW][iI][nN].*",
- ".*[mM][aA][cC].*",
- ".*[aA][qQ][uU][aA].*",
- ".*[nN][iI][mM][bB].*"
- };
-
- lf: for (String lafName : lafNames) {
- for (UIManager.LookAndFeelInfo l : info) {
- if (l.getName().matches(lafName)) {
- UIManager.setLookAndFeel(l.getClassName());
- break lf;
- }
- }
- }
- }
- } catch (Exception e) {
- log.warn("Error setting LAF: " + e);
- }
- }
-
-
- /**
- * Changes the size of the font of the specified component by the given amount.
- *
- * @param component the component for which to change the font
- * @param size the change in the font size
- */
- public static void changeFontSize(JComponent component, float size) {
- Font font = component.getFont();
- font = font.deriveFont(font.getSize2D() + size);
- component.setFont(font);
- }
-
-
-
- /**
- * Automatically remember the size of a window. This stores the window size in the user
- * preferences when resizing/maximizing the window and sets the state on the first call.
- */
- public static void rememberWindowSize(final Window window) {
- window.addComponentListener(new ComponentAdapter() {
- @Override
- public void componentResized(ComponentEvent e) {
- log.debug("Storing size of " + window.getClass().getName() + ": " + window.getSize());
- Prefs.setWindowSize(window.getClass(), window.getSize());
- if (window instanceof JFrame) {
- if ((((JFrame) window).getExtendedState() & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH) {
- log.debug("Storing maximized state of " + window.getClass().getName());
- Prefs.setWindowMaximized(window.getClass());
- }
- }
- }
- });
-
- if (Prefs.isWindowMaximized(window.getClass())) {
- if (window instanceof JFrame) {
- ((JFrame) window).setExtendedState(JFrame.MAXIMIZED_BOTH);
- }
- } else {
- Dimension dim = Prefs.getWindowSize(window.getClass());
- if (dim != null) {
- window.setSize(dim);
- }
- }
- }
-
-
- /**
- * Automatically remember the position of a window. The position is stored in the user preferences
- * every time the window is moved and set from there when first calling this method.
- */
- public static void rememberWindowPosition(final Window window) {
- window.addComponentListener(new ComponentAdapter() {
- @Override
- public void componentMoved(ComponentEvent e) {
- Prefs.setWindowPosition(window.getClass(), window.getLocation());
- }
- });
-
- // Set window position according to preferences, and set prefs when moving
- Point position = Prefs.getWindowPosition(window.getClass());
- if (position != null) {
- window.setLocationByPlatform(false);
- window.setLocation(position);
- }
- }
-
-
- /**
- * Changes the style of the font of the specified border.
- *
- * @param border the component for which to change the font
- * @param style the change in the font style
- */
- public static void changeFontStyle(TitledBorder border, int style) {
- /*
- * The fix of JRE bug #4129681 causes a TitledBorder occasionally to
- * return a null font. We try to work around the issue by detecting it
- * and reverting to the font of a JLabel instead.
- */
- Font font = border.getTitleFont();
- if (font == null) {
- log.error("Border font is null, reverting to JLabel font");
- font = new JLabel().getFont();
- if (font == null) {
- log.error("JLabel font is null, not modifying font");
- return;
- }
- }
- font = font.deriveFont(style);
- if (font == null) {
- throw new BugException("Derived font is null");
- }
- border.setTitleFont(font);
- }
-
-
-
- /**
- * Traverses recursively the component tree, and sets all applicable component
- * models to null, so as to remove the listener connections. After calling this
- * method the component hierarchy should no longed be used.
- * <p>
- * All components that use custom models should be added to this method, as
- * there exists no standard way of removing the model from a component.
- *
- * @param c the component (<code>null</code> is ok)
- */
- public static void setNullModels(Component c) {
- if (c == null)
- return;
-
- // Remove various listeners
- for (ComponentListener l : c.getComponentListeners()) {
- c.removeComponentListener(l);
- }
- for (FocusListener l : c.getFocusListeners()) {
- c.removeFocusListener(l);
- }
- for (MouseListener l : c.getMouseListeners()) {
- c.removeMouseListener(l);
- }
- for (PropertyChangeListener l : c.getPropertyChangeListeners()) {
- c.removePropertyChangeListener(l);
- }
- for (PropertyChangeListener l : c.getPropertyChangeListeners("model")) {
- c.removePropertyChangeListener("model", l);
- }
- for (PropertyChangeListener l : c.getPropertyChangeListeners("action")) {
- c.removePropertyChangeListener("action", l);
- }
-
- // Remove models for known components
- // Why the FSCK must this be so hard?!?!?
-
- if (c instanceof JSpinner) {
-
- JSpinner spinner = (JSpinner) c;
- for (ChangeListener l : spinner.getChangeListeners()) {
- spinner.removeChangeListener(l);
- }
- SpinnerModel model = spinner.getModel();
- spinner.setModel(new SpinnerNumberModel());
- if (model instanceof Invalidatable) {
- ((Invalidatable) model).invalidate();
- }
-
- } else if (c instanceof JSlider) {
-
- JSlider slider = (JSlider) c;
- for (ChangeListener l : slider.getChangeListeners()) {
- slider.removeChangeListener(l);
- }
- BoundedRangeModel model = slider.getModel();
- slider.setModel(new DefaultBoundedRangeModel());
- if (model instanceof Invalidatable) {
- ((Invalidatable) model).invalidate();
- }
-
- } else if (c instanceof JComboBox) {
-
- JComboBox combo = (JComboBox) c;
- for (ActionListener l : combo.getActionListeners()) {
- combo.removeActionListener(l);
- }
- ComboBoxModel model = combo.getModel();
- combo.setModel(new DefaultComboBoxModel());
- if (model instanceof Invalidatable) {
- ((Invalidatable) model).invalidate();
- }
-
- } else if (c instanceof AbstractButton) {
-
- AbstractButton button = (AbstractButton) c;
- for (ActionListener l : button.getActionListeners()) {
- button.removeActionListener(l);
- }
- Action model = button.getAction();
- button.setAction(new AbstractAction() {
- @Override
- public void actionPerformed(ActionEvent e) {
- }
- });
- if (model instanceof Invalidatable) {
- ((Invalidatable) model).invalidate();
- }
-
- } else if (c instanceof JTable) {
-
- JTable table = (JTable) c;
- TableModel model1 = table.getModel();
- table.setModel(new DefaultTableModel());
- if (model1 instanceof Invalidatable) {
- ((Invalidatable) model1).invalidate();
- }
-
- TableColumnModel model2 = table.getColumnModel();
- table.setColumnModel(new DefaultTableColumnModel());
- if (model2 instanceof Invalidatable) {
- ((Invalidatable) model2).invalidate();
- }
-
- ListSelectionModel model3 = table.getSelectionModel();
- table.setSelectionModel(new DefaultListSelectionModel());
- if (model3 instanceof Invalidatable) {
- ((Invalidatable) model3).invalidate();
- }
-
- } else if (c instanceof JTree) {
-
- JTree tree = (JTree) c;
- TreeModel model1 = tree.getModel();
- tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
- if (model1 instanceof Invalidatable) {
- ((Invalidatable) model1).invalidate();
- }
-
- TreeSelectionModel model2 = tree.getSelectionModel();
- tree.setSelectionModel(new DefaultTreeSelectionModel());
- if (model2 instanceof Invalidatable) {
- ((Invalidatable) model2).invalidate();
- }
-
- } else if (c instanceof Resettable) {
-
- ((Resettable) c).resetModel();
-
- }
-
- // Recurse the component
- if (c instanceof Container) {
- Component[] cs = ((Container) c).getComponents();
- for (Component sub : cs)
- setNullModels(sub);
- }
-
- }
-
-
-
- /**
- * A mouse listener that toggles the state of a boolean value in a table model
- * when clicked on another column of the table.
- * <p>
- * NOTE: If the table model does not extend AbstractTableModel, the model must
- * fire a change event (which in normal table usage is not necessary).
- *
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
- public static class BooleanTableClickListener extends MouseAdapter {
-
- private final JTable table;
- private final int clickColumn;
- private final int booleanColumn;
-
-
- public BooleanTableClickListener(JTable table) {
- this(table, 1, 0);
- }
-
-
- public BooleanTableClickListener(JTable table, int clickColumn, int booleanColumn) {
- this.table = table;
- this.clickColumn = clickColumn;
- this.booleanColumn = booleanColumn;
- }
-
- @Override
- public void mouseClicked(MouseEvent e) {
- if (e.getButton() != MouseEvent.BUTTON1)
- return;
-
- Point p = e.getPoint();
- int col = table.columnAtPoint(p);
- if (col < 0)
- return;
- col = table.convertColumnIndexToModel(col);
- if (col != clickColumn)
- return;
-
- int row = table.rowAtPoint(p);
- if (row < 0)
- return;
- row = table.convertRowIndexToModel(row);
- if (row < 0)
- return;
-
- TableModel model = table.getModel();
- Object value = model.getValueAt(row, booleanColumn);
-
- if (!(value instanceof Boolean)) {
- throw new IllegalStateException("Table value at row=" + row + " col=" +
- booleanColumn + " is not a Boolean, value=" + value);
- }
-
- Boolean b = (Boolean) value;
- b = !b;
- model.setValueAt(b, row, booleanColumn);
- if (model instanceof AbstractTableModel) {
- ((AbstractTableModel) model).fireTableCellUpdated(row, booleanColumn);
- }
- }
-
- }
-
-}
+++ /dev/null
-package net.sf.openrocket.util;
-
-import java.net.URL;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-
-import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.gui.main.ExceptionHandler;
-import net.sf.openrocket.l10n.Translator;
-import net.sf.openrocket.logging.LogHelper;
-import net.sf.openrocket.startup.Application;
-
-
-public class Icons {
- private static final LogHelper log = Application.getLogger();
- private static final Translator trans = Application.getTranslator();
-
- static {
- log.debug("Starting to load icons");
- }
-
- /**
- * Icons used for showing the status of a simulation (up to date, out of date, etc).
- */
- public static final Map<Simulation.Status, Icon> SIMULATION_STATUS_ICON_MAP;
- static {
- HashMap<Simulation.Status, Icon> map = new HashMap<Simulation.Status, Icon>();
- map.put(Simulation.Status.NOT_SIMULATED, loadImageIcon("pix/spheres/gray-16x16.png", "Not simulated"));
- map.put(Simulation.Status.UPTODATE, loadImageIcon("pix/spheres/green-16x16.png", "Up to date"));
- map.put(Simulation.Status.LOADED, loadImageIcon("pix/spheres/yellow-16x16.png", "Loaded from file"));
- map.put(Simulation.Status.OUTDATED, loadImageIcon("pix/spheres/red-16x16.png", "Out-of-date"));
- map.put(Simulation.Status.EXTERNAL, loadImageIcon("pix/spheres/blue-16x16.png", "Imported data"));
- SIMULATION_STATUS_ICON_MAP = Collections.unmodifiableMap(map);
- }
-
- public static final Icon SIMULATION_LISTENER_OK;
- public static final Icon SIMULATION_LISTENER_ERROR;
- static {
- SIMULATION_LISTENER_OK = SIMULATION_STATUS_ICON_MAP.get(Simulation.Status.UPTODATE);
- SIMULATION_LISTENER_ERROR = SIMULATION_STATUS_ICON_MAP.get(Simulation.Status.OUTDATED);
- }
-
-
- public static final Icon FILE_NEW = loadImageIcon("pix/icons/document-new.png", "New document");
- public static final Icon FILE_OPEN = loadImageIcon("pix/icons/document-open.png", "Open document");
- public static final Icon FILE_OPEN_EXAMPLE = loadImageIcon("pix/icons/document-open-example.png", "Open example document");
- public static final Icon FILE_SAVE = loadImageIcon("pix/icons/document-save.png", "Save document");
- public static final Icon FILE_SAVE_AS = loadImageIcon("pix/icons/document-save-as.png", "Save document as");
- public static final Icon FILE_PRINT = loadImageIcon("pix/icons/document-print.png", "Print document");
- public static final Icon FILE_CLOSE = loadImageIcon("pix/icons/document-close.png", "Close document");
- public static final Icon FILE_QUIT = loadImageIcon("pix/icons/application-exit.png", "Quit OpenRocket");
-
- public static final Icon EDIT_UNDO = loadImageIcon("pix/icons/edit-undo.png", trans.get("Icons.Undo"));
- public static final Icon EDIT_REDO = loadImageIcon("pix/icons/edit-redo.png", trans.get("Icons.Redo"));
- public static final Icon EDIT_CUT = loadImageIcon("pix/icons/edit-cut.png", "Cut");
- public static final Icon EDIT_COPY = loadImageIcon("pix/icons/edit-copy.png", "Copy");
- public static final Icon EDIT_PASTE = loadImageIcon("pix/icons/edit-paste.png", "Paste");
- public static final Icon EDIT_DELETE = loadImageIcon("pix/icons/edit-delete.png", "Delete");
- public static final Icon EDIT_SCALE = loadImageIcon("pix/icons/edit-scale.png", "Scale");
-
- public static final Icon HELP_ABOUT = loadImageIcon("pix/icons/help-about.png", "About");
- public static final Icon HELP_BUG_REPORT = loadImageIcon("pix/icons/help-bug.png", "Bug report");
- public static final Icon HELP_DEBUG_LOG = loadImageIcon("pix/icons/help-log.png", "Debug log");
- public static final Icon HELP_LICENSE = loadImageIcon("pix/icons/help-license.png", "License");
-
- public static final Icon ZOOM_IN = loadImageIcon("pix/icons/zoom-in.png", "Zoom in");
- public static final Icon ZOOM_OUT = loadImageIcon("pix/icons/zoom-out.png", "Zoom out");
-
- public static final Icon PREFERENCES = loadImageIcon("pix/icons/preferences.png", "Preferences");
-
- public static final Icon DELETE = loadImageIcon("pix/icons/delete.png", "Delete");
-
- static {
- log.debug("Icons loaded");
- }
-
- /**
- * Load an ImageIcon from the specified file. The file is obtained as a system
- * resource from the normal classpath. If the file cannot be loaded a bug dialog
- * is opened and <code>null</code> is returned.
- *
- * @param file the file to load.
- * @param name the description of the icon.
- * @return the ImageIcon, or null if could not be loaded (after the user closes the dialog)
- */
- public static ImageIcon loadImageIcon(String file, String name) {
- if (System.getProperty("openrocket.unittest") != null) {
- return new ImageIcon();
- }
-
- URL url = ClassLoader.getSystemResource(file);
- if (url == null) {
- ExceptionHandler.handleErrorCondition("Image file " + file + " not found, ignoring.");
- return null;
- }
- return new ImageIcon(url, name);
- }
-}
+++ /dev/null
-package net.sf.openrocket.util;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InterruptedIOException;
-
-import javax.swing.SwingWorker;
-
-import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.file.RocketLoader;
-import net.sf.openrocket.gui.main.ExceptionHandler;
-import net.sf.openrocket.logging.LogHelper;
-import net.sf.openrocket.startup.Application;
-
-
-/**
- * A SwingWorker thread that opens a rocket design file.
- *
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-public class OpenFileWorker extends SwingWorker<OpenRocketDocument, Void> {
- private static final LogHelper log = Application.getLogger();
-
- private final File file;
- private final InputStream stream;
- private final RocketLoader loader;
-
- public OpenFileWorker(File file, RocketLoader loader) {
- this.file = file;
- this.stream = null;
- this.loader = loader;
- }
-
-
- public OpenFileWorker(InputStream stream, RocketLoader loader) {
- this.stream = stream;
- this.file = null;
- this.loader = loader;
- }
-
- public RocketLoader getRocketLoader() {
- return loader;
- }
-
- @Override
- protected OpenRocketDocument doInBackground() throws Exception {
- InputStream is;
-
- // Get the correct input stream
- if (file != null) {
- is = new FileInputStream(file);
- } else {
- is = stream;
- }
-
- // Buffer stream unless already buffered
- if (!(is instanceof BufferedInputStream)) {
- is = new BufferedInputStream(is);
- }
-
- // Encapsulate in a ProgressInputStream
- is = new ProgressInputStream(is);
-
- try {
- return loader.load(is);
- } finally {
- try {
- is.close();
- } catch (Exception e) {
- ExceptionHandler.handleErrorCondition("Error closing file", e);
- }
- }
- }
-
-
-
-
- private class ProgressInputStream extends FilterInputStream {
-
- private final int size;
- private int readBytes = 0;
- private int progress = -1;
-
- protected ProgressInputStream(InputStream in) {
- super(in);
- int s;
- try {
- s = in.available();
- } catch (IOException e) {
- log.info("Exception while estimating available bytes!", e);
- s = 0;
- }
- size = Math.max(s, 1);
- }
-
-
-
- @Override
- public int read() throws IOException {
- int c = in.read();
- if (c >= 0) {
- readBytes++;
- setProgress();
- }
- if (isCancelled()) {
- throw new InterruptedIOException("OpenFileWorker was cancelled");
- }
- return c;
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- int n = in.read(b, off, len);
- if (n > 0) {
- readBytes += n;
- setProgress();
- }
- if (isCancelled()) {
- throw new InterruptedIOException("OpenFileWorker was cancelled");
- }
- return n;
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- int n = in.read(b);
- if (n > 0) {
- readBytes += n;
- setProgress();
- }
- if (isCancelled()) {
- throw new InterruptedIOException("OpenFileWorker was cancelled");
- }
- return n;
- }
-
- @Override
- public long skip(long n) throws IOException {
- long nr = in.skip(n);
- if (nr > 0) {
- readBytes += nr;
- setProgress();
- }
- if (isCancelled()) {
- throw new InterruptedIOException("OpenFileWorker was cancelled");
- }
- return nr;
- }
-
- @Override
- public synchronized void reset() throws IOException {
- in.reset();
- readBytes = size - in.available();
- setProgress();
- if (isCancelled()) {
- throw new InterruptedIOException("OpenFileWorker was cancelled");
- }
- }
-
-
-
- private void setProgress() {
- int p = MathUtil.clamp(readBytes * 100 / size, 0, 100);
- if (progress != p) {
- progress = p;
- OpenFileWorker.this.setProgress(progress);
- }
- }
- }
-}
+++ /dev/null
-package net.sf.openrocket.util;
-
-import java.awt.Window;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.concurrent.ExecutionException;
-
-import javax.swing.JOptionPane;
-import javax.swing.SwingWorker;
-
-import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.file.CSVExport;
-import net.sf.openrocket.gui.dialogs.SwingWorkerDialog;
-import net.sf.openrocket.gui.main.ExceptionHandler;
-import net.sf.openrocket.simulation.FlightDataBranch;
-import net.sf.openrocket.simulation.FlightDataType;
-import net.sf.openrocket.unit.Unit;
-
-
-public class SaveCSVWorker extends SwingWorker<Void, Void> {
-
- private static final int BYTES_PER_FIELD_PER_POINT = 7;
-
- private final File file;
- private final Simulation simulation;
- private final FlightDataBranch branch;
- private final FlightDataType[] fields;
- private final Unit[] units;
- private final String fieldSeparator;
- private final String commentStarter;
- private final boolean simulationComments;
- private final boolean fieldComments;
- private final boolean eventComments;
-
-
- public SaveCSVWorker(File file, Simulation simulation, FlightDataBranch branch,
- FlightDataType[] fields, Unit[] units, String fieldSeparator, String commentStarter,
- boolean simulationComments, boolean fieldComments, boolean eventComments) {
- this.file = file;
- this.simulation = simulation;
- this.branch = branch;
- this.fields = fields;
- this.units = units;
- this.fieldSeparator = fieldSeparator;
- this.commentStarter = commentStarter;
- this.simulationComments = simulationComments;
- this.fieldComments = fieldComments;
- this.eventComments = eventComments;
- }
-
-
- @Override
- protected Void doInBackground() throws Exception {
-
- int estimate = BYTES_PER_FIELD_PER_POINT * fields.length * branch.getLength();
- estimate = Math.max(estimate, 1000);
-
- // Create the ProgressOutputStream that provides progress estimates
- ProgressOutputStream os = new ProgressOutputStream(
- new BufferedOutputStream(new FileOutputStream(file)),
- estimate, this) {
-
- @Override
- protected void setProgress(int progress) {
- SaveCSVWorker.this.setProgress(progress);
- }
-
- };
-
- try {
- CSVExport.exportCSV(os, simulation, branch, fields, units, fieldSeparator,
- commentStarter, simulationComments, fieldComments, eventComments);
- } finally {
- try {
- os.close();
- } catch (Exception e) {
- ExceptionHandler.handleErrorCondition("Error closing file", e);
- }
- }
- return null;
- }
-
-
-
- /**
- * Exports a CSV file using a progress dialog if necessary.
- *
- * @return <code>true</code> if the save was successful, <code>false</code> otherwise.
- */
- public static boolean export(File file, Simulation simulation, FlightDataBranch branch,
- FlightDataType[] fields, Unit[] units, String fieldSeparator, String commentStarter,
- boolean simulationComments, boolean fieldComments, boolean eventComments,
- Window parent) {
-
-
- SaveCSVWorker worker = new SaveCSVWorker(file, simulation, branch, fields, units,
- fieldSeparator, commentStarter, simulationComments, fieldComments,
- eventComments);
-
- if (!SwingWorkerDialog.runWorker(parent, "Exporting flight data",
- "Writing " + file.getName() + "...", worker)) {
-
- // User cancelled the save
- file.delete();
- return false;
- }
-
- try {
- worker.get();
- } catch (ExecutionException e) {
- Throwable cause = e.getCause();
-
- if (cause instanceof IOException) {
- JOptionPane.showMessageDialog(parent, new String[] {
- "An I/O error occurred while saving:",
- e.getMessage() }, "Saving failed", JOptionPane.ERROR_MESSAGE);
- return false;
- } else {
- throw new BugException("Unknown error when saving file", e);
- }
-
- } catch (InterruptedException e) {
- throw new BugException("EDT was interrupted", e);
- }
-
- return true;
- }
-}
+++ /dev/null
-package net.sf.openrocket.util;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-
-import javax.swing.SwingWorker;
-
-import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.file.RocketSaver;
-import net.sf.openrocket.gui.main.ExceptionHandler;
-
-public class SaveFileWorker extends SwingWorker<Void, Void> {
-
- private final OpenRocketDocument document;
- private final File file;
- private final RocketSaver saver;
-
- public SaveFileWorker(OpenRocketDocument document, File file, RocketSaver saver) {
- this.document = document;
- this.file = file;
- this.saver = saver;
- }
-
-
- @Override
- protected Void doInBackground() throws Exception {
-
- int estimate = (int)saver.estimateFileSize(document,
- document.getDefaultStorageOptions());
-
- // Create the ProgressOutputStream that provides progress estimates
- ProgressOutputStream os = new ProgressOutputStream(
- new BufferedOutputStream(new FileOutputStream(file)),
- estimate, this) {
-
- @Override
- protected void setProgress(int progress) {
- SaveFileWorker.this.setProgress(progress);
- }
-
- };
-
- try {
- saver.save(os, document);
- } finally {
- try {
- os.close();
- } catch (Exception e) {
- ExceptionHandler.handleErrorCondition("Error closing file", e);
- }
- }
- return null;
- }
-
-}
+++ /dev/null
-package net.sf.openrocket.util;
-
-import java.io.File;
-
-import javax.swing.filechooser.FileFilter;
-
-/**
- * A FileFilter similar to FileNameExtensionFilter except that
- * it allows multipart extensions (.ork.gz), and also implements
- * the java.io.FileFilter interface.
- *
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-public class SimpleFileFilter extends FileFilter implements java.io.FileFilter {
-
- private final String description;
- private final boolean acceptDir;
- private final String[] extensions;
-
-
- /**
- * Create filter that accepts files with the provided extensions that
- * accepts directories as well.
- *
- * @param description the description of this file filter.
- * @param extensions an array of extensions that match this filter.
- */
- public SimpleFileFilter(String description, String ... extensions) {
- this(description, true, extensions);
- }
-
-
- /**
- * Create filter that accepts files with the provided extensions.
- *
- * @param description the description of this file filter.
- * @param acceptDir whether to accept directories
- * @param extensions an array of extensions that match this filter.
- */
- public SimpleFileFilter(String description, boolean acceptDir, String ... extensions) {
- this.description = description;
- this.acceptDir = acceptDir;
- this.extensions = new String[extensions.length];
- for (int i=0; i<extensions.length; i++) {
- String ext = extensions[i].toLowerCase();
- if (ext.charAt(0) == '.') {
- this.extensions[i] = ext;
- } else {
- this.extensions[i] = '.' + ext;
- }
- }
- }
-
-
- @Override
- public boolean accept(File file) {
- if (file == null)
- return false;
- if (file.isDirectory())
- return acceptDir;
-
- String filename = file.getName();
- filename = filename.toLowerCase();
- for (String ext: extensions) {
- if (filename.endsWith(ext))
- return true;
- }
-
- return false;
- }
-
- @Override
- public String getDescription() {
- return description;
- }
-
-}
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.file.motor.GeneralMotorLoader;
+import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.ThrustCurveMotor;
import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.GUIUtil;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;