From 84af78ccf403b216724163f7cbc1bfa03bec7ca5 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Tue, 10 Sep 2013 21:46:38 -0500 Subject: [PATCH 01/17] Extract the MotorRowFilter out of the ThrustCurveMotorSelectionPanel to facilitate adding more filters. --- .../motor/thrustcurve/MotorRowFilter.java | 83 +++++++++++++++++ .../ThrustCurveMotorSelectionPanel.java | 92 +++---------------- 2 files changed, 94 insertions(+), 81 deletions(-) create mode 100644 core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java diff --git a/core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java b/core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java new file mode 100644 index 000000000..142571e04 --- /dev/null +++ b/core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java @@ -0,0 +1,83 @@ +package net.sf.openrocket.gui.dialogs.motor.thrustcurve; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import javax.swing.RowFilter; +import javax.swing.table.TableModel; + +import net.sf.openrocket.database.motor.ThrustCurveMotorSet; + +//////// Row filters + +/** + * Abstract adapter class. + */ +class MotorRowFilter extends RowFilter { + + public enum DiameterFilterControl { + ALL, + EXACT, + SMALLER + }; + + private final ThrustCurveMotorDatabaseModel model; + private final double diameter; + + private List searchTerms = Collections. emptyList(); + private DiameterFilterControl diameterControl = DiameterFilterControl.ALL; + + public MotorRowFilter(ThrustCurveMotorDatabaseModel model, double diameter) { + super(); + this.model = model; + this.diameter = diameter; + } + + public void setSearchTerms(final List searchTerms) { + this.searchTerms = new ArrayList(); + for (String s : searchTerms) { + s = s.trim().toLowerCase(Locale.getDefault()); + if (s.length() > 0) { + this.searchTerms.add(s); + } + } + } + + void setDiameterControl(DiameterFilterControl diameterControl) { + this.diameterControl = diameterControl; + } + + @Override + public boolean include(RowFilter.Entry entry) { + int index = entry.getIdentifier(); + ThrustCurveMotorSet m = model.getMotorSet(index); + return filterByDiameter(m) && filterByString(m); + } + + public boolean filterByDiameter(ThrustCurveMotorSet m) { + switch (diameterControl) { + default: + case ALL: + return true; + case EXACT: + return ((m.getDiameter() <= diameter + 0.0004) && (m.getDiameter() >= diameter - 0.0015)); + case SMALLER: + return (m.getDiameter() <= diameter + 0.0004); + } + } + + + public boolean filterByString(ThrustCurveMotorSet m) { + main: for (String s : searchTerms) { + for (ThrustCurveMotorColumns col : ThrustCurveMotorColumns.values()) { + String str = col.getValue(m).toString().toLowerCase(Locale.getDefault()); + if (str.indexOf(s) >= 0) + continue main; + } + return false; + } + return true; + } +} diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java index e9781b210..3456fa65b 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java @@ -34,7 +34,6 @@ import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.ListCellRenderer; import javax.swing.ListSelectionModel; -import javax.swing.RowFilter; import javax.swing.RowSorter; import javax.swing.SortOrder; import javax.swing.SwingUtilities; @@ -109,18 +108,17 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec private final List database; - private final double diameter; private CloseableDialog dialog = null; - private final ThrustCurveMotorDatabaseModel model; + final ThrustCurveMotorDatabaseModel model; private final JTable table; private final TableRowSorter sorter; private final JCheckBox hideSimilarBox; private final JTextField searchField; - private String[] searchTerms = new String[0]; + String[] searchTerms = new String[0]; private final JLabel curveSelectionLabel; @@ -162,7 +160,6 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec public ThrustCurveMotorSelectionPanel(ThrustCurveMotor current, double delay, double diameter) { super(new MigLayout("fill", "[grow][]")); - this.diameter = diameter; // Construct the database (adding the current motor if not in the db already) @@ -189,6 +186,8 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec } database = db; + model = new ThrustCurveMotorDatabaseModel(database); + final MotorRowFilter rowFilter = new MotorRowFilter(model, diameter); //// GUI @@ -217,20 +216,21 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec sel = SHOW_ALL; switch (sel) { case SHOW_ALL: - sorter.setRowFilter(new MotorRowFilterAll()); + rowFilter.setDiameterControl(MotorRowFilter.DiameterFilterControl.ALL); break; case SHOW_SMALLER: - sorter.setRowFilter(new MotorRowFilterSmaller()); + rowFilter.setDiameterControl(MotorRowFilter.DiameterFilterControl.SMALLER); break; case SHOW_EXACT: - sorter.setRowFilter(new MotorRowFilterExact()); + rowFilter.setDiameterControl(MotorRowFilter.DiameterFilterControl.EXACT); break; default: throw new BugException("Invalid selection mode sel=" + sel); } + sorter.sort(); Application.getPreferences().putChoice("MotorDiameterMatch", sel); scrollSelectionVisible(); } @@ -252,7 +252,6 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec // Motor selection table - model = new ThrustCurveMotorDatabaseModel(database); table = new JTable(model); @@ -275,6 +274,8 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec sorter.setSortKeys(Arrays.asList(sortKeys)); } + sorter.setRowFilter(rowFilter); + // Set selection and double-click listeners table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override @@ -344,14 +345,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec private void update() { String text = searchField.getText().trim(); String[] split = text.split("\\s+"); - ArrayList list = new ArrayList(); - for (String s : split) { - s = s.trim().toLowerCase(Locale.getDefault()); - if (s.length() > 0) { - list.add(s); - } - } - searchTerms = list.toArray(new String[0]); + rowFilter.setSearchTerms( Arrays.asList(split) ); sorter.sort(); scrollSelectionVisible(); } @@ -386,10 +380,6 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec }); panel.add(curveSelectionBox, "growx, wrap para"); - - - - // Ejection charge delay: panel.add(new JLabel(trans.get("TCMotorSelPan.lbl.Ejectionchargedelay"))); @@ -936,66 +926,6 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec } - //////// Row filters - - /** - * Abstract adapter class. - */ - private abstract class MotorRowFilter extends RowFilter { - @Override - public boolean include(RowFilter.Entry entry) { - int index = entry.getIdentifier(); - ThrustCurveMotorSet m = model.getMotorSet(index); - return filterByDiameter(m) && filterByString(m); - } - - public abstract boolean filterByDiameter(ThrustCurveMotorSet m); - - - public boolean filterByString(ThrustCurveMotorSet m) { - main: for (String s : searchTerms) { - for (ThrustCurveMotorColumns col : ThrustCurveMotorColumns.values()) { - String str = col.getValue(m).toString().toLowerCase(Locale.getDefault()); - if (str.indexOf(s) >= 0) - continue main; - } - return false; - } - return true; - } - } - - /** - * Show all motors. - */ - private class MotorRowFilterAll extends MotorRowFilter { - @Override - public boolean filterByDiameter(ThrustCurveMotorSet m) { - return true; - } - } - - /** - * Show motors smaller than the mount. - */ - private class MotorRowFilterSmaller extends MotorRowFilter { - @Override - public boolean filterByDiameter(ThrustCurveMotorSet m) { - return (m.getDiameter() <= diameter + 0.0004); - } - } - - /** - * Show motors that fit the mount. - */ - private class MotorRowFilterExact extends MotorRowFilter { - @Override - public boolean filterByDiameter(ThrustCurveMotorSet m) { - return ((m.getDiameter() <= diameter + 0.0004) && (m.getDiameter() >= diameter - 0.0015)); - } - } - - /** * Custom layered pane that sets the bounds of the components on every layout. */ From 64015d72bef565704426e6c7cb668dfdb8418923 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Wed, 11 Sep 2013 13:27:08 -0500 Subject: [PATCH 02/17] Refactor the api so the motor mount goes into the ThrustCurveMotorSelectionPanel. This allows greater flexibility in filter functionality. --- .../gui/configdialog/MotorConfig.java | 3 +-- .../MotorConfigurationPanel.java | 6 +---- .../gui/dialogs/motor/MotorChooserDialog.java | 6 ++--- .../ThrustCurveMotorSelectionPanel.java | 23 +++++++++++-------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/configdialog/MotorConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/MotorConfig.java index 03882cce5..564ba3954 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/MotorConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/MotorConfig.java @@ -184,8 +184,7 @@ public class MotorConfig extends JPanel { public void actionPerformed(ActionEvent e) { String id = configuration.getFlightConfigurationID(); - MotorChooserDialog dialog = new MotorChooserDialog(mount.getMotor(id), - mount.getMotorDelay(id), mount.getMotorMountDiameter(), + MotorChooserDialog dialog = new MotorChooserDialog(mount, id, SwingUtilities.getWindowAncestor(MotorConfig.this)); dialog.setVisible(true); Motor m = dialog.getSelectedMotor(); diff --git a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationPanel.java index 811169dd0..1cb7178f6 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationPanel.java @@ -207,11 +207,7 @@ public class MotorConfigurationPanel extends JPanel { MotorConfiguration config = mount.getMotorConfiguration().get(id); - MotorChooserDialog dialog = new MotorChooserDialog( - config.getMotor(), - config.getEjectionDelay(), - mount.getMotorMountDiameter(), - flightConfigurationDialog); + MotorChooserDialog dialog = new MotorChooserDialog(mount, id, flightConfigurationDialog); dialog.setVisible(true); Motor m = dialog.getSelectedMotor(); double d = dialog.getSelectedDelay(); diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java index 761d4dab6..898964af0 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java @@ -16,7 +16,7 @@ import net.sf.openrocket.gui.dialogs.motor.thrustcurve.ThrustCurveMotorSelection 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.rocketcomponent.MotorMount; import net.sf.openrocket.startup.Application; public class MotorChooserDialog extends JDialog implements CloseableDialog { @@ -27,13 +27,13 @@ public class MotorChooserDialog extends JDialog implements CloseableDialog { private static final Translator trans = Application.getTranslator(); - public MotorChooserDialog(Motor current, double delay, double diameter, Window owner) { + public MotorChooserDialog(MotorMount mount, String currentConfig, Window owner) { super(owner, trans.get("MotorChooserDialog.title"), Dialog.ModalityType.APPLICATION_MODAL); JPanel panel = new JPanel(new MigLayout("fill")); - selectionPanel = new ThrustCurveMotorSelectionPanel((ThrustCurveMotor) current, delay, diameter); + selectionPanel = new ThrustCurveMotorSelectionPanel(mount, currentConfig); panel.add(selectionPanel, "grow, wrap para"); diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java index 3456fa65b..731a5f5ba 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java @@ -15,7 +15,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Locale; import java.util.prefs.Preferences; import javax.swing.BorderFactory; @@ -57,6 +56,8 @@ import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.logging.Markers; import net.sf.openrocket.motor.Motor; import net.sf.openrocket.motor.ThrustCurveMotor; +import net.sf.openrocket.rocketcomponent.MotorConfiguration; +import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.startup.Application; import net.sf.openrocket.unit.UnitGroup; import net.sf.openrocket.util.BugException; @@ -157,20 +158,25 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec * @param delay the currently selected ejection charge delay. * @param diameter the diameter of the motor mount. */ - public ThrustCurveMotorSelectionPanel(ThrustCurveMotor current, double delay, double diameter) { + public ThrustCurveMotorSelectionPanel(MotorMount mount, String currentConfig) { super(new MigLayout("fill", "[grow][]")); - + double diameter = 0; + if (currentConfig != null && mount != null) { + MotorConfiguration motorConf = mount.getMotorConfiguration().get(currentConfig); + selectedMotor = (ThrustCurveMotor) motorConf.getMotor(); + selectedDelay = motorConf.getEjectionDelay(); + diameter = mount.getMotorMountDiameter(); + } // Construct the database (adding the current motor if not in the db already) List db; db = Application.getThrustCurveMotorSetDatabase().getMotorSets(); // If current motor is not found in db, add a new ThrustCurveMotorSet containing it - if (current != null) { - selectedMotor = current; + if (selectedMotor != null) { for (ThrustCurveMotorSet motorSet : db) { - if (motorSet.getMotors().contains(current)) { + if (motorSet.getMotors().contains(selectedMotor)) { selectedMotorSet = motorSet; break; } @@ -178,7 +184,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec if (selectedMotorSet == null) { db = new ArrayList(db); ThrustCurveMotorSet extra = new ThrustCurveMotorSet(); - extra.addMotor(current); + extra.addMotor(selectedMotor); selectedMotorSet = extra; db.add(extra); Collections.sort(db); @@ -345,7 +351,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec private void update() { String text = searchField.getText().trim(); String[] split = text.split("\\s+"); - rowFilter.setSearchTerms( Arrays.asList(split) ); + rowFilter.setSearchTerms(Arrays.asList(split)); sorter.sort(); scrollSelectionVisible(); } @@ -555,7 +561,6 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec // Update the panel data updateData(); - selectedDelay = delay; setDelays(false); } From ea6aa3e414af36d2f1c1ed57094d18dbeb86ac2d Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Thu, 12 Sep 2013 15:10:31 -0500 Subject: [PATCH 03/17] Added manufacturer selection boxes and exclude motors currently used filters. --- .../ManufacturerPopupSelector.java | 96 ++++++++ .../motor/thrustcurve/MotorRowFilter.java | 60 ++++- .../net/sf/openrocket/gui/util/CheckList.java | 177 ++++++++++++++ .../openrocket/gui/util/CheckListEditor.java | 86 +++++++ .../gui/util/CheckListRenderer.java | 228 ++++++++++++++++++ .../gui/util/DefaultCheckListModel.java | 124 ++++++++++ .../rocketcomponent/FlightConfiguration.java | 2 +- .../FlightConfigurationImpl.java | 5 + .../ThrustCurveMotorSelectionPanel.java | 77 +++++- .../openrocket/gui/util/SwingPreferences.java | 64 +++-- 10 files changed, 892 insertions(+), 27 deletions(-) create mode 100644 core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java create mode 100644 core/src/net/sf/openrocket/gui/util/CheckList.java create mode 100644 core/src/net/sf/openrocket/gui/util/CheckListEditor.java create mode 100644 core/src/net/sf/openrocket/gui/util/CheckListRenderer.java create mode 100644 core/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java diff --git a/core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java b/core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java new file mode 100644 index 000000000..447f864e2 --- /dev/null +++ b/core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java @@ -0,0 +1,96 @@ +package net.sf.openrocket.gui.dialogs.motor.thrustcurve; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.UIManager; + +import net.sf.openrocket.gui.util.CheckList; +import net.sf.openrocket.motor.Manufacturer; + +public abstract class ManufacturerPopupSelector extends JPopupMenu implements ActionListener { + + Map componentMap = new HashMap(); + CheckList list; + + public ManufacturerPopupSelector(Collection allManufacturers, Collection unselectedManufacturers) { + + JPanel root = new JPanel(new BorderLayout(3, 3)); + root.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); + root.setPreferredSize(new Dimension(250, 150)); // default popup size + + Box commands = new Box(BoxLayout.LINE_AXIS); + + commands.add(Box.createHorizontalStrut(5)); + commands.setBorder(BorderFactory.createEmptyBorder(3, 0, 3, 0)); + commands.setBackground(UIManager.getColor("Panel.background")); + commands.setOpaque(true); + + JButton closeButton = new JButton("close"); + closeButton.addActionListener(this); + commands.add(closeButton); + + List manufacturers = new ArrayList(); + for (Manufacturer m : allManufacturers) { + manufacturers.add(m.getSimpleName()); + componentMap.put(m.getSimpleName(), m); + } + + Collections.sort(manufacturers); + + list = new CheckList.Builder().build(); + list.setData(manufacturers); + + if (unselectedManufacturers != null) + { + for (Manufacturer m : unselectedManufacturers) { + manufacturers.remove(m.getSimpleName()); + } + } + list.setCheckedItems(manufacturers); + + root.add(new JScrollPane(list.getList()), BorderLayout.CENTER); + root.add(commands, BorderLayout.SOUTH); + + this.add(root); + + } + + @Override + public void actionPerformed(ActionEvent e) { + + List selectedManufacturers = new ArrayList(); + List unselectedManufacturers = new ArrayList(); + + Collection selected = list.getCheckedItems(); + for (String s : selected) { + selectedManufacturers.add(componentMap.get(s)); + } + + Collection unselected = list.getUncheckedItems(); + for (String s : unselected) { + unselectedManufacturers.add(componentMap.get(s)); + } + + onDismissed(selectedManufacturers, unselectedManufacturers); + setVisible(false); + } + + public abstract void onDismissed(List selectedManufacturers, List unselectedManufacturers); + +} diff --git a/core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java b/core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java index 142571e04..1713c36ef 100644 --- a/core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java +++ b/core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java @@ -9,6 +9,10 @@ import javax.swing.RowFilter; import javax.swing.table.TableModel; import net.sf.openrocket.database.motor.ThrustCurveMotorSet; +import net.sf.openrocket.motor.Manufacturer; +import net.sf.openrocket.motor.ThrustCurveMotor; +import net.sf.openrocket.rocketcomponent.MotorConfiguration; +import net.sf.openrocket.rocketcomponent.MotorMount; //////// Row filters @@ -23,16 +27,28 @@ class MotorRowFilter extends RowFilter { SMALLER }; + // configuration data used in the filter process private final ThrustCurveMotorDatabaseModel model; - private final double diameter; + private final Double diameter; + private List usedMotors = new ArrayList(); + // things which can be changed to modify filter behavior private List searchTerms = Collections. emptyList(); private DiameterFilterControl diameterControl = DiameterFilterControl.ALL; + private boolean hideUsedMotors = false; + private List excludedManufacturers = new ArrayList(); - public MotorRowFilter(ThrustCurveMotorDatabaseModel model, double diameter) { + public MotorRowFilter(MotorMount mount, ThrustCurveMotorDatabaseModel model) { super(); this.model = model; - this.diameter = diameter; + if (mount != null) { + this.diameter = mount.getMotorMountDiameter(); + for (MotorConfiguration m : mount.getMotorConfiguration()) { + this.usedMotors.add((ThrustCurveMotor) m.getMotor()); + } + } else { + this.diameter = null; + } } public void setSearchTerms(final List searchTerms) { @@ -49,14 +65,46 @@ class MotorRowFilter extends RowFilter { this.diameterControl = diameterControl; } + void setHideUsedMotors(boolean hideUsedMotors) { + this.hideUsedMotors = hideUsedMotors; + } + + void setExcludedManufacturers(List excludedManufacturers) { + this.excludedManufacturers.clear(); + this.excludedManufacturers.addAll(excludedManufacturers); + } + @Override public boolean include(RowFilter.Entry entry) { int index = entry.getIdentifier(); ThrustCurveMotorSet m = model.getMotorSet(index); - return filterByDiameter(m) && filterByString(m); + return filterManufacturers(m) && filterUsed(m) && filterByDiameter(m) && filterByString(m); } - public boolean filterByDiameter(ThrustCurveMotorSet m) { + private boolean filterManufacturers(ThrustCurveMotorSet m) { + if (excludedManufacturers.contains(m.getManufacturer())) { + return false; + } else { + return true; + } + } + + private boolean filterUsed(ThrustCurveMotorSet m) { + if (!hideUsedMotors) { + return true; + } + for (ThrustCurveMotor motor : usedMotors) { + if (m.matches(motor)) { + return false; + } + } + return true; + } + + private boolean filterByDiameter(ThrustCurveMotorSet m) { + if (diameter == null) { + return true; + } switch (diameterControl) { default: case ALL: @@ -69,7 +117,7 @@ class MotorRowFilter extends RowFilter { } - public boolean filterByString(ThrustCurveMotorSet m) { + private boolean filterByString(ThrustCurveMotorSet m) { main: for (String s : searchTerms) { for (ThrustCurveMotorColumns col : ThrustCurveMotorColumns.values()) { String str = col.getValue(m).toString().toLowerCase(Locale.getDefault()); diff --git a/core/src/net/sf/openrocket/gui/util/CheckList.java b/core/src/net/sf/openrocket/gui/util/CheckList.java new file mode 100644 index 000000000..6eb233092 --- /dev/null +++ b/core/src/net/sf/openrocket/gui/util/CheckList.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2009-2011, EzWare + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer.Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution.Neither the name of the + * EzWare nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.sf.openrocket.gui.util; + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseListener; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.JList; +import javax.swing.KeyStroke; +import javax.swing.ListSelectionModel; + +/** + * The decorator for JList which makes it work like check list + * UI can be designed using JList and which can be later decorated to become a check list + * @author Eugene Ryzhikov + * + * @param list item type + */ +public class CheckList { + + private final JList list; + private static final MouseAdapter checkBoxEditor = new CheckListEditor(); + + public static class Builder { + + private JList list; + + public Builder(JList list) { + this.list = list == null ? new JList() : list; + } + + public Builder() { + this(null); + } + + public CheckList build() { + return new CheckList(list); + } + + } + + + /** + * Wraps the standard JList and makes it work like check list + * @param list + */ + private CheckList(final JList list) { + + if (list == null) + throw new NullPointerException(); + this.list = list; + this.list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + if (!isEditorAttached()) + list.addMouseListener(checkBoxEditor); + this.list.setCellRenderer(new CheckListRenderer()); + + setupKeyboardActions(list); + + } + + @SuppressWarnings("serial") + private void setupKeyboardActions(final JList list) { + String actionKey = "toggle-check"; + list.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), actionKey); + list.getActionMap().put(actionKey, new AbstractAction() { + + @Override + public void actionPerformed(ActionEvent e) { + toggleIndex(list.getSelectedIndex()); + } + }); + } + + private boolean isEditorAttached() { + + for (MouseListener ml : list.getMouseListeners()) { + if (ml instanceof CheckListEditor) + return true; + } + return false; + + } + + public JList getList() { + return list; + } + + /** + * Sets data to a check list. Simplification for setting new the model + * @param data + */ + public void setData(Collection data) { + setModel(new DefaultCheckListModel(data)); + } + + /** + * Sets the model for check list. + * @param model + */ + public void setModel(DefaultCheckListModel model) { + list.setModel(model); + } + + @SuppressWarnings("unchecked") + public DefaultCheckListModel getModel() { + return (DefaultCheckListModel) list.getModel(); + } + + /** + * Returns a collection of checked items. + * @return collection of checked items. Empty collection if nothing is selected + */ + public Collection getCheckedItems() { + return getModel().getCheckedItems(); + } + + public Collection getUncheckedItems() { + List unchecked = new ArrayList(); + for (int i = getModel().getSize() - 1; i >= 0; i--) { + unchecked.add((T) getModel().getElementAt(i)); + } + unchecked.removeAll(getCheckedItems()); + return unchecked; + } + + /** + * Resets checked elements + * @param elements + */ + public void setCheckedItems(Collection elements) { + getModel().setCheckedItems(elements); + } + + public void toggleIndex(int index) { + if (index >= 0 && index < list.getModel().getSize()) { + DefaultCheckListModel model = getModel(); + model.setCheckedIndex(index, !model.isCheckedIndex(index)); + } + } + +} diff --git a/core/src/net/sf/openrocket/gui/util/CheckListEditor.java b/core/src/net/sf/openrocket/gui/util/CheckListEditor.java new file mode 100644 index 000000000..0dafdc111 --- /dev/null +++ b/core/src/net/sf/openrocket/gui/util/CheckListEditor.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2009-2011, EzWare + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer.Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution.Neither the name of the + * EzWare nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.sf.openrocket.gui.util; + +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Arrays; + +import javax.swing.JList; +import javax.swing.SwingUtilities; + + +/** + * Determines mouse click and + * 1. Toggles the check on selected item if clicked once + * 2. Clears checks and checks selected item if clicked more then once + * + * Created on Feb 4, 2011 + * @author Eugene Ryzhikov + * + */ +final class CheckListEditor extends MouseAdapter { + @Override + public void mouseClicked(MouseEvent e) { + + if (!SwingUtilities.isLeftMouseButton(e)) + return; + + JList list = (JList) e.getSource(); + if (!list.isEnabled() || (!(list.getModel() instanceof DefaultCheckListModel))) + return; + + int index = list.locationToIndex(e.getPoint()); + if (index < 0) + return; + + Rectangle bounds = list.getCellBounds(index, index); + + if (bounds.contains(e.getPoint())) { + + @SuppressWarnings("unchecked") + DefaultCheckListModel model = (DefaultCheckListModel) list.getModel(); + + if (e.getClickCount() > 1) { + // clear all and check selected for more then 1 clicks + model.setCheckedItems(Arrays.asList(model.getElementAt(index))); + } else { + // simple toggle for 1 click + model.setCheckedIndex(index, !model.isCheckedIndex(index)); + } + e.consume(); + } + + } + +} diff --git a/core/src/net/sf/openrocket/gui/util/CheckListRenderer.java b/core/src/net/sf/openrocket/gui/util/CheckListRenderer.java new file mode 100644 index 000000000..e0777c4f9 --- /dev/null +++ b/core/src/net/sf/openrocket/gui/util/CheckListRenderer.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2009-2011, EzWare + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer.Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution.Neither the name of the + * EzWare nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.sf.openrocket.gui.util; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Rectangle; +import java.io.Serializable; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.Icon; +import javax.swing.JCheckBox; +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; + +public class CheckListRenderer extends JCheckBox implements ListCellRenderer, Serializable { + + private static final long serialVersionUID = 1L; + + private static final Border NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1); + private static final Border SAFE_NO_FOCUS_BORDER = NO_FOCUS_BORDER; // may change in the feature + + /** + * Constructs a default renderer object for an item in a list. + */ + public CheckListRenderer() { + super(); + setOpaque(true); + setBorder(getNoFocusBorder()); + } + + private static Border getNoFocusBorder() { + if (System.getSecurityManager() != null) { + return SAFE_NO_FOCUS_BORDER; + } else { + return NO_FOCUS_BORDER; + } + } + + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, + boolean cellHasFocus) { + + setComponentOrientation(list.getComponentOrientation()); + + Color bg = null; + Color fg = null; + + JList.DropLocation dropLocation = list.getDropLocation(); + if (dropLocation != null && !dropLocation.isInsert() && dropLocation.getIndex() == index) { + + bg = UIManager.getColor("List.dropCellBackground"); + fg = UIManager.getColor("List.dropCellForeground"); + + isSelected = true; + } + + if (isSelected) { + setBackground(bg == null ? list.getSelectionBackground() : bg); + setForeground(fg == null ? list.getSelectionForeground() : fg); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + if (value instanceof Icon) { + setIcon((Icon) value); + setText(""); + } else { + setIcon(null); + setText(getObjectAsText(value)); + } + + setSelected(isChecked(list, index)); + + setEnabled(list.isEnabled()); + setFont(list.getFont()); + + Border border = null; + if (cellHasFocus) { + if (isSelected) { + border = UIManager.getBorder("List.focusSelectedCellHighlightBorder"); + } + if (border == null) { + border = UIManager.getBorder("List.focusCellHighlightBorder"); + } + } else { + border = getNoFocusBorder(); + } + setBorder(border); + + return this; + } + + protected String getObjectAsText(Object obj) { + return (obj == null) ? "" : obj.toString(); + } + + private boolean isChecked(JList list, int index) { + + if (list.getModel() instanceof DefaultCheckListModel) { + return ((DefaultCheckListModel) list.getModel()).isCheckedIndex(index); + } else { + return false; + } + + } + + /** + * @return true if the background is opaque and differs from the JList's background; false otherwise + */ + @Override + public boolean isOpaque() { + Color back = getBackground(); + Component p = getParent(); + if (p != null) { + p = p.getParent(); + } + // p should now be the JList. + boolean colorMatch = (back != null) && (p != null) && back.equals(p.getBackground()) && p.isOpaque(); + return !colorMatch && super.isOpaque(); + } + + @Override + protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + + if ("text".equals(propertyName) || + (("font".equals(propertyName) || "foreground".equals(propertyName)) && + oldValue != newValue && getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey) != null)) { + + super.firePropertyChange(propertyName, oldValue, newValue); + } + } + + // Methods below are overridden for performance reasons. + + @Override + public void validate() { + } + + @Override + public void invalidate() { + } + + @Override + public void repaint() { + } + + @Override + public void revalidate() { + } + + @Override + public void repaint(long tm, int x, int y, int width, int height) { + } + + @Override + public void repaint(Rectangle r) { + } + + @Override + public void firePropertyChange(String propertyName, byte oldValue, byte newValue) { + } + + @Override + public void firePropertyChange(String propertyName, char oldValue, char newValue) { + } + + @Override + public void firePropertyChange(String propertyName, short oldValue, short newValue) { + } + + @Override + public void firePropertyChange(String propertyName, int oldValue, int newValue) { + } + + @Override + public void firePropertyChange(String propertyName, long oldValue, long newValue) { + } + + @Override + public void firePropertyChange(String propertyName, float oldValue, float newValue) { + } + + @Override + public void firePropertyChange(String propertyName, double oldValue, double newValue) { + } + + @Override + public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { + } + + @SuppressWarnings("serial") + public static class UIResource extends DefaultListCellRenderer implements javax.swing.plaf.UIResource { + } + +} \ No newline at end of file diff --git a/core/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java b/core/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java new file mode 100644 index 000000000..647019400 --- /dev/null +++ b/core/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2009-2011, EzWare + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer.Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution.Neither the name of the + * EzWare nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.sf.openrocket.gui.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.swing.AbstractListModel; + +/** + * Default model for check list. It is based on the list of items + * Implementation of checks is based on HashSet of checked items + * + * @author Eugene Ryzhikov + * + * @param list element type + */ +public class DefaultCheckListModel extends AbstractListModel { + + private static final long serialVersionUID = 1L; + + private final List data = new ArrayList(); + private final Set checks = new HashSet(); + + public DefaultCheckListModel(Collection data) { + + if (data == null) + return; + for (T object : data) { + this.data.add(object); + checks.clear(); + } + } + + public DefaultCheckListModel(T... data) { + this(Arrays.asList(data)); + } + + /* (non-Javadoc) + * @see org.oxbow.swingbits.list.ICheckListModel#getSize() + */ + @Override + public int getSize() { + return data().size(); + } + + private List data() { + return data; + } + + + @Override + public Object getElementAt(int index) { + return data().get(index); + } + + public boolean isCheckedIndex(int index) { + return checks.contains(data().get(index)); + } + + public void setCheckedIndex(int index, boolean value) { + T o = data().get(index); + if (value) + checks.add(o); + else + checks.remove(o); + fireContentsChanged(this, index, index); + } + + public Collection getCheckedItems() { + List items = new ArrayList(checks); + items.retainAll(data); + return Collections.unmodifiableList(items); + } + + public void setCheckedItems(Collection items) { + + // if ( CollectionUtils.isEmpty(items)) return; + + List correctedItems = new ArrayList(items); + correctedItems.retainAll(data); + + checks.clear(); + checks.addAll(correctedItems); + fireContentsChanged(this, 0, checks.size() - 1); + + + } + +} diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java index d99c81b9e..054f50cf3 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java @@ -11,7 +11,7 @@ import net.sf.openrocket.util.ChangeSource; * * @param the parameter type */ -public interface FlightConfiguration extends FlightConfigurableComponent { +public interface FlightConfiguration extends FlightConfigurableComponent, Iterable { /** * Return the default parameter value for this FlightConfiguration. diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfigurationImpl.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfigurationImpl.java index f69fa6b22..91fa99d60 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfigurationImpl.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfigurationImpl.java @@ -2,6 +2,7 @@ package net.sf.openrocket.rocketcomponent; import java.util.EventObject; import java.util.HashMap; +import java.util.Iterator; import net.sf.openrocket.util.StateChangeListener; import net.sf.openrocket.util.Utils; @@ -79,6 +80,10 @@ class FlightConfigurationImpl> implemen fireEvent(); } + @Override + public Iterator iterator() { + return map.values().iterator(); + } @Override diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java index 731a5f5ba..bdd644588 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java @@ -11,14 +11,18 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.prefs.Preferences; import javax.swing.BorderFactory; import javax.swing.DefaultComboBoxModel; +import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; @@ -54,6 +58,7 @@ import net.sf.openrocket.gui.util.Icons; import net.sf.openrocket.gui.util.SwingPreferences; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.logging.Markers; +import net.sf.openrocket.motor.Manufacturer; import net.sf.openrocket.motor.Motor; import net.sf.openrocket.motor.ThrustCurveMotor; import net.sf.openrocket.rocketcomponent.MotorConfiguration; @@ -105,13 +110,10 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec private static final ThrustCurveMotorComparator MOTOR_COMPARATOR = new ThrustCurveMotorComparator(); - - private final List database; private CloseableDialog dialog = null; - final ThrustCurveMotorDatabaseModel model; private final JTable table; private final TableRowSorter sorter; @@ -192,9 +194,11 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec } database = db; - model = new ThrustCurveMotorDatabaseModel(database); - final MotorRowFilter rowFilter = new MotorRowFilter(model, diameter); + List unselectedManusFromPreferences = ((SwingPreferences) Application.getPreferences()).getExcludedMotorManufacturers(); + model = new ThrustCurveMotorDatabaseModel(database); + final MotorRowFilter rowFilter = new MotorRowFilter(mount, model); + rowFilter.setExcludedManufacturers(unselectedManusFromPreferences); //// GUI @@ -256,6 +260,69 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec }); panel.add(hideSimilarBox, "gapleft para, spanx, growx, wrap para"); + { + final JCheckBox hideUsedBox = new JCheckBox("Hide motors already used in the mount"); + GUIUtil.changeFontSize(hideUsedBox, -1); + hideUsedBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + rowFilter.setHideUsedMotors(hideUsedBox.isSelected()); + sorter.sort(); + scrollSelectionVisible(); + } + }); + panel.add(hideUsedBox, "gapleft para, spanx, growx, wrap para"); + } + + { + + // Find all the manufacturers: + Set manus = new HashSet(); + for (ThrustCurveMotorSet s : database) { + manus.add(s.getManufacturer()); + } + final ManufacturerPopupSelector popup = new ManufacturerPopupSelector(manus, unselectedManusFromPreferences) { + + @Override + public void onDismissed(List selectedManufacturers, List unselectedManufacturers) { + ((SwingPreferences) Application.getPreferences()).setExcludedMotorManufacturers(unselectedManufacturers); + rowFilter.setExcludedManufacturers(unselectedManufacturers); + sorter.sort(); + scrollSelectionVisible(); + System.out.println("Here I am"); + } + + }; + + JButton manuFilter = new JButton("Manufacturer Filter"); + manuFilter.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) { + } + + @Override + public void mousePressed(MouseEvent e) { + } + + @Override + public void mouseReleased(MouseEvent e) { + popup.show(e.getComponent(), e.getX(), e.getY()); + } + + @Override + public void mouseEntered(MouseEvent e) { + } + + @Override + public void mouseExited(MouseEvent e) { + } + + }); + panel.add(manuFilter, "gapleft para, spanx, growx, wrap para"); + + + } // Motor selection table table = new JTable(model); diff --git a/swing/src/net/sf/openrocket/gui/util/SwingPreferences.java b/swing/src/net/sf/openrocket/gui/util/SwingPreferences.java index d752c260a..9bdb5f2e9 100644 --- a/swing/src/net/sf/openrocket/gui/util/SwingPreferences.java +++ b/swing/src/net/sf/openrocket/gui/util/SwingPreferences.java @@ -6,6 +6,7 @@ import java.awt.Point; import java.io.File; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -14,12 +15,10 @@ import java.util.Set; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import net.sf.openrocket.arch.SystemInfo; import net.sf.openrocket.document.Simulation; import net.sf.openrocket.material.Material; +import net.sf.openrocket.motor.Manufacturer; import net.sf.openrocket.preset.ComponentPreset; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.simulation.FlightDataType; @@ -30,6 +29,9 @@ import net.sf.openrocket.unit.UnitGroup; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.BuildProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class SwingPreferences extends net.sf.openrocket.startup.Preferences { private static final Logger log = LoggerFactory.getLogger(SwingPreferences.class); @@ -575,9 +577,9 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences { return materials; } - + //// Preset Component Favorites - + @Override public void setComponentFavorite(ComponentPreset preset, ComponentPreset.Type type, boolean favorite) { Preferences prefs = PREFNODE.node("favoritePresets").node(type.name()); @@ -599,35 +601,67 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences { } return collection; } - + //// Decal Editor Setting private final static String DECAL_EDITOR_PREFERNCE_NODE = "decalEditorPreference"; private final static String DECAL_EDITOR_USE_SYSTEM_DEFAULT = ""; - public void clearDecalEditorPreference( ) { - putString(DECAL_EDITOR_PREFERNCE_NODE,null); + public void clearDecalEditorPreference() { + putString(DECAL_EDITOR_PREFERNCE_NODE, null); } + public void setDecalEditorPreference(boolean useSystem, String commandLine) { - if ( useSystem ) { - putString(DECAL_EDITOR_PREFERNCE_NODE,DECAL_EDITOR_USE_SYSTEM_DEFAULT); - } else if ( commandLine != null ) { + if (useSystem) { + putString(DECAL_EDITOR_PREFERNCE_NODE, DECAL_EDITOR_USE_SYSTEM_DEFAULT); + } else if (commandLine != null) { putString(DECAL_EDITOR_PREFERNCE_NODE, commandLine); } else { clearDecalEditorPreference(); } } - + public boolean isDecalEditorPreferenceSet() { - String s = getString(DECAL_EDITOR_PREFERNCE_NODE,null); + String s = getString(DECAL_EDITOR_PREFERNCE_NODE, null); return s != null; } public boolean isDecalEditorPreferenceSystem() { - String s = getString(DECAL_EDITOR_PREFERNCE_NODE,null); + String s = getString(DECAL_EDITOR_PREFERNCE_NODE, null); return DECAL_EDITOR_USE_SYSTEM_DEFAULT.equals(s); } + public String getDecalEditorCommandLine() { - return getString(DECAL_EDITOR_PREFERNCE_NODE,null); + return getString(DECAL_EDITOR_PREFERNCE_NODE, null); } + public List getExcludedMotorManufacturers() { + Preferences prefs = PREFNODE.node("excludedMotorManufacturers"); + List collection = new ArrayList(); + try { + String[] manuShortNames = prefs.keys(); + for (String s : manuShortNames) { + Manufacturer m = Manufacturer.getManufacturer(s); + if (m != null) { + collection.add(m); + } + } + } catch (BackingStoreException e) { + } + + return collection; + + } + + public void setExcludedMotorManufacturers(Collection manus) { + Preferences prefs = PREFNODE.node("excludedMotorManufacturers"); + try { + for (String s : prefs.keys()) { + prefs.remove(s); + } + } catch (BackingStoreException e) { + } + for (Manufacturer m : manus) { + prefs.putBoolean(m.getSimpleName(), true); + } + } } From 246b9a6823ded2e71edbc4acd7dd367877747059 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Fri, 27 Sep 2013 21:54:05 -0500 Subject: [PATCH 04/17] Relocate the swing files into the swing/ project. They were misplaced with the rebase. --- .../gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java | 0 .../openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java | 0 {core => swing}/src/net/sf/openrocket/gui/util/CheckList.java | 0 .../src/net/sf/openrocket/gui/util/CheckListEditor.java | 0 .../src/net/sf/openrocket/gui/util/CheckListRenderer.java | 0 .../src/net/sf/openrocket/gui/util/DefaultCheckListModel.java | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename {core => swing}/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java (100%) rename {core => swing}/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java (100%) rename {core => swing}/src/net/sf/openrocket/gui/util/CheckList.java (100%) rename {core => swing}/src/net/sf/openrocket/gui/util/CheckListEditor.java (100%) rename {core => swing}/src/net/sf/openrocket/gui/util/CheckListRenderer.java (100%) rename {core => swing}/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java (100%) diff --git a/core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java similarity index 100% rename from core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java rename to swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java diff --git a/core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java similarity index 100% rename from core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java rename to swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java diff --git a/core/src/net/sf/openrocket/gui/util/CheckList.java b/swing/src/net/sf/openrocket/gui/util/CheckList.java similarity index 100% rename from core/src/net/sf/openrocket/gui/util/CheckList.java rename to swing/src/net/sf/openrocket/gui/util/CheckList.java diff --git a/core/src/net/sf/openrocket/gui/util/CheckListEditor.java b/swing/src/net/sf/openrocket/gui/util/CheckListEditor.java similarity index 100% rename from core/src/net/sf/openrocket/gui/util/CheckListEditor.java rename to swing/src/net/sf/openrocket/gui/util/CheckListEditor.java diff --git a/core/src/net/sf/openrocket/gui/util/CheckListRenderer.java b/swing/src/net/sf/openrocket/gui/util/CheckListRenderer.java similarity index 100% rename from core/src/net/sf/openrocket/gui/util/CheckListRenderer.java rename to swing/src/net/sf/openrocket/gui/util/CheckListRenderer.java diff --git a/core/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java b/swing/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java similarity index 100% rename from core/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java rename to swing/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java From bae9d38a5172e95e0141fd00b0bdb59c4b34d494 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Sat, 28 Sep 2013 22:01:14 -0500 Subject: [PATCH 05/17] Further refinements to motor filter. Moved diameter configuration into popup. Added impulse class filters. Improved interface to CheckList and removed the double-click functionality from CheckListEditor. --- .../motor/thrustcurve/ImpulseClass.java | 45 ++++ .../ManufacturerPopupSelector.java | 96 ------- .../thrustcurve/MotorFilterPopupMenu.java | 251 ++++++++++++++++++ .../motor/thrustcurve/MotorRowFilter.java | 39 ++- .../ThrustCurveMotorSelectionPanel.java | 183 ++++--------- .../net/sf/openrocket/gui/util/CheckList.java | 12 + .../openrocket/gui/util/CheckListEditor.java | 3 +- .../gui/util/DefaultCheckListModel.java | 20 ++ 8 files changed, 426 insertions(+), 223 deletions(-) create mode 100644 swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ImpulseClass.java delete mode 100644 swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java create mode 100644 swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPopupMenu.java diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ImpulseClass.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ImpulseClass.java new file mode 100644 index 000000000..6b8fc6a9f --- /dev/null +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ImpulseClass.java @@ -0,0 +1,45 @@ +package net.sf.openrocket.gui.dialogs.motor.thrustcurve; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +import net.sf.openrocket.database.motor.ThrustCurveMotorSet; + +public enum ImpulseClass { + + A("A",0.0, 2.5 ), + B("B",2.5, 5.0 ), + C("C",5.0, 10.0), + D("D",10.0, 20.0), + E("E",20.0, 40.0), + F("F", 40.0, 80.0), + G("G", 80.0, 160.0), + H("H", 160.0, 320.0), + I("I", 320.0, 640.0), + J("J", 640.0, 1280.0), + K("K", 1280.0, 2560.0), + L("L", 2560.0, 5120.0), + M("M", 5120.0, 10240.0), + N("N", 10240.0, 20480.0), + O("O", 20480.0, Double.MAX_VALUE); + + private ImpulseClass( String name, double low, double high ) { + this.name = name; + this.low = low; + this.high = high; + } + + public String toString() { + return name; + } + + public boolean isIn( ThrustCurveMotorSet m ) { + long motorImpulse = m.getTotalImpuse(); + return motorImpulse >= low && motorImpulse <= high; + } + + private double low; + private double high; + private String name; + +} diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java deleted file mode 100644 index 447f864e2..000000000 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ManufacturerPopupSelector.java +++ /dev/null @@ -1,96 +0,0 @@ -package net.sf.openrocket.gui.dialogs.motor.thrustcurve; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.UIManager; - -import net.sf.openrocket.gui.util.CheckList; -import net.sf.openrocket.motor.Manufacturer; - -public abstract class ManufacturerPopupSelector extends JPopupMenu implements ActionListener { - - Map componentMap = new HashMap(); - CheckList list; - - public ManufacturerPopupSelector(Collection allManufacturers, Collection unselectedManufacturers) { - - JPanel root = new JPanel(new BorderLayout(3, 3)); - root.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); - root.setPreferredSize(new Dimension(250, 150)); // default popup size - - Box commands = new Box(BoxLayout.LINE_AXIS); - - commands.add(Box.createHorizontalStrut(5)); - commands.setBorder(BorderFactory.createEmptyBorder(3, 0, 3, 0)); - commands.setBackground(UIManager.getColor("Panel.background")); - commands.setOpaque(true); - - JButton closeButton = new JButton("close"); - closeButton.addActionListener(this); - commands.add(closeButton); - - List manufacturers = new ArrayList(); - for (Manufacturer m : allManufacturers) { - manufacturers.add(m.getSimpleName()); - componentMap.put(m.getSimpleName(), m); - } - - Collections.sort(manufacturers); - - list = new CheckList.Builder().build(); - list.setData(manufacturers); - - if (unselectedManufacturers != null) - { - for (Manufacturer m : unselectedManufacturers) { - manufacturers.remove(m.getSimpleName()); - } - } - list.setCheckedItems(manufacturers); - - root.add(new JScrollPane(list.getList()), BorderLayout.CENTER); - root.add(commands, BorderLayout.SOUTH); - - this.add(root); - - } - - @Override - public void actionPerformed(ActionEvent e) { - - List selectedManufacturers = new ArrayList(); - List unselectedManufacturers = new ArrayList(); - - Collection selected = list.getCheckedItems(); - for (String s : selected) { - selectedManufacturers.add(componentMap.get(s)); - } - - Collection unselected = list.getUncheckedItems(); - for (String s : unselected) { - unselectedManufacturers.add(componentMap.get(s)); - } - - onDismissed(selectedManufacturers, unselectedManufacturers); - setVisible(false); - } - - public abstract void onDismissed(List selectedManufacturers, List unselectedManufacturers); - -} diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPopupMenu.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPopupMenu.java new file mode 100644 index 000000000..e49733413 --- /dev/null +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPopupMenu.java @@ -0,0 +1,251 @@ +package net.sf.openrocket.gui.dialogs.motor.thrustcurve; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.border.TitledBorder; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.gui.util.CheckList; +import net.sf.openrocket.gui.util.GUIUtil; +import net.sf.openrocket.gui.util.SwingPreferences; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.motor.Manufacturer; +import net.sf.openrocket.startup.Application; + +import com.itextpdf.text.Font; + +public abstract class MotorFilterPopupMenu extends JPopupMenu { + + private static final Translator trans = Application.getTranslator(); + + private final CheckList manufacturerCheckList; + + private final CheckList impulseCheckList; + + private final MotorRowFilter filter; + + private int showMode = SHOW_ALL; + + private static final int SHOW_ALL = 0; + private static final int SHOW_SMALLER = 1; + private static final int SHOW_EXACT = 2; + private static final int SHOW_MAX = 2; + + + public MotorFilterPopupMenu(Collection allManufacturers, MotorRowFilter filter ) { + + this.filter = filter; + + showMode = Application.getPreferences().getChoice(net.sf.openrocket.startup.Preferences.MOTOR_DIAMETER_FILTER, MotorFilterPopupMenu.SHOW_MAX, MotorFilterPopupMenu.SHOW_EXACT); + List unselectedManusFromPreferences = ((SwingPreferences) Application.getPreferences()).getExcludedMotorManufacturers(); + + // Manufacturer selection + JPanel sub = new JPanel(new MigLayout("fill")); + TitledBorder border = BorderFactory.createTitledBorder("Manufacturer"); + GUIUtil.changeFontStyle(border, Font.BOLD); + sub.setBorder(border); + + JPanel root = new JPanel(new MigLayout("fill", "[grow]")); + root.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); + + List manufacturers = new ArrayList(); + for (Manufacturer m : allManufacturers) { + manufacturers.add(m); + } + + Collections.sort(manufacturers, new Comparator() { + @Override + public int compare(Manufacturer o1, Manufacturer o2) { + return o1.getSimpleName().compareTo( o2.getSimpleName()); + } + + }); + + manufacturerCheckList = new CheckList.Builder().build(); + manufacturerCheckList.setData(manufacturers); + + manufacturerCheckList.setUncheckedItems(unselectedManusFromPreferences); + filter.setExcludedManufacturers(unselectedManusFromPreferences); + manufacturerCheckList.getModel().addListDataListener( new ListDataListener() { + @Override + public void intervalAdded(ListDataEvent e) { + } + @Override + public void intervalRemoved(ListDataEvent e) { + } + + @Override + public void contentsChanged(ListDataEvent e) { + MotorFilterPopupMenu.this.filter.setExcludedManufacturers( manufacturerCheckList.getUncheckedItems() ); + onSelectionChanged(); + } + }); + + sub.add(new JScrollPane(manufacturerCheckList.getList()), "grow,wrap"); + + JButton clearMotors = new JButton("clear"); + clearMotors.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + MotorFilterPopupMenu.this.manufacturerCheckList.clearAll(); + + } + }); + + sub.add(clearMotors,"split 2"); + + JButton selectMotors = new JButton("all"); + selectMotors.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + MotorFilterPopupMenu.this.manufacturerCheckList.checkAll(); + + } + }); + + sub.add(selectMotors,"wrap"); + + root.add(sub,"grow, wrap"); + + // Impulse selection + sub = new JPanel(new MigLayout("fill")); + border = BorderFactory.createTitledBorder("Impulse"); + GUIUtil.changeFontStyle(border, Font.BOLD); + sub.setBorder(border); + + impulseCheckList = new CheckList.Builder().build(); + impulseCheckList.setData(Arrays.asList(ImpulseClass.values())); + impulseCheckList.checkAll(); + impulseCheckList.getModel().addListDataListener( new ListDataListener() { + @Override + public void intervalAdded(ListDataEvent e) { + } + @Override + public void intervalRemoved(ListDataEvent e) { + } + @Override + public void contentsChanged(ListDataEvent e) { + MotorFilterPopupMenu.this.filter.setExcludedImpulseClasses( impulseCheckList.getUncheckedItems() ); + onSelectionChanged(); + } + + }); + + sub.add(new JScrollPane(impulseCheckList.getList()), "grow,wrap"); + + JButton clearImpulse = new JButton("clear"); + clearImpulse.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + MotorFilterPopupMenu.this.impulseCheckList.clearAll(); + + } + }); + sub.add(clearImpulse,"split 2"); + + JButton selectImpulse = new JButton("all"); + selectImpulse.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + MotorFilterPopupMenu.this.impulseCheckList.checkAll(); + + } + }); + sub.add(selectImpulse,"wrap"); + + root.add(sub,"grow, wrap"); + + // Diameter selection + + sub = new JPanel(new MigLayout("fill")); + border = BorderFactory.createTitledBorder("Diameter"); + GUIUtil.changeFontStyle(border, Font.BOLD); + sub.setBorder(border); + + JRadioButton showAllDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc1") ); + showAllDiametersButton.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showMode = SHOW_ALL; + MotorFilterPopupMenu.this.filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.ALL); + onSelectionChanged(); + } + }); + showAllDiametersButton.setSelected( showMode == SHOW_ALL); + sub.add(showAllDiametersButton, "growx,wrap"); + + JRadioButton showSmallerDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc2") ); + showSmallerDiametersButton.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showMode = SHOW_SMALLER; + MotorFilterPopupMenu.this.filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.SMALLER); + onSelectionChanged(); + } + }); + showSmallerDiametersButton.setSelected( showMode == SHOW_SMALLER); + sub.add(showSmallerDiametersButton, "growx,wrap"); + + JRadioButton showExactDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc3") ); + showExactDiametersButton.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showMode = SHOW_EXACT; + MotorFilterPopupMenu.this.filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.EXACT); + onSelectionChanged(); + } + }); + showExactDiametersButton.setSelected( showMode == SHOW_EXACT ); + sub.add(showExactDiametersButton, "growx,wrap"); + + root.add(sub, "grow,wrap"); + ButtonGroup comboGroup = new ButtonGroup(); + comboGroup.add( showAllDiametersButton ); + comboGroup.add( showSmallerDiametersButton ); + comboGroup.add( showExactDiametersButton ); + + + // Close button + JButton closeButton = new JButton("close"); + closeButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + MotorFilterPopupMenu.this.onClose(); + } + + }); + root.add(closeButton, "split 2"); + + this.add(root); + + } + + public void onClose() { + + ((SwingPreferences) Application.getPreferences()).setExcludedMotorManufacturers(filter.getExcludedManufacturers()); + + Application.getPreferences().putChoice("MotorDiameterMatch", showMode ); + + setVisible(false); + } + + public abstract void onSelectionChanged(); + +} diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java index 1713c36ef..82d7483c9 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java @@ -1,6 +1,7 @@ package net.sf.openrocket.gui.dialogs.motor.thrustcurve; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -33,11 +34,22 @@ class MotorRowFilter extends RowFilter { private List usedMotors = new ArrayList(); // things which can be changed to modify filter behavior + + // Collection of strings which match text in the moto private List searchTerms = Collections. emptyList(); + + // Limit motors based on diameter of the motor mount private DiameterFilterControl diameterControl = DiameterFilterControl.ALL; + + // Boolean which hides motors in the usedMotors list private boolean hideUsedMotors = false; + + // List of manufacturers to exclude. private List excludedManufacturers = new ArrayList(); + // List of ImpulseClasses to exclude. + private List excludedImpulseClass = new ArrayList(); + public MotorRowFilter(MotorMount mount, ThrustCurveMotorDatabaseModel model) { super(); this.model = model; @@ -61,6 +73,10 @@ class MotorRowFilter extends RowFilter { } } + DiameterFilterControl getDiameterControl() { + return diameterControl; + } + void setDiameterControl(DiameterFilterControl diameterControl) { this.diameterControl = diameterControl; } @@ -69,16 +85,25 @@ class MotorRowFilter extends RowFilter { this.hideUsedMotors = hideUsedMotors; } - void setExcludedManufacturers(List excludedManufacturers) { + List getExcludedManufacturers() { + return excludedManufacturers; + } + + void setExcludedManufacturers(Collection excludedManufacturers) { this.excludedManufacturers.clear(); this.excludedManufacturers.addAll(excludedManufacturers); } + void setExcludedImpulseClasses(Collection excludedImpulseClasses ) { + this.excludedImpulseClass.clear(); + this.excludedImpulseClass.addAll(excludedImpulseClasses); + } + @Override public boolean include(RowFilter.Entry entry) { int index = entry.getIdentifier(); ThrustCurveMotorSet m = model.getMotorSet(index); - return filterManufacturers(m) && filterUsed(m) && filterByDiameter(m) && filterByString(m); + return filterManufacturers(m) && filterUsed(m) && filterByDiameter(m) && filterByString(m) && filterByImpulseClass(m); } private boolean filterManufacturers(ThrustCurveMotorSet m) { @@ -128,4 +153,14 @@ class MotorRowFilter extends RowFilter { } return true; } + + private boolean filterByImpulseClass(ThrustCurveMotorSet m) { + for( ImpulseClass c : excludedImpulseClass ) { + if (c.isIn(m) ) { + return false; + } + } + return true; + } + } diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java index bdd644588..3c09a7a15 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java @@ -83,23 +83,11 @@ import org.slf4j.LoggerFactory; public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelector { private static final Logger log = LoggerFactory.getLogger(ThrustCurveMotorSelectionPanel.class); + private static final Translator trans = Application.getTranslator(); private static final double MOTOR_SIMILARITY_THRESHOLD = 0.95; - private static final int SHOW_ALL = 0; - private static final int SHOW_SMALLER = 1; - private static final int SHOW_EXACT = 2; - private static final String[] SHOW_DESCRIPTIONS = { - //// Show all motors - trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc1"), - //// Show motors with diameter less than that of the motor mount - trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc2"), - //// Show motors with diameter equal to that of the motor mount - trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc3") - }; - private static final int SHOW_MAX = 2; - private static final int ZOOM_ICON_POSITION_NEGATIVE_X = 50; private static final int ZOOM_ICON_POSITION_POSITIVE_Y = 12; @@ -194,11 +182,8 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec } database = db; - List unselectedManusFromPreferences = ((SwingPreferences) Application.getPreferences()).getExcludedMotorManufacturers(); - model = new ThrustCurveMotorDatabaseModel(database); final MotorRowFilter rowFilter = new MotorRowFilter(mount, model); - rowFilter.setExcludedManufacturers(unselectedManusFromPreferences); //// GUI @@ -215,86 +200,57 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec label = new StyledLabel(trans.get("TCMotorSelPan.lbl.Selrocketmotor"), Style.BOLD); panel.add(label, "spanx, wrap para"); - // Diameter selection - JComboBox filterComboBox = new JComboBox(SHOW_DESCRIPTIONS); - filterComboBox.addActionListener(new ActionListener() { + // Search field + //// Search: + label = new StyledLabel(trans.get("TCMotorSelPan.lbl.Search")); + panel.add(label, ""); + + searchField = new JTextField(); + searchField.getDocument().addDocumentListener(new DocumentListener() { @Override - public void actionPerformed(ActionEvent e) { - JComboBox cb = (JComboBox) e.getSource(); - int sel = cb.getSelectedIndex(); - if ((sel < 0) || (sel > SHOW_MAX)) - sel = SHOW_ALL; - switch (sel) { - case SHOW_ALL: - rowFilter.setDiameterControl(MotorRowFilter.DiameterFilterControl.ALL); - break; - - case SHOW_SMALLER: - rowFilter.setDiameterControl(MotorRowFilter.DiameterFilterControl.SMALLER); - break; - - case SHOW_EXACT: - rowFilter.setDiameterControl(MotorRowFilter.DiameterFilterControl.EXACT); - break; - - default: - throw new BugException("Invalid selection mode sel=" + sel); - } + public void changedUpdate(DocumentEvent e) { + update(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + update(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + update(); + } + + private void update() { + String text = searchField.getText().trim(); + String[] split = text.split("\\s+"); + rowFilter.setSearchTerms(Arrays.asList(split)); sorter.sort(); - Application.getPreferences().putChoice("MotorDiameterMatch", sel); scrollSelectionVisible(); } }); - panel.add(filterComboBox, "spanx, growx, wrap rel"); - - //// Hide very similar thrust curves - hideSimilarBox = new JCheckBox(trans.get("TCMotorSelPan.checkbox.hideSimilar")); - GUIUtil.changeFontSize(hideSimilarBox, -1); - hideSimilarBox.setSelected(Application.getPreferences().getBoolean(net.sf.openrocket.startup.Preferences.MOTOR_HIDE_SIMILAR, true)); - hideSimilarBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Application.getPreferences().putBoolean(net.sf.openrocket.startup.Preferences.MOTOR_HIDE_SIMILAR, hideSimilarBox.isSelected()); - updateData(); - } - }); - panel.add(hideSimilarBox, "gapleft para, spanx, growx, wrap para"); - - { - final JCheckBox hideUsedBox = new JCheckBox("Hide motors already used in the mount"); - GUIUtil.changeFontSize(hideUsedBox, -1); - hideUsedBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - rowFilter.setHideUsedMotors(hideUsedBox.isSelected()); - sorter.sort(); - scrollSelectionVisible(); - } - }); - panel.add(hideUsedBox, "gapleft para, spanx, growx, wrap para"); - } + panel.add(searchField, "growx"); { // Find all the manufacturers: - Set manus = new HashSet(); + Set allManufacturers = new HashSet(); for (ThrustCurveMotorSet s : database) { - manus.add(s.getManufacturer()); + allManufacturers.add(s.getManufacturer()); } - final ManufacturerPopupSelector popup = new ManufacturerPopupSelector(manus, unselectedManusFromPreferences) { + + final MotorFilterPopupMenu popup = new MotorFilterPopupMenu(allManufacturers, rowFilter) { @Override - public void onDismissed(List selectedManufacturers, List unselectedManufacturers) { - ((SwingPreferences) Application.getPreferences()).setExcludedMotorManufacturers(unselectedManufacturers); - rowFilter.setExcludedManufacturers(unselectedManufacturers); + public void onSelectionChanged() { sorter.sort(); scrollSelectionVisible(); - System.out.println("Here I am"); } }; - JButton manuFilter = new JButton("Manufacturer Filter"); + JButton manuFilter = new JButton("Motor Filter"); manuFilter.addMouseListener(new MouseListener() { @Override @@ -319,7 +275,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec } }); - panel.add(manuFilter, "gapleft para, spanx, growx, wrap para"); + panel.add(manuFilter, "gapleft para, wrap para"); } @@ -382,8 +338,32 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec scrollpane.setViewportView(table); panel.add(scrollpane, "grow, width :500:, height :300:, spanx, wrap para"); + { + final JCheckBox hideUsedBox = new JCheckBox("Hide motors already used in the mount"); + GUIUtil.changeFontSize(hideUsedBox, -1); + hideUsedBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + rowFilter.setHideUsedMotors(hideUsedBox.isSelected()); + sorter.sort(); + scrollSelectionVisible(); + } + }); + panel.add(hideUsedBox, "gapleft para, spanx, growx, wrap para"); + } - + //// Hide very similar thrust curves + hideSimilarBox = new JCheckBox(trans.get("TCMotorSelPan.checkbox.hideSimilar")); + GUIUtil.changeFontSize(hideSimilarBox, -1); + hideSimilarBox.setSelected(Application.getPreferences().getBoolean(net.sf.openrocket.startup.Preferences.MOTOR_HIDE_SIMILAR, true)); + hideSimilarBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Application.getPreferences().putBoolean(net.sf.openrocket.startup.Preferences.MOTOR_HIDE_SIMILAR, hideSimilarBox.isSelected()); + updateData(); + } + }); + panel.add(hideSimilarBox, "gapleft para, spanx, growx, wrap para"); // Motor mount diameter label //// Motor mount diameter: @@ -391,42 +371,6 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(diameter)); panel.add(label, "gapright 30lp, spanx, split"); - - - // Search field - //// Search: - label = new StyledLabel(trans.get("TCMotorSelPan.lbl.Search")); - panel.add(label, ""); - - searchField = new JTextField(); - searchField.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void changedUpdate(DocumentEvent e) { - update(); - } - - @Override - public void insertUpdate(DocumentEvent e) { - update(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - update(); - } - - private void update() { - String text = searchField.getText().trim(); - String[] split = text.split("\\s+"); - rowFilter.setSearchTerms(Arrays.asList(split)); - sorter.sort(); - scrollSelectionVisible(); - } - }); - panel.add(searchField, "growx, wrap"); - - - // Vertical split this.add(panel, "grow"); this.add(new JSeparator(JSeparator.VERTICAL), "growy, gap para para"); @@ -615,17 +559,8 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec panel.add(layer, "width 300:300:, height 180:180:, grow, spanx"); - - this.add(panel, "grow"); - - - // Sets the filter: - int showMode = Application.getPreferences().getChoice(net.sf.openrocket.startup.Preferences.MOTOR_DIAMETER_FILTER, SHOW_MAX, SHOW_EXACT); - filterComboBox.setSelectedIndex(showMode); - - // Update the panel data updateData(); setDelays(false); diff --git a/swing/src/net/sf/openrocket/gui/util/CheckList.java b/swing/src/net/sf/openrocket/gui/util/CheckList.java index 6eb233092..fa7c17948 100644 --- a/swing/src/net/sf/openrocket/gui/util/CheckList.java +++ b/swing/src/net/sf/openrocket/gui/util/CheckList.java @@ -159,6 +159,14 @@ public class CheckList { return unchecked; } + public void checkAll() { + getModel().checkAll(); + } + + public void clearAll() { + getModel().clearAll(); + } + /** * Resets checked elements * @param elements @@ -167,6 +175,10 @@ public class CheckList { getModel().setCheckedItems(elements); } + public void setUncheckedItems( Collection elements ) { + getModel().setUncheckedItems(elements); + } + public void toggleIndex(int index) { if (index >= 0 && index < list.getModel().getSize()) { DefaultCheckListModel model = getModel(); diff --git a/swing/src/net/sf/openrocket/gui/util/CheckListEditor.java b/swing/src/net/sf/openrocket/gui/util/CheckListEditor.java index 0dafdc111..68680670f 100644 --- a/swing/src/net/sf/openrocket/gui/util/CheckListEditor.java +++ b/swing/src/net/sf/openrocket/gui/util/CheckListEditor.java @@ -73,7 +73,8 @@ final class CheckListEditor extends MouseAdapter { if (e.getClickCount() > 1) { // clear all and check selected for more then 1 clicks - model.setCheckedItems(Arrays.asList(model.getElementAt(index))); + // Original implementation had this implementation. I didn't like that behavior. +// model.setCheckedItems(Arrays.asList(model.getElementAt(index))); } else { // simple toggle for 1 click model.setCheckedIndex(index, !model.isCheckedIndex(index)); diff --git a/swing/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java b/swing/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java index 647019400..cbb4e5919 100644 --- a/swing/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java +++ b/swing/src/net/sf/openrocket/gui/util/DefaultCheckListModel.java @@ -107,6 +107,16 @@ public class DefaultCheckListModel extends AbstractListModel { return Collections.unmodifiableList(items); } + public void clearAll() { + checks.clear(); + fireContentsChanged(this, 0, checks.size() - 1); + } + + public void checkAll() { + checks.addAll(data); + fireContentsChanged(this, 0, checks.size() - 1); + } + public void setCheckedItems(Collection items) { // if ( CollectionUtils.isEmpty(items)) return; @@ -121,4 +131,14 @@ public class DefaultCheckListModel extends AbstractListModel { } + public void setUncheckedItems( Collection items ) { + + List correctedItems = new ArrayList(data); + correctedItems.removeAll(items); + + checks.clear(); + checks.addAll(correctedItems); + fireContentsChanged(this, 0, checks.size() - 1); + + } } From 572b14de13c118e68bf074952ba931c78b8f955b Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Sat, 28 Sep 2013 22:16:31 -0500 Subject: [PATCH 06/17] Localize motor popup and new fields in ThrustCurveMotorSelectionPanel. --- core/resources/l10n/messages.properties | 6 ++++++ .../motor/thrustcurve/MotorFilterPopupMenu.java | 16 ++++++++-------- .../ThrustCurveMotorSelectionPanel.java | 6 +++--- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 7d169196e..267f1e13d 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -1087,6 +1087,8 @@ StorageOptChooser.lbl.Saveopt = Save options ! ThrustCurveMotorSelectionPanel TCMotorSelPan.lbl.Selrocketmotor = Select rocket motor: TCMotorSelPan.checkbox.hideSimilar = Hide very similar thrust curves +TCMotorSelPan.checkbox.hideUsed = Hide motors already used in the mount +TCMotorSelPan.btn.filter = Filter Motors TCMotorSelPan.SHOW_DESCRIPTIONS.desc1 = Show all motors TCMotorSelPan.SHOW_DESCRIPTIONS.desc2 = Show motors with diameter less than that of the motor mount TCMotorSelPan.SHOW_DESCRIPTIONS.desc3 = Show motors with diameter equal to that of the motor mount @@ -1108,6 +1110,10 @@ TCMotorSelPan.title.Thrustcurve = Thrust curve: TCMotorSelPan.title.Thrust = Thrust TCMotorSelPan.delayBox.None = None TCMotorSelPan.noDescription = No description available. +TCMotorSelPan.btn.checkAll = Select All +TCMotorSelPan.btn.checkNone = Clear All +TCMotorSelPan.btn.close = Close + ! PlotDialog diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPopupMenu.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPopupMenu.java index e49733413..b124c6036 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPopupMenu.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPopupMenu.java @@ -57,7 +57,7 @@ public abstract class MotorFilterPopupMenu extends JPopupMenu { // Manufacturer selection JPanel sub = new JPanel(new MigLayout("fill")); - TitledBorder border = BorderFactory.createTitledBorder("Manufacturer"); + TitledBorder border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.MANUFACTURER")); GUIUtil.changeFontStyle(border, Font.BOLD); sub.setBorder(border); @@ -99,7 +99,7 @@ public abstract class MotorFilterPopupMenu extends JPopupMenu { sub.add(new JScrollPane(manufacturerCheckList.getList()), "grow,wrap"); - JButton clearMotors = new JButton("clear"); + JButton clearMotors = new JButton(trans.get("TCMotorSelPan.btn.checkNone")); clearMotors.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -110,7 +110,7 @@ public abstract class MotorFilterPopupMenu extends JPopupMenu { sub.add(clearMotors,"split 2"); - JButton selectMotors = new JButton("all"); + JButton selectMotors = new JButton(trans.get("TCMotorSelPan.btn.checkAll")); selectMotors.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -125,7 +125,7 @@ public abstract class MotorFilterPopupMenu extends JPopupMenu { // Impulse selection sub = new JPanel(new MigLayout("fill")); - border = BorderFactory.createTitledBorder("Impulse"); + border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.TOTAL_IMPULSE")); GUIUtil.changeFontStyle(border, Font.BOLD); sub.setBorder(border); @@ -149,7 +149,7 @@ public abstract class MotorFilterPopupMenu extends JPopupMenu { sub.add(new JScrollPane(impulseCheckList.getList()), "grow,wrap"); - JButton clearImpulse = new JButton("clear"); + JButton clearImpulse = new JButton(trans.get("TCMotorSelPan.btn.checkNone")); clearImpulse.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -159,7 +159,7 @@ public abstract class MotorFilterPopupMenu extends JPopupMenu { }); sub.add(clearImpulse,"split 2"); - JButton selectImpulse = new JButton("all"); + JButton selectImpulse = new JButton(trans.get("TCMotorSelPan.btn.checkAll")); selectImpulse.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -174,7 +174,7 @@ public abstract class MotorFilterPopupMenu extends JPopupMenu { // Diameter selection sub = new JPanel(new MigLayout("fill")); - border = BorderFactory.createTitledBorder("Diameter"); + border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.DIAMETER")); GUIUtil.changeFontStyle(border, Font.BOLD); sub.setBorder(border); @@ -222,7 +222,7 @@ public abstract class MotorFilterPopupMenu extends JPopupMenu { // Close button - JButton closeButton = new JButton("close"); + JButton closeButton = new JButton(trans.get("TCMotorSelPan.btn.close")); closeButton.addActionListener(new ActionListener() { @Override diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java index 3c09a7a15..bd24a5ca5 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java @@ -203,7 +203,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec // Search field //// Search: label = new StyledLabel(trans.get("TCMotorSelPan.lbl.Search")); - panel.add(label, ""); + panel.add(label, "split"); searchField = new JTextField(); searchField.getDocument().addDocumentListener(new DocumentListener() { @@ -250,7 +250,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec }; - JButton manuFilter = new JButton("Motor Filter"); + JButton manuFilter = new JButton(trans.get("TCMotorSelPan.btn.filter")); manuFilter.addMouseListener(new MouseListener() { @Override @@ -339,7 +339,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec panel.add(scrollpane, "grow, width :500:, height :300:, spanx, wrap para"); { - final JCheckBox hideUsedBox = new JCheckBox("Hide motors already used in the mount"); + final JCheckBox hideUsedBox = new JCheckBox(trans.get("TCMotorSelPan.checkbox.hideUsed")); GUIUtil.changeFontSize(hideUsedBox, -1); hideUsedBox.addActionListener(new ActionListener() { @Override From 444035442f35c67ca806c08abcdaddef3f3a81f7 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Wed, 2 Oct 2013 13:45:54 -0500 Subject: [PATCH 07/17] scroll to selection on opening. --- .../motor/thrustcurve/ThrustCurveMotorSelectionPanel.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java index bd24a5ca5..555c49a38 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java @@ -352,6 +352,8 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec panel.add(hideUsedBox, "gapleft para, spanx, growx, wrap para"); } + scrollSelectionVisible(); + //// Hide very similar thrust curves hideSimilarBox = new JCheckBox(trans.get("TCMotorSelPan.checkbox.hideSimilar")); GUIUtil.changeFontSize(hideSimilarBox, -1); From e44c87029b9ab2787715335c04f917b778c4ac10 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Wed, 2 Oct 2013 20:48:13 -0500 Subject: [PATCH 08/17] Fix eclipse classpath after moving the lib-test stuff. --- core/.classpath | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/.classpath b/core/.classpath index 19534aee6..753ef1030 100644 --- a/core/.classpath +++ b/core/.classpath @@ -10,20 +10,20 @@ - - - - - - - + + + + + + + From 32817f2cb1c2f302f092de3c9735ff5403d2d876 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Thu, 3 Oct 2013 21:00:50 -0500 Subject: [PATCH 09/17] Reworked the ThrustCurveMotorSelectionPanel so a single instance can be reused for different searches. This means the MotorRowFilter has an easier time remembering its settings on a per rocket basis. --- .../MotorConfigurationPanel.java | 4 +- .../gui/dialogs/motor/MotorChooserDialog.java | 11 ++- .../motor/thrustcurve/MotorRowFilter.java | 7 +- .../ThrustCurveMotorSelectionPanel.java | 85 +++++++++++-------- 4 files changed, 67 insertions(+), 40 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationPanel.java index 1cb7178f6..b47d910f7 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationPanel.java @@ -43,9 +43,11 @@ public class MotorConfigurationPanel extends JPanel { private final MotorConfigurationTableModel configurationTableModel; private final JButton selectMotorButton, removeMotorButton, selectIgnitionButton, resetIgnitionButton; + private final MotorChooserDialog dialog; MotorConfigurationPanel(FlightConfigurationDialog flightConfigurationDialog, Rocket rocket) { super(new MigLayout("fill")); + dialog = new MotorChooserDialog(flightConfigurationDialog); this.flightConfigurationDialog = flightConfigurationDialog; this.rocket = rocket; @@ -207,7 +209,7 @@ public class MotorConfigurationPanel extends JPanel { MotorConfiguration config = mount.getMotorConfiguration().get(id); - MotorChooserDialog dialog = new MotorChooserDialog(mount, id, flightConfigurationDialog); + dialog.setMotorMountAndConfig(mount, id); dialog.setVisible(true); Motor m = dialog.getSelectedMotor(); double d = dialog.getSelectedDelay(); diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java index 898964af0..a6718116f 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java @@ -26,14 +26,18 @@ public class MotorChooserDialog extends JDialog implements CloseableDialog { private boolean okClicked = false; private static final Translator trans = Application.getTranslator(); - public MotorChooserDialog(MotorMount mount, String currentConfig, Window owner) { + this(owner); + setMotorMountAndConfig(mount, currentConfig); + } + + public MotorChooserDialog(Window owner) { super(owner, trans.get("MotorChooserDialog.title"), Dialog.ModalityType.APPLICATION_MODAL); JPanel panel = new JPanel(new MigLayout("fill")); - selectionPanel = new ThrustCurveMotorSelectionPanel(mount, currentConfig); + selectionPanel = new ThrustCurveMotorSelectionPanel(); panel.add(selectionPanel, "grow, wrap para"); @@ -74,6 +78,9 @@ public class MotorChooserDialog extends JDialog implements CloseableDialog { selectionPanel.setCloseableDialog(this); } + public void setMotorMountAndConfig( MotorMount mount, String currentConfig ) { + selectionPanel.setMotorMountAndConfig(mount, currentConfig); + } /** * Return the motor selected by this chooser dialog, or null if the selection has been aborted. diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java index 82d7483c9..a7961ec1d 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java @@ -30,7 +30,7 @@ class MotorRowFilter extends RowFilter { // configuration data used in the filter process private final ThrustCurveMotorDatabaseModel model; - private final Double diameter; + private Double diameter; private List usedMotors = new ArrayList(); // things which can be changed to modify filter behavior @@ -50,9 +50,12 @@ class MotorRowFilter extends RowFilter { // List of ImpulseClasses to exclude. private List excludedImpulseClass = new ArrayList(); - public MotorRowFilter(MotorMount mount, ThrustCurveMotorDatabaseModel model) { + public MotorRowFilter(ThrustCurveMotorDatabaseModel model) { super(); this.model = model; + } + + public void setMotorMount( MotorMount mount ) { if (mount != null) { this.diameter = mount.getMotorMountDiameter(); for (MotorConfiguration m : mount.getMotorConfiguration()) { diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java index 555c49a38..07d2ccc54 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java @@ -98,20 +98,21 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec private static final ThrustCurveMotorComparator MOTOR_COMPARATOR = new ThrustCurveMotorComparator(); - private final List database; + private List database; private CloseableDialog dialog = null; final ThrustCurveMotorDatabaseModel model; private final JTable table; private final TableRowSorter sorter; + private final MotorRowFilter rowFilter; private final JCheckBox hideSimilarBox; private final JTextField searchField; String[] searchTerms = new String[0]; - + private final StyledLabel diameterLabel; private final JLabel curveSelectionLabel; private final JComboBox curveSelectionBox; private final DefaultComboBoxModel curveSelectionModel; @@ -140,7 +141,11 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec private ThrustCurveMotorSet selectedMotorSet; private double selectedDelay; - + public ThrustCurveMotorSelectionPanel(MotorMount mount, String currentConfig) { + this(); + setMotorMountAndConfig( mount, currentConfig ); + + } /** * Sole constructor. * @@ -148,42 +153,17 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec * @param delay the currently selected ejection charge delay. * @param diameter the diameter of the motor mount. */ - public ThrustCurveMotorSelectionPanel(MotorMount mount, String currentConfig) { + public ThrustCurveMotorSelectionPanel() { super(new MigLayout("fill", "[grow][]")); - double diameter = 0; - if (currentConfig != null && mount != null) { - MotorConfiguration motorConf = mount.getMotorConfiguration().get(currentConfig); - selectedMotor = (ThrustCurveMotor) motorConf.getMotor(); - selectedDelay = motorConf.getEjectionDelay(); - diameter = mount.getMotorMountDiameter(); - } - // Construct the database (adding the current motor if not in the db already) List db; db = Application.getThrustCurveMotorSetDatabase().getMotorSets(); - // If current motor is not found in db, add a new ThrustCurveMotorSet containing it - if (selectedMotor != null) { - for (ThrustCurveMotorSet motorSet : db) { - if (motorSet.getMotors().contains(selectedMotor)) { - selectedMotorSet = motorSet; - break; - } - } - if (selectedMotorSet == null) { - db = new ArrayList(db); - ThrustCurveMotorSet extra = new ThrustCurveMotorSet(); - extra.addMotor(selectedMotor); - selectedMotorSet = extra; - db.add(extra); - Collections.sort(db); - } - } database = db; model = new ThrustCurveMotorDatabaseModel(database); - final MotorRowFilter rowFilter = new MotorRowFilter(mount, model); + rowFilter = new MotorRowFilter(model); //// GUI @@ -369,8 +349,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec // Motor mount diameter label //// Motor mount diameter: - label = new StyledLabel(trans.get("TCMotorSelPan.lbl.Motormountdia") + " " + - UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(diameter)); + diameterLabel = new StyledLabel(); panel.add(label, "gapright 30lp, spanx, split"); // Vertical split @@ -490,9 +469,6 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec scrollpane = new JScrollPane(comment); panel.add(scrollpane, "spanx, growx, wrap para"); - - - // Thrust curve plot chart = ChartFactory.createXYLineChart( null, // title @@ -569,6 +545,45 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec } + public void setMotorMountAndConfig( MotorMount mount, String currentConfig ) { + double diameter = 0; + + if (currentConfig != null && mount != null) { + MotorConfiguration motorConf = mount.getMotorConfiguration().get(currentConfig); + selectedMotor = (ThrustCurveMotor) motorConf.getMotor(); + selectedDelay = motorConf.getEjectionDelay(); + diameter = mount.getMotorMountDiameter(); + } + + // If current motor is not found in db, add a new ThrustCurveMotorSet containing it + if (selectedMotor != null) { + for (ThrustCurveMotorSet motorSet : database) { + if (motorSet.getMotors().contains(selectedMotor)) { + selectedMotorSet = motorSet; + break; + } + } + if (selectedMotorSet == null) { + database = new ArrayList(database); + ThrustCurveMotorSet extra = new ThrustCurveMotorSet(); + extra.addMotor(selectedMotor); + selectedMotorSet = extra; + database.add(extra); + Collections.sort(database); + } + } + + updateData(); + setDelays(true); + + diameterLabel.setText(trans.get("TCMotorSelPan.lbl.Motormountdia") + " " + + UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(0)); + + rowFilter.setMotorMount(mount); + scrollSelectionVisible(); + + } + @Override public Motor getSelectedMotor() { return selectedMotor; From 71e3e76493038baed8e85a49f9a305c5939b91d1 Mon Sep 17 00:00:00 2001 From: soupwizard Date: Thu, 3 Oct 2013 21:25:55 -0700 Subject: [PATCH 10/17] Swing build depends on core jar already being built, added that dependency. --- build.xml | 172 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 101 insertions(+), 71 deletions(-) diff --git a/build.xml b/build.xml index 8a746fad8..b568e33ea 100644 --- a/build.xml +++ b/build.xml @@ -1,91 +1,121 @@ - + + + + + + + + + - + + + + + + + - - + + + + + + + + + + + + + + - - - + - - + + + - - - - - Checking project for FIXMEs. - - - - - - - - - - - - - - - - - - - - - - CRITICAL TODOs exist in project: + + + + + + + + + + + + Checking project for FIXMEs. + + + + + + + + + + + + + + + + + + + + + + CRITICAL TODOs exist in project: ${criticaltodos} - No critical TODOs in project. - - - - - - - - Checking project for non-ASCII characters. - - - - - - - - - - - - - - - - - - - - - - Non-ASCII characters exist in project: + No critical TODOs in project. + + + + + + + Checking project for non-ASCII characters. + + + + + + + + + + + + + + + + + + + + + + Non-ASCII characters exist in project: ${nonascii} - No non-ASCII characters in project. - - - + No non-ASCII characters in project. + + From e6755e0e8475b5a00b16d4cb11994ea1de809a8c Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Fri, 4 Oct 2013 20:36:30 -0500 Subject: [PATCH 11/17] Rework the thrustcurve motor filter and information. They now share tabs on the MotorSelectionPanel. Added Minimum Motor diameter to the motor filter. --- core/resources/l10n/messages.properties | 1 + ...erPopupMenu.java => MotorFilterPanel.java} | 538 ++++++------ .../thrustcurve/MotorInformationPanel.java | 315 +++++++ .../motor/thrustcurve/MotorRowFilter.java | 20 +- .../ThrustCurveMotorSelectionPanel.java | 824 ++++++------------ 5 files changed, 888 insertions(+), 810 deletions(-) rename swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/{MotorFilterPopupMenu.java => MotorFilterPanel.java} (61%) create mode 100644 swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorInformationPanel.java diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 267f1e13d..55f9ece1a 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -1088,6 +1088,7 @@ StorageOptChooser.lbl.Saveopt = Save options TCMotorSelPan.lbl.Selrocketmotor = Select rocket motor: TCMotorSelPan.checkbox.hideSimilar = Hide very similar thrust curves TCMotorSelPan.checkbox.hideUsed = Hide motors already used in the mount +TCMotorSelPan.btn.details = Show Details TCMotorSelPan.btn.filter = Filter Motors TCMotorSelPan.SHOW_DESCRIPTIONS.desc1 = Show all motors TCMotorSelPan.SHOW_DESCRIPTIONS.desc2 = Show motors with diameter less than that of the motor mount diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPopupMenu.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java similarity index 61% rename from swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPopupMenu.java rename to swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java index b124c6036..3c706c430 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPopupMenu.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java @@ -1,251 +1,287 @@ -package net.sf.openrocket.gui.dialogs.motor.thrustcurve; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; -import javax.swing.JButton; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JRadioButton; -import javax.swing.JScrollPane; -import javax.swing.border.TitledBorder; -import javax.swing.event.ListDataEvent; -import javax.swing.event.ListDataListener; - -import net.miginfocom.swing.MigLayout; -import net.sf.openrocket.gui.util.CheckList; -import net.sf.openrocket.gui.util.GUIUtil; -import net.sf.openrocket.gui.util.SwingPreferences; -import net.sf.openrocket.l10n.Translator; -import net.sf.openrocket.motor.Manufacturer; -import net.sf.openrocket.startup.Application; - -import com.itextpdf.text.Font; - -public abstract class MotorFilterPopupMenu extends JPopupMenu { - - private static final Translator trans = Application.getTranslator(); - - private final CheckList manufacturerCheckList; - - private final CheckList impulseCheckList; - - private final MotorRowFilter filter; - - private int showMode = SHOW_ALL; - - private static final int SHOW_ALL = 0; - private static final int SHOW_SMALLER = 1; - private static final int SHOW_EXACT = 2; - private static final int SHOW_MAX = 2; - - - public MotorFilterPopupMenu(Collection allManufacturers, MotorRowFilter filter ) { - - this.filter = filter; - - showMode = Application.getPreferences().getChoice(net.sf.openrocket.startup.Preferences.MOTOR_DIAMETER_FILTER, MotorFilterPopupMenu.SHOW_MAX, MotorFilterPopupMenu.SHOW_EXACT); - List unselectedManusFromPreferences = ((SwingPreferences) Application.getPreferences()).getExcludedMotorManufacturers(); - - // Manufacturer selection - JPanel sub = new JPanel(new MigLayout("fill")); - TitledBorder border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.MANUFACTURER")); - GUIUtil.changeFontStyle(border, Font.BOLD); - sub.setBorder(border); - - JPanel root = new JPanel(new MigLayout("fill", "[grow]")); - root.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); - - List manufacturers = new ArrayList(); - for (Manufacturer m : allManufacturers) { - manufacturers.add(m); - } - - Collections.sort(manufacturers, new Comparator() { - @Override - public int compare(Manufacturer o1, Manufacturer o2) { - return o1.getSimpleName().compareTo( o2.getSimpleName()); - } - - }); - - manufacturerCheckList = new CheckList.Builder().build(); - manufacturerCheckList.setData(manufacturers); - - manufacturerCheckList.setUncheckedItems(unselectedManusFromPreferences); - filter.setExcludedManufacturers(unselectedManusFromPreferences); - manufacturerCheckList.getModel().addListDataListener( new ListDataListener() { - @Override - public void intervalAdded(ListDataEvent e) { - } - @Override - public void intervalRemoved(ListDataEvent e) { - } - - @Override - public void contentsChanged(ListDataEvent e) { - MotorFilterPopupMenu.this.filter.setExcludedManufacturers( manufacturerCheckList.getUncheckedItems() ); - onSelectionChanged(); - } - }); - - sub.add(new JScrollPane(manufacturerCheckList.getList()), "grow,wrap"); - - JButton clearMotors = new JButton(trans.get("TCMotorSelPan.btn.checkNone")); - clearMotors.addActionListener( new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - MotorFilterPopupMenu.this.manufacturerCheckList.clearAll(); - - } - }); - - sub.add(clearMotors,"split 2"); - - JButton selectMotors = new JButton(trans.get("TCMotorSelPan.btn.checkAll")); - selectMotors.addActionListener( new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - MotorFilterPopupMenu.this.manufacturerCheckList.checkAll(); - - } - }); - - sub.add(selectMotors,"wrap"); - - root.add(sub,"grow, wrap"); - - // Impulse selection - sub = new JPanel(new MigLayout("fill")); - border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.TOTAL_IMPULSE")); - GUIUtil.changeFontStyle(border, Font.BOLD); - sub.setBorder(border); - - impulseCheckList = new CheckList.Builder().build(); - impulseCheckList.setData(Arrays.asList(ImpulseClass.values())); - impulseCheckList.checkAll(); - impulseCheckList.getModel().addListDataListener( new ListDataListener() { - @Override - public void intervalAdded(ListDataEvent e) { - } - @Override - public void intervalRemoved(ListDataEvent e) { - } - @Override - public void contentsChanged(ListDataEvent e) { - MotorFilterPopupMenu.this.filter.setExcludedImpulseClasses( impulseCheckList.getUncheckedItems() ); - onSelectionChanged(); - } - - }); - - sub.add(new JScrollPane(impulseCheckList.getList()), "grow,wrap"); - - JButton clearImpulse = new JButton(trans.get("TCMotorSelPan.btn.checkNone")); - clearImpulse.addActionListener( new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - MotorFilterPopupMenu.this.impulseCheckList.clearAll(); - - } - }); - sub.add(clearImpulse,"split 2"); - - JButton selectImpulse = new JButton(trans.get("TCMotorSelPan.btn.checkAll")); - selectImpulse.addActionListener( new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - MotorFilterPopupMenu.this.impulseCheckList.checkAll(); - - } - }); - sub.add(selectImpulse,"wrap"); - - root.add(sub,"grow, wrap"); - - // Diameter selection - - sub = new JPanel(new MigLayout("fill")); - border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.DIAMETER")); - GUIUtil.changeFontStyle(border, Font.BOLD); - sub.setBorder(border); - - JRadioButton showAllDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc1") ); - showAllDiametersButton.addActionListener( new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - showMode = SHOW_ALL; - MotorFilterPopupMenu.this.filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.ALL); - onSelectionChanged(); - } - }); - showAllDiametersButton.setSelected( showMode == SHOW_ALL); - sub.add(showAllDiametersButton, "growx,wrap"); - - JRadioButton showSmallerDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc2") ); - showSmallerDiametersButton.addActionListener( new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - showMode = SHOW_SMALLER; - MotorFilterPopupMenu.this.filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.SMALLER); - onSelectionChanged(); - } - }); - showSmallerDiametersButton.setSelected( showMode == SHOW_SMALLER); - sub.add(showSmallerDiametersButton, "growx,wrap"); - - JRadioButton showExactDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc3") ); - showExactDiametersButton.addActionListener( new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - showMode = SHOW_EXACT; - MotorFilterPopupMenu.this.filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.EXACT); - onSelectionChanged(); - } - }); - showExactDiametersButton.setSelected( showMode == SHOW_EXACT ); - sub.add(showExactDiametersButton, "growx,wrap"); - - root.add(sub, "grow,wrap"); - ButtonGroup comboGroup = new ButtonGroup(); - comboGroup.add( showAllDiametersButton ); - comboGroup.add( showSmallerDiametersButton ); - comboGroup.add( showExactDiametersButton ); - - - // Close button - JButton closeButton = new JButton(trans.get("TCMotorSelPan.btn.close")); - closeButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - MotorFilterPopupMenu.this.onClose(); - } - - }); - root.add(closeButton, "split 2"); - - this.add(root); - - } - - public void onClose() { - - ((SwingPreferences) Application.getPreferences()).setExcludedMotorManufacturers(filter.getExcludedManufacturers()); - - Application.getPreferences().putChoice("MotorDiameterMatch", showMode ); - - setVisible(false); - } - - public abstract void onSelectionChanged(); - -} +package net.sf.openrocket.gui.dialogs.motor.thrustcurve; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.border.TitledBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.gui.SpinnerEditor; +import net.sf.openrocket.gui.adaptors.DoubleModel; +import net.sf.openrocket.gui.components.BasicSlider; +import net.sf.openrocket.gui.components.UnitSelector; +import net.sf.openrocket.gui.util.CheckList; +import net.sf.openrocket.gui.util.GUIUtil; +import net.sf.openrocket.gui.util.SwingPreferences; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.motor.Manufacturer; +import net.sf.openrocket.rocketcomponent.MotorMount; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.unit.UnitGroup; + +import com.itextpdf.text.Font; + +public abstract class MotorFilterPanel extends JPanel { + + private static final Translator trans = Application.getTranslator(); + + private final CheckList manufacturerCheckList; + + private final CheckList impulseCheckList; + + private final MotorRowFilter filter; + private final TitledBorder diameterTitleBorder; + private final DoubleModel mountDiameter = new DoubleModel(1); + + private int showMode = SHOW_ALL; + + private static final int SHOW_ALL = 0; + private static final int SHOW_SMALLER = 1; + private static final int SHOW_EXACT = 2; + private static final int SHOW_MAX = 2; + + public MotorFilterPanel(Collection allManufacturers, MotorRowFilter filter ) { + super(new MigLayout("fill", "[grow]")); + this.filter = filter; + + showMode = Application.getPreferences().getChoice(net.sf.openrocket.startup.Preferences.MOTOR_DIAMETER_FILTER, MotorFilterPanel.SHOW_MAX, MotorFilterPanel.SHOW_EXACT); + switch( showMode ) { + case SHOW_ALL: + filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.ALL); + break; + case SHOW_EXACT: + filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.EXACT); + break; + case SHOW_SMALLER: + filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.SMALLER); + break; + } + List unselectedManusFromPreferences = ((SwingPreferences) Application.getPreferences()).getExcludedMotorManufacturers(); + filter.setExcludedManufacturers(unselectedManusFromPreferences); + + // Manufacturer selection + JPanel sub = new JPanel(new MigLayout("fill")); + TitledBorder border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.MANUFACTURER")); + GUIUtil.changeFontStyle(border, Font.BOLD); + sub.setBorder(border); + + this.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); + + List manufacturers = new ArrayList(); + for (Manufacturer m : allManufacturers) { + manufacturers.add(m); + } + + Collections.sort(manufacturers, new Comparator() { + @Override + public int compare(Manufacturer o1, Manufacturer o2) { + return o1.getSimpleName().compareTo( o2.getSimpleName()); + } + + }); + + manufacturerCheckList = new CheckList.Builder().build(); + manufacturerCheckList.setData(manufacturers); + + manufacturerCheckList.setUncheckedItems(unselectedManusFromPreferences); + manufacturerCheckList.getModel().addListDataListener( new ListDataListener() { + @Override + public void intervalAdded(ListDataEvent e) { + } + @Override + public void intervalRemoved(ListDataEvent e) { + } + + @Override + public void contentsChanged(ListDataEvent e) { + MotorFilterPanel.this.filter.setExcludedManufacturers( manufacturerCheckList.getUncheckedItems() ); + onSelectionChanged(); + } + }); + + sub.add(new JScrollPane(manufacturerCheckList.getList()), "grow,wrap"); + + JButton clearMotors = new JButton(trans.get("TCMotorSelPan.btn.checkNone")); + clearMotors.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + MotorFilterPanel.this.manufacturerCheckList.clearAll(); + + } + }); + + sub.add(clearMotors,"split 2"); + + JButton selectMotors = new JButton(trans.get("TCMotorSelPan.btn.checkAll")); + selectMotors.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + MotorFilterPanel.this.manufacturerCheckList.checkAll(); + + } + }); + + sub.add(selectMotors,"wrap"); + + this.add(sub,"grow, wrap"); + + // Impulse selection + sub = new JPanel(new MigLayout("fill")); + border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.TOTAL_IMPULSE")); + GUIUtil.changeFontStyle(border, Font.BOLD); + sub.setBorder(border); + + impulseCheckList = new CheckList.Builder().build(); + impulseCheckList.setData(Arrays.asList(ImpulseClass.values())); + impulseCheckList.checkAll(); + impulseCheckList.getModel().addListDataListener( new ListDataListener() { + @Override + public void intervalAdded(ListDataEvent e) { + } + @Override + public void intervalRemoved(ListDataEvent e) { + } + @Override + public void contentsChanged(ListDataEvent e) { + MotorFilterPanel.this.filter.setExcludedImpulseClasses( impulseCheckList.getUncheckedItems() ); + onSelectionChanged(); + } + + }); + + sub.add(new JScrollPane(impulseCheckList.getList()), "grow,wrap"); + + JButton clearImpulse = new JButton(trans.get("TCMotorSelPan.btn.checkNone")); + clearImpulse.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + MotorFilterPanel.this.impulseCheckList.clearAll(); + + } + }); + sub.add(clearImpulse,"split 2"); + + JButton selectImpulse = new JButton(trans.get("TCMotorSelPan.btn.checkAll")); + selectImpulse.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + MotorFilterPanel.this.impulseCheckList.checkAll(); + + } + }); + sub.add(selectImpulse,"wrap"); + + this.add(sub,"grow, wrap"); + + // Diameter selection + + sub = new JPanel(new MigLayout("fill")); + diameterTitleBorder = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.DIAMETER")); + GUIUtil.changeFontStyle(diameterTitleBorder, Font.BOLD); + sub.setBorder(diameterTitleBorder); + + JRadioButton showAllDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc1") ); + showAllDiametersButton.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showMode = SHOW_ALL; + MotorFilterPanel.this.filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.ALL); + saveMotorDiameterMatchPrefence(); + onSelectionChanged(); + } + }); + showAllDiametersButton.setSelected( showMode == SHOW_ALL); + sub.add(showAllDiametersButton, "growx,wrap"); + + JRadioButton showSmallerDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc2") ); + showSmallerDiametersButton.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showMode = SHOW_SMALLER; + MotorFilterPanel.this.filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.SMALLER); + saveMotorDiameterMatchPrefence(); + onSelectionChanged(); + } + }); + showSmallerDiametersButton.setSelected( showMode == SHOW_SMALLER); + sub.add(showSmallerDiametersButton, "growx,wrap"); + + JRadioButton showExactDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc3") ); + showExactDiametersButton.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showMode = SHOW_EXACT; + MotorFilterPanel.this.filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.EXACT); + saveMotorDiameterMatchPrefence(); + onSelectionChanged(); + } + }); + showExactDiametersButton.setSelected( showMode == SHOW_EXACT ); + sub.add(showExactDiametersButton, "growx,wrap"); + ButtonGroup comboGroup = new ButtonGroup(); + comboGroup.add( showAllDiametersButton ); + comboGroup.add( showSmallerDiametersButton ); + comboGroup.add( showExactDiametersButton ); + + { + sub.add( new JLabel("Minimum diameter"), "split 4"); + final DoubleModel minDiameter = new DoubleModel(0, UnitGroup.UNITS_MOTOR_DIMENSIONS, 0, .2); + minDiameter.addChangeListener( new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + MotorFilterPanel.this.filter.setMinimumDiameter(minDiameter.getValue()); + onSelectionChanged(); + } + }); + JSpinner spin = new JSpinner(minDiameter.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + sub.add(spin, "growx"); + + sub.add(new UnitSelector(minDiameter)); + sub.add(new BasicSlider(minDiameter.getSliderModel(0,0.5, mountDiameter)), "w 100lp, wrap"); + } + this.add(sub, "grow,wrap"); + + } + + public void setMotorMount( MotorMount mount ) { + filter.setMotorMount(mount); + onSelectionChanged(); + if ( mount == null ) { + // Disable diameter controls? + diameterTitleBorder.setTitle(trans.get("TCurveMotorCol.DIAMETER")); + mountDiameter.setValue(1.0); + } else { + mountDiameter.setValue(mount.getMotorMountDiameter()); + diameterTitleBorder.setTitle(trans.get("TCurveMotorCol.DIAMETER") + " " + + trans.get("TCMotorSelPan.lbl.Motormountdia") + " " + + UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(mount.getMotorMountDiameter())); + + } + } + + private void saveMotorDiameterMatchPrefence() { + Application.getPreferences().putChoice("MotorDiameterMatch", showMode ); + } + + public abstract void onSelectionChanged(); + +} diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorInformationPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorInformationPanel.java new file mode 100644 index 000000000..8e5fb2ebb --- /dev/null +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorInformationPanel.java @@ -0,0 +1,315 @@ +package net.sf.openrocket.gui.dialogs.motor.thrustcurve; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Font; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JLayeredPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.gui.util.GUIUtil; +import net.sf.openrocket.gui.util.Icons; +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 org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.ValueAxis; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.title.TextTitle; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; + +class MotorInformationPanel extends JPanel { + + private static final int ZOOM_ICON_POSITION_NEGATIVE_X = 50; + private static final int ZOOM_ICON_POSITION_POSITIVE_Y = 12; + + private static final Color NO_COMMENT_COLOR = Color.GRAY; + private static final Color WITH_COMMENT_COLOR = Color.BLACK; + + private static final Translator trans = Application.getTranslator(); + + // Motors in set + private List selectedMotorSet; + // Selected motor + private ThrustCurveMotor selectedMotor; + + private final JLabel totalImpulseLabel; + private final JLabel classificationLabel; + private final JLabel avgThrustLabel; + private final JLabel maxThrustLabel; + private final JLabel burnTimeLabel; + private final JLabel launchMassLabel; + private final JLabel emptyMassLabel; + private final JLabel dataPointsLabel; + private final JLabel digestLabel; + + private final JTextArea comment; + private final Font noCommentFont; + private final Font withCommentFont; + + private final JFreeChart chart; + private final ChartPanel chartPanel; + private final JLabel zoomIcon; + + public MotorInformationPanel() { + super(new MigLayout("fill")); + + // Thrust curve info + //// Total impulse: + { + this.add(new JLabel(trans.get("TCMotorSelPan.lbl.Totalimpulse"))); + totalImpulseLabel = new JLabel(); + this.add(totalImpulseLabel, "split"); + + classificationLabel = new JLabel(); + classificationLabel.setEnabled(false); // Gray out + this.add(classificationLabel, "gapleft unrel, wrap"); + + //// Avg. thrust: + this.add(new JLabel(trans.get("TCMotorSelPan.lbl.Avgthrust"))); + avgThrustLabel = new JLabel(); + this.add(avgThrustLabel, "wrap"); + + //// Max. thrust: + this.add(new JLabel(trans.get("TCMotorSelPan.lbl.Maxthrust"))); + maxThrustLabel = new JLabel(); + this.add(maxThrustLabel, "wrap"); + + //// Burn time: + this.add(new JLabel(trans.get("TCMotorSelPan.lbl.Burntime"))); + burnTimeLabel = new JLabel(); + this.add(burnTimeLabel, "wrap"); + + //// Launch mass: + this.add(new JLabel(trans.get("TCMotorSelPan.lbl.Launchmass"))); + launchMassLabel = new JLabel(); + this.add(launchMassLabel, "wrap"); + + //// Empty mass: + this.add(new JLabel(trans.get("TCMotorSelPan.lbl.Emptymass"))); + emptyMassLabel = new JLabel(); + this.add(emptyMassLabel, "wrap"); + + //// Data points: + this.add(new JLabel(trans.get("TCMotorSelPan.lbl.Datapoints"))); + dataPointsLabel = new JLabel(); + this.add(dataPointsLabel, "wrap para"); + + if (System.getProperty("openrocket.debug.motordigest") != null) { + //// Digest: + this.add(new JLabel(trans.get("TCMotorSelPan.lbl.Digest"))); + digestLabel = new JLabel(); + this.add(digestLabel, "w :300:, wrap para"); + } else { + digestLabel = null; + } + + + comment = new JTextArea(5, 5); + GUIUtil.changeFontSize(comment, -2); + withCommentFont = comment.getFont(); + noCommentFont = withCommentFont.deriveFont(Font.ITALIC); + comment.setLineWrap(true); + comment.setWrapStyleWord(true); + comment.setEditable(false); + JScrollPane scrollpane = new JScrollPane(comment); + this.add(scrollpane, "spanx, growx, wrap para"); + } + + // Thrust curve plot + { + chart = ChartFactory.createXYLineChart( + null, // title + null, // xAxisLabel + null, // yAxisLabel + null, // dataset + PlotOrientation.VERTICAL, + false, // legend + false, // tooltips + false // urls + ); + + // Add the data and formatting to the plot + XYPlot plot = chart.getXYPlot(); + + changeLabelFont(plot.getRangeAxis(), -2); + changeLabelFont(plot.getDomainAxis(), -2); + + //// Thrust curve: + chart.setTitle(new TextTitle(trans.get("TCMotorSelPan.title.Thrustcurve"), this.getFont())); + chart.setBackgroundPaint(this.getBackground()); + plot.setBackgroundPaint(Color.WHITE); + plot.setDomainGridlinePaint(Color.LIGHT_GRAY); + plot.setRangeGridlinePaint(Color.LIGHT_GRAY); + + chartPanel = new ChartPanel(chart, + false, // properties + false, // save + false, // print + false, // zoom + false); // tooltips + chartPanel.setMouseZoomable(false); + chartPanel.setPopupMenu(null); + chartPanel.setMouseWheelEnabled(false); + chartPanel.setRangeZoomable(false); + chartPanel.setDomainZoomable(false); + + chartPanel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + chartPanel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (selectedMotor == null || selectedMotorSet == null) + return; + if (e.getButton() == MouseEvent.BUTTON1) { + // Open plot dialog + ThrustCurveMotorPlotDialog plotDialog = new ThrustCurveMotorPlotDialog(selectedMotorSet, + selectedMotorSet.indexOf(selectedMotor), + SwingUtilities.getWindowAncestor(MotorInformationPanel.this)); + plotDialog.setVisible(true); + } + } + }); + + JLayeredPane layer = new CustomLayeredPane(); + + layer.setBorder(BorderFactory.createLineBorder(Color.BLUE)); + + layer.add(chartPanel, (Integer) 0); + + zoomIcon = new JLabel(Icons.ZOOM_IN); + zoomIcon.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + layer.add(zoomIcon, (Integer) 1); + + this.add(layer, "width 300:300:, height 180:180:, grow, spanx"); + } + } + + public void clearData() { + totalImpulseLabel.setText(""); + totalImpulseLabel.setToolTipText(null); + classificationLabel.setText(""); + classificationLabel.setToolTipText(null); + avgThrustLabel.setText(""); + maxThrustLabel.setText(""); + burnTimeLabel.setText(""); + launchMassLabel.setText(""); + emptyMassLabel.setText(""); + dataPointsLabel.setText(""); + if (digestLabel != null) { + digestLabel.setText(""); + } + setComment(""); + chart.getXYPlot().setDataset(new XYSeriesCollection()); + } + + public void updateData( List motors, ThrustCurveMotor selectedMotor ) { + + this.selectedMotorSet = motors; + this.selectedMotor = selectedMotor; + + // Update thrust curve data + double impulse = selectedMotor.getTotalImpulseEstimate(); + MotorClass mc = MotorClass.getMotorClass(impulse); + totalImpulseLabel.setText(UnitGroup.UNITS_IMPULSE.getDefaultUnit().toStringUnit(impulse)); + classificationLabel.setText("(" + mc.getDescription(impulse) + ")"); + totalImpulseLabel.setToolTipText(mc.getClassDescription()); + classificationLabel.setToolTipText(mc.getClassDescription()); + + avgThrustLabel.setText(UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit( + selectedMotor.getAverageThrustEstimate())); + maxThrustLabel.setText(UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit( + selectedMotor.getMaxThrustEstimate())); + burnTimeLabel.setText(UnitGroup.UNITS_SHORT_TIME.getDefaultUnit().toStringUnit( + selectedMotor.getBurnTimeEstimate())); + launchMassLabel.setText(UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit( + selectedMotor.getLaunchCG().weight)); + emptyMassLabel.setText(UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit( + selectedMotor.getEmptyCG().weight)); + dataPointsLabel.setText("" + (selectedMotor.getTimePoints().length - 1)); + if (digestLabel != null) { + digestLabel.setText(selectedMotor.getDigest()); + } + + setComment(selectedMotor.getDescription()); + + // Update the plot + XYPlot plot = chart.getXYPlot(); + final int index = motors.indexOf(selectedMotor); + + XYSeriesCollection dataset = new XYSeriesCollection(); + for (int i = 0; i < motors.size(); i++) { + ThrustCurveMotor m = motors.get(i); + + //// Thrust + XYSeries series = new XYSeries(trans.get("TCMotorSelPan.title.Thrust") + " (" + i + ")"); + double[] time = m.getTimePoints(); + double[] thrust = m.getThrustPoints(); + + for (int j = 0; j < time.length; j++) { + series.add(time[j], thrust[j]); + } + + dataset.addSeries(series); + + boolean selected = (i == index); + plot.getRenderer().setSeriesStroke(i, new BasicStroke(selected ? 3 : 1)); + plot.getRenderer().setSeriesPaint(i, ThrustCurveMotorSelectionPanel.getColor(i)); + } + + plot.setDataset(dataset); + + } + + private void setComment(String s) { + s = s.trim(); + if (s.length() == 0) { + //// No description available. + comment.setText(trans.get("TCMotorSelPan.noDescription")); + comment.setFont(noCommentFont); + comment.setForeground(NO_COMMENT_COLOR); + } else { + comment.setText(s); + comment.setFont(withCommentFont); + comment.setForeground(WITH_COMMENT_COLOR); + } + comment.setCaretPosition(0); + } + + void changeLabelFont(ValueAxis axis, float size) { + Font font = axis.getTickLabelFont(); + font = font.deriveFont(font.getSize2D() + size); + axis.setTickLabelFont(font); + } + + /** + * Custom layered pane that sets the bounds of the components on every layout. + */ + public class CustomLayeredPane extends JLayeredPane { + @Override + public void doLayout() { + synchronized (getTreeLock()) { + int w = getWidth(); + int h = getHeight(); + chartPanel.setBounds(0, 0, w, h); + zoomIcon.setBounds(w - ZOOM_ICON_POSITION_NEGATIVE_X, ZOOM_ICON_POSITION_POSITIVE_Y, 50, 50); + } + } + } + +} \ No newline at end of file diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java index a7961ec1d..568dd31e1 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java @@ -35,7 +35,10 @@ class MotorRowFilter extends RowFilter { // things which can be changed to modify filter behavior - // Collection of strings which match text in the moto + // Limit motors based on minimum diameter + private Double minimumDiameter; + + // Collection of strings which match text in the motor private List searchTerms = Collections. emptyList(); // Limit motors based on diameter of the motor mount @@ -76,6 +79,14 @@ class MotorRowFilter extends RowFilter { } } + Double getMinimumDiameter() { + return minimumDiameter; + } + + void setMinimumDiameter(Double minimumDiameter) { + this.minimumDiameter = minimumDiameter; + } + DiameterFilterControl getDiameterControl() { return diameterControl; } @@ -130,6 +141,13 @@ class MotorRowFilter extends RowFilter { } private boolean filterByDiameter(ThrustCurveMotorSet m) { + + if ( minimumDiameter != null ) { + if ( m.getDiameter() <= minimumDiameter - 0.0015 ) { + return false; + } + } + if (diameter == null) { return true; } diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java index 07d2ccc54..83b5e5b62 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java @@ -1,9 +1,7 @@ package net.sf.openrocket.gui.dialogs.motor.thrustcurve; -import java.awt.BasicStroke; import java.awt.Color; import java.awt.Component; -import java.awt.Cursor; import java.awt.Font; import java.awt.Paint; import java.awt.Rectangle; @@ -20,26 +18,24 @@ import java.util.List; import java.util.Set; import java.util.prefs.Preferences; -import javax.swing.BorderFactory; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; -import javax.swing.JLayeredPane; import javax.swing.JList; import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSeparator; +import javax.swing.JTabbedPane; import javax.swing.JTable; -import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.ListCellRenderer; import javax.swing.ListSelectionModel; import javax.swing.RowSorter; import javax.swing.SortOrder; -import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; @@ -50,11 +46,9 @@ import javax.swing.table.TableRowSorter; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.database.motor.ThrustCurveMotorSet; import net.sf.openrocket.gui.components.StyledLabel; -import net.sf.openrocket.gui.components.StyledLabel.Style; import net.sf.openrocket.gui.dialogs.motor.CloseableDialog; import net.sf.openrocket.gui.dialogs.motor.MotorSelector; import net.sf.openrocket.gui.util.GUIUtil; -import net.sf.openrocket.gui.util.Icons; import net.sf.openrocket.gui.util.SwingPreferences; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.logging.Markers; @@ -69,82 +63,50 @@ import net.sf.openrocket.util.BugException; import net.sf.openrocket.utils.MotorCorrelation; import org.jfree.chart.ChartColor; -import org.jfree.chart.ChartFactory; -import org.jfree.chart.ChartPanel; -import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.ValueAxis; -import org.jfree.chart.plot.PlotOrientation; -import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.title.TextTitle; -import org.jfree.data.xy.XYSeries; -import org.jfree.data.xy.XYSeriesCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelector { private static final Logger log = LoggerFactory.getLogger(ThrustCurveMotorSelectionPanel.class); - + private static final Translator trans = Application.getTranslator(); - + private static final double MOTOR_SIMILARITY_THRESHOLD = 0.95; - - private static final int ZOOM_ICON_POSITION_NEGATIVE_X = 50; - private static final int ZOOM_ICON_POSITION_POSITIVE_Y = 12; - + private static final Paint[] CURVE_COLORS = ChartColor.createDefaultPaintArray(); - - private static final Color NO_COMMENT_COLOR = Color.GRAY; - private static final Color WITH_COMMENT_COLOR = Color.BLACK; - + private static final ThrustCurveMotorComparator MOTOR_COMPARATOR = new ThrustCurveMotorComparator(); - + private List database; - + private CloseableDialog dialog = null; - - final ThrustCurveMotorDatabaseModel model; + + private final ThrustCurveMotorDatabaseModel model; private final JTable table; private final TableRowSorter sorter; private final MotorRowFilter rowFilter; - + private final JCheckBox hideSimilarBox; - + private final JTextField searchField; - String[] searchTerms = new String[0]; - - private final StyledLabel diameterLabel; + private final JLabel curveSelectionLabel; private final JComboBox curveSelectionBox; private final DefaultComboBoxModel curveSelectionModel; - - private final JLabel totalImpulseLabel; - private final JLabel classificationLabel; - private final JLabel avgThrustLabel; - private final JLabel maxThrustLabel; - private final JLabel burnTimeLabel; - private final JLabel launchMassLabel; - private final JLabel emptyMassLabel; - private final JLabel dataPointsLabel; - private final JLabel digestLabel; - - private final JTextArea comment; - private final Font noCommentFont; - private final Font withCommentFont; - - private final JFreeChart chart; - private final ChartPanel chartPanel; - private final JLabel zoomIcon; - private final JComboBox delayBox; + private final MotorInformationPanel motorInformationPanel; + private final MotorFilterPanel motorFilterPanel; + private ThrustCurveMotor selectedMotor; private ThrustCurveMotorSet selectedMotorSet; private double selectedDelay; - + public ThrustCurveMotorSelectionPanel(MotorMount mount, String currentConfig) { this(); setMotorMountAndConfig( mount, currentConfig ); - + } /** * Sole constructor. @@ -155,169 +117,199 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec */ public ThrustCurveMotorSelectionPanel() { super(new MigLayout("fill", "[grow][]")); - + // Construct the database (adding the current motor if not in the db already) - List db; - db = Application.getThrustCurveMotorSetDatabase().getMotorSets(); - - database = db; - + database = Application.getThrustCurveMotorSetDatabase().getMotorSets(); + model = new ThrustCurveMotorDatabaseModel(database); rowFilter = new MotorRowFilter(model); - - //// GUI - - JPanel panel; - JLabel label; - - panel = new JPanel(new MigLayout("fill")); - this.add(panel, "grow"); - - - - // Selection label - //// Select rocket motor: - label = new StyledLabel(trans.get("TCMotorSelPan.lbl.Selrocketmotor"), Style.BOLD); - panel.add(label, "spanx, wrap para"); - - // Search field - //// Search: - label = new StyledLabel(trans.get("TCMotorSelPan.lbl.Search")); - panel.add(label, "split"); - - searchField = new JTextField(); - searchField.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void changedUpdate(DocumentEvent e) { - update(); - } - - @Override - public void insertUpdate(DocumentEvent e) { - update(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - update(); - } - - private void update() { - String text = searchField.getText().trim(); - String[] split = text.split("\\s+"); - rowFilter.setSearchTerms(Arrays.asList(split)); - sorter.sort(); - scrollSelectionVisible(); - } - }); - panel.add(searchField, "growx"); - + motorInformationPanel = new MotorInformationPanel(); + + //// MotorFilter { - // Find all the manufacturers: Set allManufacturers = new HashSet(); for (ThrustCurveMotorSet s : database) { allManufacturers.add(s.getManufacturer()); } - final MotorFilterPopupMenu popup = new MotorFilterPopupMenu(allManufacturers, rowFilter) { - + motorFilterPanel = new MotorFilterPanel(allManufacturers, rowFilter) { @Override public void onSelectionChanged() { sorter.sort(); scrollSelectionVisible(); } - }; - JButton manuFilter = new JButton(trans.get("TCMotorSelPan.btn.filter")); - manuFilter.addMouseListener(new MouseListener() { - + } + + //// GUI + JPanel panel = new JPanel(new MigLayout("fill","[][grow][]")); + this.add(panel, "grow"); + + //// Select thrust curve: + { + curveSelectionLabel = new JLabel(trans.get("TCMotorSelPan.lbl.Selectthrustcurve")); + panel.add(curveSelectionLabel); + + curveSelectionModel = new DefaultComboBoxModel(); + curveSelectionBox = new JComboBox(curveSelectionModel); + curveSelectionBox.setRenderer(new CurveSelectionRenderer(curveSelectionBox.getRenderer())); + curveSelectionBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Object value = curveSelectionBox.getSelectedItem(); + if (value != null) { + select(((MotorHolder) value).getMotor()); + } + } + }); + panel.add(curveSelectionBox, "growx"); + + final JPopupMenu popup = new JPopupMenu(); + popup.add( motorInformationPanel ); + JButton showDetailsButton = new JButton(trans.get("TCMotorSelPan.btn.details")); + showDetailsButton.addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent e) { } - @Override public void mousePressed(MouseEvent e) { } - @Override public void mouseReleased(MouseEvent e) { popup.show(e.getComponent(), e.getX(), e.getY()); } - @Override public void mouseEntered(MouseEvent e) { } - @Override public void mouseExited(MouseEvent e) { } - }); - panel.add(manuFilter, "gapleft para, wrap para"); - - + panel.add(showDetailsButton, "gapleft para, wrap"); + } - - // Motor selection table - table = new JTable(model); - - - // Set comparators and widths - table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - sorter = new TableRowSorter(model); - for (int i = 0; i < ThrustCurveMotorColumns.values().length; i++) { - ThrustCurveMotorColumns column = ThrustCurveMotorColumns.values()[i]; - sorter.setComparator(i, column.getComparator()); - table.getColumnModel().getColumn(i).setPreferredWidth(column.getWidth()); - } - table.setRowSorter(sorter); - // force initial sort order to by diameter, total impulse, manufacturer + + // Ejection charge delay: { - RowSorter.SortKey[] sortKeys = { - new RowSorter.SortKey(ThrustCurveMotorColumns.DIAMETER.ordinal(), SortOrder.ASCENDING), - new RowSorter.SortKey(ThrustCurveMotorColumns.TOTAL_IMPULSE.ordinal(), SortOrder.ASCENDING), - new RowSorter.SortKey(ThrustCurveMotorColumns.MANUFACTURER.ordinal(), SortOrder.ASCENDING) - }; - sorter.setSortKeys(Arrays.asList(sortKeys)); + panel.add(new JLabel(trans.get("TCMotorSelPan.lbl.Ejectionchargedelay"))); + + delayBox = new JComboBox(); + delayBox.setEditable(true); + delayBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + JComboBox cb = (JComboBox) e.getSource(); + String sel = (String) cb.getSelectedItem(); + //// None + if (sel.equalsIgnoreCase(trans.get("TCMotorSelPan.equalsIgnoreCase.None"))) { + selectedDelay = Motor.PLUGGED; + } else { + try { + selectedDelay = Double.parseDouble(sel); + } catch (NumberFormatException ignore) { + } + } + setDelays(false); + } + }); + panel.add(delayBox, "growx"); + //// (Number of seconds or \"None\") + panel.add(new StyledLabel(trans.get("TCMotorSelPan.lbl.NumberofsecondsorNone"), -3), "wrap para"); + setDelays(false); } - - sorter.setRowFilter(rowFilter); - - // Set selection and double-click listeners - table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - int row = table.getSelectedRow(); - if (row >= 0) { - row = table.convertRowIndexToModel(row); - ThrustCurveMotorSet motorSet = model.getMotorSet(row); - log.info(Markers.USER_MARKER, "Selected table row " + row + ": " + motorSet); - if (motorSet != selectedMotorSet) { - select(selectMotor(motorSet)); - } - } else { - log.info(Markers.USER_MARKER, "Selected table row " + row + ", nothing selected"); + + // Search field + { + //// Search: + StyledLabel label = new StyledLabel(trans.get("TCMotorSelPan.lbl.Search")); + panel.add(label); + searchField = new JTextField(); + searchField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { + update(); } + @Override + public void insertUpdate(DocumentEvent e) { + update(); + } + @Override + public void removeUpdate(DocumentEvent e) { + update(); + } + private void update() { + String text = searchField.getText().trim(); + String[] split = text.split("\\s+"); + rowFilter.setSearchTerms(Arrays.asList(split)); + sorter.sort(); + scrollSelectionVisible(); + } + }); + panel.add(searchField, "span, growx, wrap"); + } + + //// Motor selection table + { + table = new JTable(model); + + // Set comparators and widths + table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + sorter = new TableRowSorter(model); + for (int i = 0; i < ThrustCurveMotorColumns.values().length; i++) { + ThrustCurveMotorColumns column = ThrustCurveMotorColumns.values()[i]; + sorter.setComparator(i, column.getComparator()); + table.getColumnModel().getColumn(i).setPreferredWidth(column.getWidth()); } - }); - table.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { - if (dialog != null) { - dialog.close(true); + table.setRowSorter(sorter); + // force initial sort order to by diameter, total impulse, manufacturer + { + RowSorter.SortKey[] sortKeys = { + new RowSorter.SortKey(ThrustCurveMotorColumns.DIAMETER.ordinal(), SortOrder.ASCENDING), + new RowSorter.SortKey(ThrustCurveMotorColumns.TOTAL_IMPULSE.ordinal(), SortOrder.ASCENDING), + new RowSorter.SortKey(ThrustCurveMotorColumns.MANUFACTURER.ordinal(), SortOrder.ASCENDING) + }; + sorter.setSortKeys(Arrays.asList(sortKeys)); + } + + sorter.setRowFilter(rowFilter); + + // Set selection and double-click listeners + table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + int row = table.getSelectedRow(); + if (row >= 0) { + row = table.convertRowIndexToModel(row); + ThrustCurveMotorSet motorSet = model.getMotorSet(row); + log.info(Markers.USER_MARKER, "Selected table row " + row + ": " + motorSet); + if (motorSet != selectedMotorSet) { + select(selectMotor(motorSet)); + } + } else { + log.info(Markers.USER_MARKER, "Selected table row " + row + ", nothing selected"); } } - } - }); - - - JScrollPane scrollpane = new JScrollPane(); - scrollpane.setViewportView(table); - panel.add(scrollpane, "grow, width :500:, height :300:, spanx, wrap para"); - + }); + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { + if (dialog != null) { + dialog.close(true); + } + } + } + }); + + JScrollPane scrollpane = new JScrollPane(); + scrollpane.setViewportView(table); + panel.add(scrollpane, "grow, width :500:, height :300:, spanx, wrap para"); + + } + + //// Hide used motor files { final JCheckBox hideUsedBox = new JCheckBox(trans.get("TCMotorSelPan.checkbox.hideUsed")); GUIUtil.changeFontSize(hideUsedBox, -1); @@ -331,230 +323,53 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec }); panel.add(hideUsedBox, "gapleft para, spanx, growx, wrap para"); } - - scrollSelectionVisible(); - + //// Hide very similar thrust curves - hideSimilarBox = new JCheckBox(trans.get("TCMotorSelPan.checkbox.hideSimilar")); - GUIUtil.changeFontSize(hideSimilarBox, -1); - hideSimilarBox.setSelected(Application.getPreferences().getBoolean(net.sf.openrocket.startup.Preferences.MOTOR_HIDE_SIMILAR, true)); - hideSimilarBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Application.getPreferences().putBoolean(net.sf.openrocket.startup.Preferences.MOTOR_HIDE_SIMILAR, hideSimilarBox.isSelected()); - updateData(); - } - }); - panel.add(hideSimilarBox, "gapleft para, spanx, growx, wrap para"); - - // Motor mount diameter label - //// Motor mount diameter: - diameterLabel = new StyledLabel(); - panel.add(label, "gapright 30lp, spanx, split"); - + { + hideSimilarBox = new JCheckBox(trans.get("TCMotorSelPan.checkbox.hideSimilar")); + GUIUtil.changeFontSize(hideSimilarBox, -1); + hideSimilarBox.setSelected(Application.getPreferences().getBoolean(net.sf.openrocket.startup.Preferences.MOTOR_HIDE_SIMILAR, true)); + hideSimilarBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Application.getPreferences().putBoolean(net.sf.openrocket.startup.Preferences.MOTOR_HIDE_SIMILAR, hideSimilarBox.isSelected()); + updateData(); + } + }); + panel.add(hideSimilarBox, "gapleft para, spanx, growx, wrap para"); + } + // Vertical split this.add(panel, "grow"); this.add(new JSeparator(JSeparator.VERTICAL), "growy, gap para para"); - panel = new JPanel(new MigLayout("fill")); - - - - // Thrust curve selection - //// Select thrust curve: - curveSelectionLabel = new JLabel(trans.get("TCMotorSelPan.lbl.Selectthrustcurve")); - panel.add(curveSelectionLabel); - - curveSelectionModel = new DefaultComboBoxModel(); - curveSelectionBox = new JComboBox(curveSelectionModel); - curveSelectionBox.setRenderer(new CurveSelectionRenderer(curveSelectionBox.getRenderer())); - curveSelectionBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Object value = curveSelectionBox.getSelectedItem(); - if (value != null) { - select(((MotorHolder) value).getMotor()); - } - } - }); - panel.add(curveSelectionBox, "growx, wrap para"); - - // Ejection charge delay: - panel.add(new JLabel(trans.get("TCMotorSelPan.lbl.Ejectionchargedelay"))); - - delayBox = new JComboBox(); - delayBox.setEditable(true); - delayBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JComboBox cb = (JComboBox) e.getSource(); - String sel = (String) cb.getSelectedItem(); - //// None - if (sel.equalsIgnoreCase(trans.get("TCMotorSelPan.equalsIgnoreCase.None"))) { - selectedDelay = Motor.PLUGGED; - } else { - try { - selectedDelay = Double.parseDouble(sel); - } catch (NumberFormatException ignore) { - } - } - setDelays(false); - } - }); - panel.add(delayBox, "growx, wrap rel"); - //// (Number of seconds or \"None\") - panel.add(new StyledLabel(trans.get("TCMotorSelPan.lbl.NumberofsecondsorNone"), -3), "skip, wrap para"); - setDelays(false); - - - panel.add(new JSeparator(), "spanx, growx, wrap para"); - - - - // Thrust curve info - //// Total impulse: - panel.add(new JLabel(trans.get("TCMotorSelPan.lbl.Totalimpulse"))); - totalImpulseLabel = new JLabel(); - panel.add(totalImpulseLabel, "split"); - classificationLabel = new JLabel(); - classificationLabel.setEnabled(false); // Gray out - panel.add(classificationLabel, "gapleft unrel, wrap"); - - //// Avg. thrust: - panel.add(new JLabel(trans.get("TCMotorSelPan.lbl.Avgthrust"))); - avgThrustLabel = new JLabel(); - panel.add(avgThrustLabel, "wrap"); - - //// Max. thrust: - panel.add(new JLabel(trans.get("TCMotorSelPan.lbl.Maxthrust"))); - maxThrustLabel = new JLabel(); - panel.add(maxThrustLabel, "wrap"); - - //// Burn time: - panel.add(new JLabel(trans.get("TCMotorSelPan.lbl.Burntime"))); - burnTimeLabel = new JLabel(); - panel.add(burnTimeLabel, "wrap"); - - //// Launch mass: - panel.add(new JLabel(trans.get("TCMotorSelPan.lbl.Launchmass"))); - launchMassLabel = new JLabel(); - panel.add(launchMassLabel, "wrap"); - - //// Empty mass: - panel.add(new JLabel(trans.get("TCMotorSelPan.lbl.Emptymass"))); - emptyMassLabel = new JLabel(); - panel.add(emptyMassLabel, "wrap"); - - //// Data points: - panel.add(new JLabel(trans.get("TCMotorSelPan.lbl.Datapoints"))); - dataPointsLabel = new JLabel(); - panel.add(dataPointsLabel, "wrap para"); - - if (System.getProperty("openrocket.debug.motordigest") != null) { - //// Digest: - panel.add(new JLabel(trans.get("TCMotorSelPan.lbl.Digest"))); - digestLabel = new JLabel(); - panel.add(digestLabel, "w :300:, wrap para"); - } else { - digestLabel = null; - } - - - comment = new JTextArea(5, 5); - GUIUtil.changeFontSize(comment, -2); - withCommentFont = comment.getFont(); - noCommentFont = withCommentFont.deriveFont(Font.ITALIC); - comment.setLineWrap(true); - comment.setWrapStyleWord(true); - comment.setEditable(false); - scrollpane = new JScrollPane(comment); - panel.add(scrollpane, "spanx, growx, wrap para"); - - // Thrust curve plot - chart = ChartFactory.createXYLineChart( - null, // title - null, // xAxisLabel - null, // yAxisLabel - null, // dataset - PlotOrientation.VERTICAL, - false, // legend - false, // tooltips - false // urls - ); - - - // Add the data and formatting to the plot - XYPlot plot = chart.getXYPlot(); - - changeLabelFont(plot.getRangeAxis(), -2); - changeLabelFont(plot.getDomainAxis(), -2); - - //// Thrust curve: - chart.setTitle(new TextTitle(trans.get("TCMotorSelPan.title.Thrustcurve"), this.getFont())); - chart.setBackgroundPaint(this.getBackground()); - plot.setBackgroundPaint(Color.WHITE); - plot.setDomainGridlinePaint(Color.LIGHT_GRAY); - plot.setRangeGridlinePaint(Color.LIGHT_GRAY); - - chartPanel = new ChartPanel(chart, - false, // properties - false, // save - false, // print - false, // zoom - false); // tooltips - chartPanel.setMouseZoomable(false); - chartPanel.setPopupMenu(null); - chartPanel.setMouseWheelEnabled(false); - chartPanel.setRangeZoomable(false); - chartPanel.setDomainZoomable(false); - - chartPanel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - chartPanel.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (selectedMotor == null || selectedMotorSet == null) - return; - if (e.getButton() == MouseEvent.BUTTON1) { - // Open plot dialog - List motors = getFilteredCurves(); - ThrustCurveMotorPlotDialog plotDialog = new ThrustCurveMotorPlotDialog(motors, - motors.indexOf(selectedMotor), - SwingUtilities.getWindowAncestor(ThrustCurveMotorSelectionPanel.this)); - plotDialog.setVisible(true); - } - } - }); - - JLayeredPane layer = new CustomLayeredPane(); - - layer.setBorder(BorderFactory.createLineBorder(Color.BLUE)); - - layer.add(chartPanel, (Integer) 0); - - zoomIcon = new JLabel(Icons.ZOOM_IN); - zoomIcon.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - layer.add(zoomIcon, (Integer) 1); - - - panel.add(layer, "width 300:300:, height 180:180:, grow, spanx"); - - this.add(panel, "grow"); + JTabbedPane rightSide = new JTabbedPane(); + rightSide.add(trans.get("TCMotorSelPan.btn.filter"), motorFilterPanel); + rightSide.add(trans.get("TCMotorSelPan.btn.details"), motorInformationPanel); + + this.add(rightSide); + // Update the panel data + scrollSelectionVisible(); updateData(); setDelays(false); - + } - + public void setMotorMountAndConfig( MotorMount mount, String currentConfig ) { double diameter = 0; + if ( mount != null ) { + diameter = mount.getMotorMountDiameter(); + } + if (currentConfig != null && mount != null) { MotorConfiguration motorConf = mount.getMotorConfiguration().get(currentConfig); selectedMotor = (ThrustCurveMotor) motorConf.getMotor(); selectedDelay = motorConf.getEjectionDelay(); diameter = mount.getMotorMountDiameter(); } - + // If current motor is not found in db, add a new ThrustCurveMotorSet containing it if (selectedMotor != null) { for (ThrustCurveMotorSet motorSet : database) { @@ -575,46 +390,43 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec updateData(); setDelays(true); - - diameterLabel.setText(trans.get("TCMotorSelPan.lbl.Motormountdia") + " " + - UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(0)); - - rowFilter.setMotorMount(mount); + + motorFilterPanel.setMotorMount(mount); scrollSelectionVisible(); } - + @Override public Motor getSelectedMotor() { return selectedMotor; } - - + + @Override public double getSelectedDelay() { return selectedDelay; } - - + + @Override public JComponent getDefaultFocus() { return searchField; } - + @Override public void selectedMotor(Motor motorSelection) { if (!(motorSelection instanceof ThrustCurveMotor)) { log.error("Received argument that was not ThrustCurveMotor: " + motorSelection); return; } - + ThrustCurveMotor motor = (ThrustCurveMotor) motorSelection; ThrustCurveMotorSet set = findMotorSet(motor); if (set == null) { log.error("Could not find set for motor:" + motorSelection); return; } - + // Store selected motor in preferences node, set all others to false Preferences prefs = ((SwingPreferences) Application.getPreferences()).getNode(net.sf.openrocket.startup.Preferences.PREFERRED_THRUST_CURVE_MOTOR_NODE); for (ThrustCurveMotor m : set.getMotors()) { @@ -622,34 +434,27 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec prefs.putBoolean(digest, m == motor); } } - + public void setCloseableDialog(CloseableDialog dialog) { this.dialog = dialog; } - - - - private void changeLabelFont(ValueAxis axis, float size) { - Font font = axis.getTickLabelFont(); - font = font.deriveFont(font.getSize2D() + size); - axis.setTickLabelFont(font); - } - - + + + /** * Called when a different motor is selected from within the panel. */ private void select(ThrustCurveMotor motor) { if (selectedMotor == motor) return; - + ThrustCurveMotorSet set = findMotorSet(motor); if (set == null) { throw new BugException("Could not find motor from database, motor=" + motor); } - + boolean updateDelays = (selectedMotorSet != set); - + selectedMotor = motor; selectedMotorSet = set; updateData(); @@ -657,46 +462,30 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec setDelays(true); } } - - + + private void updateData() { - + if (selectedMotorSet == null) { // No motor selected curveSelectionModel.removeAllElements(); curveSelectionBox.setEnabled(false); curveSelectionLabel.setEnabled(false); - totalImpulseLabel.setText(""); - totalImpulseLabel.setToolTipText(null); - classificationLabel.setText(""); - classificationLabel.setToolTipText(null); - avgThrustLabel.setText(""); - maxThrustLabel.setText(""); - burnTimeLabel.setText(""); - launchMassLabel.setText(""); - emptyMassLabel.setText(""); - dataPointsLabel.setText(""); - if (digestLabel != null) { - digestLabel.setText(""); - } - setComment(""); - chart.getXYPlot().setDataset(new XYSeriesCollection()); + motorInformationPanel.clearData(); return; } - - + // Check which thrust curves to display List motors = getFilteredCurves(); final int index = motors.indexOf(selectedMotor); - - + // Update the thrust curve selection box curveSelectionModel.removeAllElements(); for (int i = 0; i < motors.size(); i++) { curveSelectionModel.addElement(new MotorHolder(motors.get(i), i)); } curveSelectionBox.setSelectedIndex(index); - + if (motors.size() > 1) { curveSelectionBox.setEnabled(true); curveSelectionLabel.setEnabled(true); @@ -705,60 +494,11 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec curveSelectionLabel.setEnabled(false); } - - // Update thrust curve data - double impulse = selectedMotor.getTotalImpulseEstimate(); - MotorClass mc = MotorClass.getMotorClass(impulse); - totalImpulseLabel.setText(UnitGroup.UNITS_IMPULSE.getDefaultUnit().toStringUnit(impulse)); - classificationLabel.setText("(" + mc.getDescription(impulse) + ")"); - totalImpulseLabel.setToolTipText(mc.getClassDescription()); - classificationLabel.setToolTipText(mc.getClassDescription()); - - avgThrustLabel.setText(UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit( - selectedMotor.getAverageThrustEstimate())); - maxThrustLabel.setText(UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit( - selectedMotor.getMaxThrustEstimate())); - burnTimeLabel.setText(UnitGroup.UNITS_SHORT_TIME.getDefaultUnit().toStringUnit( - selectedMotor.getBurnTimeEstimate())); - launchMassLabel.setText(UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit( - selectedMotor.getLaunchCG().weight)); - emptyMassLabel.setText(UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit( - selectedMotor.getEmptyCG().weight)); - dataPointsLabel.setText("" + (selectedMotor.getTimePoints().length - 1)); - if (digestLabel != null) { - digestLabel.setText(selectedMotor.getDigest()); - } - - setComment(selectedMotor.getDescription()); - - - // Update the plot - XYPlot plot = chart.getXYPlot(); - - XYSeriesCollection dataset = new XYSeriesCollection(); - for (int i = 0; i < motors.size(); i++) { - ThrustCurveMotor m = motors.get(i); - - //// Thrust - XYSeries series = new XYSeries(trans.get("TCMotorSelPan.title.Thrust") + " (" + i + ")"); - double[] time = m.getTimePoints(); - double[] thrust = m.getThrustPoints(); - - for (int j = 0; j < time.length; j++) { - series.add(time[j], thrust[j]); - } - - dataset.addSeries(series); - - boolean selected = (i == index); - plot.getRenderer().setSeriesStroke(i, new BasicStroke(selected ? 3 : 1)); - plot.getRenderer().setSeriesPaint(i, getColor(i)); - } - - plot.setDataset(dataset); + motorInformationPanel.updateData(motors, selectedMotor); + } - - private List getFilteredCurves() { + + List getFilteredCurves() { List motors = selectedMotorSet.getMotors(); if (hideSimilarBox.isSelected()) { List filtered = new ArrayList(motors.size()); @@ -768,7 +508,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec filtered.add(m); continue; } - + double similarity = MotorCorrelation.similarity(selectedMotor, m); log.debug("Motor similarity: " + similarity); if (similarity < MOTOR_SIMILARITY_THRESHOLD) { @@ -777,28 +517,13 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec } motors = filtered; } - + Collections.sort(motors, MOTOR_COMPARATOR); - + return motors; } - - - private void setComment(String s) { - s = s.trim(); - if (s.length() == 0) { - //// No description available. - comment.setText(trans.get("TCMotorSelPan.noDescription")); - comment.setFont(noCommentFont); - comment.setForeground(NO_COMMENT_COLOR); - } else { - comment.setText(s); - comment.setFont(withCommentFont); - comment.setForeground(WITH_COMMENT_COLOR); - } - comment.setCaretPosition(0); - } - + + private void scrollSelectionVisible() { if (selectedMotorSet != null) { int index = table.convertRowIndexToView(model.getIndex(selectedMotorSet)); @@ -809,13 +534,13 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec table.scrollRectToVisible(rect); } } - - + + public static Color getColor(int index) { return (Color) CURVE_COLORS[index % CURVE_COLORS.length]; } - - + + /** * Find the ThrustCurveMotorSet that contains a motor. * @@ -828,12 +553,12 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec return set; } } - + return null; } - - - + + + /** * Select the default motor from this ThrustCurveMotorSet. This uses primarily motors * that the user has previously used, and secondarily a heuristic method of selecting which @@ -849,8 +574,8 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec if (set.getMotorCount() == 1) { return set.getMotors().get(0); } - - + + // Find which motor has been used the most recently List list = set.getMotors(); Preferences prefs = ((SwingPreferences) Application.getPreferences()).getNode(net.sf.openrocket.startup.Preferences.PREFERRED_THRUST_CURVE_MOTOR_NODE); @@ -860,13 +585,13 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec return m; } } - + // No motor has been used Collections.sort(list, MOTOR_COMPARATOR); return list.get(0); } - - + + /** * Set the values in the delay combo box. If reset is true * then sets the selected value as the value closest to selectedDelay, otherwise @@ -874,25 +599,25 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec */ private void setDelays(boolean reset) { if (selectedMotor == null) { - + //// None delayBox.setModel(new DefaultComboBoxModel(new String[] { trans.get("TCMotorSelPan.delayBox.None") })); delayBox.setSelectedIndex(0); - + } else { - + List delays = selectedMotorSet.getDelays(); String[] delayStrings = new String[delays.size()]; double currentDelay = selectedDelay; // Store current setting locally - + for (int i = 0; i < delays.size(); i++) { //// None delayStrings[i] = ThrustCurveMotor.getDelayString(delays.get(i), trans.get("TCMotorSelPan.delayBox.None")); } delayBox.setModel(new DefaultComboBoxModel(delayStrings)); - + if (reset) { - + // Find and set the closest value double closest = Double.NaN; for (int i = 0; i < delays.size(); i++) { @@ -908,60 +633,43 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec } else { delayBox.setSelectedItem("None"); } - + } else { - + selectedDelay = currentDelay; //// None delayBox.setSelectedItem(ThrustCurveMotor.getDelayString(currentDelay, trans.get("TCMotorSelPan.delayBox.None"))); - + } - + } } - - - - + ////////////////////// - - + + private class CurveSelectionRenderer implements ListCellRenderer { - + private final ListCellRenderer renderer; - + public CurveSelectionRenderer(ListCellRenderer renderer) { this.renderer = renderer; } - + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - + Component c = renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value instanceof MotorHolder) { MotorHolder m = (MotorHolder) value; c.setForeground(getColor(m.getIndex())); } - + return c; } - - } - - - /** - * Custom layered pane that sets the bounds of the components on every layout. - */ - public class CustomLayeredPane extends JLayeredPane { - @Override - public void doLayout() { - synchronized (getTreeLock()) { - int w = getWidth(); - int h = getHeight(); - chartPanel.setBounds(0, 0, w, h); - zoomIcon.setBounds(w - ZOOM_ICON_POSITION_NEGATIVE_X, ZOOM_ICON_POSITION_POSITIVE_Y, 50, 50); - } - } + } + + } From 7221b6558e10c2506e273f9318e5d002df48b88d Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Fri, 4 Oct 2013 21:33:46 -0500 Subject: [PATCH 12/17] More cleanup. --- core/resources/l10n/messages.properties | 2 + .../motor/thrustcurve/MotorFilterPanel.java | 48 +++++++-- .../motor/thrustcurve/MotorRowFilter.java | 99 ++++++++++++------- .../ThrustCurveMotorSelectionPanel.java | 6 +- 4 files changed, 106 insertions(+), 49 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 55f9ece1a..09e96ae34 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -1090,6 +1090,8 @@ TCMotorSelPan.checkbox.hideSimilar = Hide very similar thrust curves TCMotorSelPan.checkbox.hideUsed = Hide motors already used in the mount TCMotorSelPan.btn.details = Show Details TCMotorSelPan.btn.filter = Filter Motors +TCMotorSelPan.MotorSize = Motor Dimensions +TCMotorSelPan.limitByLength = Limit motors to motor mount length TCMotorSelPan.SHOW_DESCRIPTIONS.desc1 = Show all motors TCMotorSelPan.SHOW_DESCRIPTIONS.desc2 = Show motors with diameter less than that of the motor mount TCMotorSelPan.SHOW_DESCRIPTIONS.desc3 = Show motors with diameter equal to that of the motor mount diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java index 3c706c430..f39f4f7e8 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java @@ -12,6 +12,7 @@ import java.util.List; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; @@ -34,6 +35,7 @@ import net.sf.openrocket.gui.util.SwingPreferences; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.motor.Manufacturer; import net.sf.openrocket.rocketcomponent.MotorMount; +import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.startup.Application; import net.sf.openrocket.unit.UnitGroup; @@ -48,7 +50,13 @@ public abstract class MotorFilterPanel extends JPanel { private final CheckList impulseCheckList; private final MotorRowFilter filter; - private final TitledBorder diameterTitleBorder; + + // Things we change the label on based on the MotorMount. + private final JCheckBox maximumLengthCheckBox; + private final JRadioButton showSmallerDiametersButton; + private final JRadioButton showExactDiametersButton; + + private Double mountLength; private final DoubleModel mountDiameter = new DoubleModel(1); private int showMode = SHOW_ALL; @@ -194,7 +202,7 @@ public abstract class MotorFilterPanel extends JPanel { // Diameter selection sub = new JPanel(new MigLayout("fill")); - diameterTitleBorder = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.DIAMETER")); + TitledBorder diameterTitleBorder = BorderFactory.createTitledBorder(trans.get("TCMotorSelPan.MotorSize")); GUIUtil.changeFontStyle(diameterTitleBorder, Font.BOLD); sub.setBorder(diameterTitleBorder); @@ -211,7 +219,7 @@ public abstract class MotorFilterPanel extends JPanel { showAllDiametersButton.setSelected( showMode == SHOW_ALL); sub.add(showAllDiametersButton, "growx,wrap"); - JRadioButton showSmallerDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc2") ); + showSmallerDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc2") ); showSmallerDiametersButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -224,7 +232,7 @@ public abstract class MotorFilterPanel extends JPanel { showSmallerDiametersButton.setSelected( showMode == SHOW_SMALLER); sub.add(showSmallerDiametersButton, "growx,wrap"); - JRadioButton showExactDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc3") ); + showExactDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc3") ); showExactDiametersButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -258,6 +266,23 @@ public abstract class MotorFilterPanel extends JPanel { sub.add(new UnitSelector(minDiameter)); sub.add(new BasicSlider(minDiameter.getSliderModel(0,0.5, mountDiameter)), "w 100lp, wrap"); } + + { + maximumLengthCheckBox = new JCheckBox(trans.get("TCMotorSelPan.limitByLength")); + maximumLengthCheckBox.addChangeListener( new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + if (maximumLengthCheckBox.isSelected() ) { + MotorFilterPanel.this.filter.setMaximumLength( mountLength ); + } else { + MotorFilterPanel.this.filter.setMaximumLength(null); + } + onSelectionChanged(); + } + + }); + sub.add(maximumLengthCheckBox); + } this.add(sub, "grow,wrap"); } @@ -267,13 +292,20 @@ public abstract class MotorFilterPanel extends JPanel { onSelectionChanged(); if ( mount == null ) { // Disable diameter controls? - diameterTitleBorder.setTitle(trans.get("TCurveMotorCol.DIAMETER")); + showSmallerDiametersButton.setText(trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc2")); + showExactDiametersButton.setText(trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc3")); + maximumLengthCheckBox.setText("Limit by length"); mountDiameter.setValue(1.0); + mountLength = null; } else { mountDiameter.setValue(mount.getMotorMountDiameter()); - diameterTitleBorder.setTitle(trans.get("TCurveMotorCol.DIAMETER") + " " - + trans.get("TCMotorSelPan.lbl.Motormountdia") + " " + - UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(mount.getMotorMountDiameter())); + mountLength = ((RocketComponent)mount).getLength(); + showSmallerDiametersButton.setText(trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc2") + + " " + UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(mount.getMotorMountDiameter())+ ")"); + showExactDiametersButton.setText(trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc3") + + " (" + UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(mount.getMotorMountDiameter())+ ")"); + maximumLengthCheckBox.setText("Limit by length" + + " (" + UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(((RocketComponent)mount).getLength()) +")"); } } diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java index 568dd31e1..513179f5f 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java @@ -21,43 +21,45 @@ import net.sf.openrocket.rocketcomponent.MotorMount; * Abstract adapter class. */ class MotorRowFilter extends RowFilter { - + public enum DiameterFilterControl { ALL, EXACT, SMALLER }; - + // configuration data used in the filter process private final ThrustCurveMotorDatabaseModel model; private Double diameter; private List usedMotors = new ArrayList(); - + // things which can be changed to modify filter behavior - + + private Double maximumLength; + // Limit motors based on minimum diameter private Double minimumDiameter; - + // Collection of strings which match text in the motor private List searchTerms = Collections. emptyList(); - + // Limit motors based on diameter of the motor mount private DiameterFilterControl diameterControl = DiameterFilterControl.ALL; - + // Boolean which hides motors in the usedMotors list private boolean hideUsedMotors = false; - + // List of manufacturers to exclude. private List excludedManufacturers = new ArrayList(); - + // List of ImpulseClasses to exclude. private List excludedImpulseClass = new ArrayList(); - + public MotorRowFilter(ThrustCurveMotorDatabaseModel model) { super(); this.model = model; } - + public void setMotorMount( MotorMount mount ) { if (mount != null) { this.diameter = mount.getMotorMountDiameter(); @@ -68,7 +70,7 @@ class MotorRowFilter extends RowFilter { this.diameter = null; } } - + public void setSearchTerms(final List searchTerms) { this.searchTerms = new ArrayList(); for (String s : searchTerms) { @@ -78,7 +80,15 @@ class MotorRowFilter extends RowFilter { } } } - + + Double getMaximumLength() { + return maximumLength; + } + + void setMaximumLength(Double maximumLength) { + this.maximumLength = maximumLength; + } + Double getMinimumDiameter() { return minimumDiameter; } @@ -94,11 +104,11 @@ class MotorRowFilter extends RowFilter { void setDiameterControl(DiameterFilterControl diameterControl) { this.diameterControl = diameterControl; } - + void setHideUsedMotors(boolean hideUsedMotors) { this.hideUsedMotors = hideUsedMotors; } - + List getExcludedManufacturers() { return excludedManufacturers; } @@ -107,19 +117,19 @@ class MotorRowFilter extends RowFilter { this.excludedManufacturers.clear(); this.excludedManufacturers.addAll(excludedManufacturers); } - + void setExcludedImpulseClasses(Collection excludedImpulseClasses ) { this.excludedImpulseClass.clear(); this.excludedImpulseClass.addAll(excludedImpulseClasses); } - + @Override public boolean include(RowFilter.Entry entry) { int index = entry.getIdentifier(); ThrustCurveMotorSet m = model.getMotorSet(index); - return filterManufacturers(m) && filterUsed(m) && filterByDiameter(m) && filterByString(m) && filterByImpulseClass(m); + return filterManufacturers(m) && filterUsed(m) && filterBySize(m) && filterByString(m) && filterByImpulseClass(m); } - + private boolean filterManufacturers(ThrustCurveMotorSet m) { if (excludedManufacturers.contains(m.getManufacturer())) { return false; @@ -127,7 +137,7 @@ class MotorRowFilter extends RowFilter { return true; } } - + private boolean filterUsed(ThrustCurveMotorSet m) { if (!hideUsedMotors) { return true; @@ -139,30 +149,43 @@ class MotorRowFilter extends RowFilter { } return true; } - - private boolean filterByDiameter(ThrustCurveMotorSet m) { - + + private boolean filterBySize(ThrustCurveMotorSet m) { + if ( minimumDiameter != null ) { if ( m.getDiameter() <= minimumDiameter - 0.0015 ) { return false; } } + + if (diameter != null) { + switch (diameterControl) { + default: + case ALL: + break; + case EXACT: + if ((m.getDiameter() <= diameter + 0.0004) && (m.getDiameter() >= diameter - 0.0015)) { + break; + } + return false; + case SMALLER: + if (m.getDiameter() <= diameter + 0.0004) { + break; + } + return false; + } + } - if (diameter == null) { - return true; - } - switch (diameterControl) { - default: - case ALL: - return true; - case EXACT: - return ((m.getDiameter() <= diameter + 0.0004) && (m.getDiameter() >= diameter - 0.0015)); - case SMALLER: - return (m.getDiameter() <= diameter + 0.0004); + if ( maximumLength != null ) { + if ( m.getLength() > maximumLength ) { + return false; + } } + + return true; } - - + + private boolean filterByString(ThrustCurveMotorSet m) { main: for (String s : searchTerms) { for (ThrustCurveMotorColumns col : ThrustCurveMotorColumns.values()) { @@ -172,9 +195,9 @@ class MotorRowFilter extends RowFilter { } return false; } - return true; + return true; } - + private boolean filterByImpulseClass(ThrustCurveMotorSet m) { for( ImpulseClass c : excludedImpulseClass ) { if (c.isIn(m) ) { diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java index 83b5e5b62..8e2016b07 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java @@ -305,7 +305,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec JScrollPane scrollpane = new JScrollPane(); scrollpane.setViewportView(table); - panel.add(scrollpane, "grow, width :500:, height :300:, spanx, wrap para"); + panel.add(scrollpane, "grow, width :500:, height :300:, spanx, wrap"); } @@ -321,7 +321,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec scrollSelectionVisible(); } }); - panel.add(hideUsedBox, "gapleft para, spanx, growx, wrap para"); + panel.add(hideUsedBox, "gapleft para, spanx, growx, wrap"); } //// Hide very similar thrust curves @@ -336,7 +336,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec updateData(); } }); - panel.add(hideSimilarBox, "gapleft para, spanx, growx, wrap para"); + panel.add(hideSimilarBox, "gapleft para, spanx, growx, wrap"); } // Vertical split From afcedf90f127a7f64e6e556eebcd48d8d224ca68 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Sat, 5 Oct 2013 15:43:12 -0500 Subject: [PATCH 13/17] Remove the show details button now that it's available in a tab. --- .../ThrustCurveMotorSelectionPanel.java | 28 ++----------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java index 8e2016b07..2091f33d5 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java @@ -144,7 +144,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec } //// GUI - JPanel panel = new JPanel(new MigLayout("fill","[][grow][]")); + JPanel panel = new JPanel(new MigLayout("fill","[][grow]")); this.add(panel, "grow"); //// Select thrust curve: @@ -165,30 +165,6 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec } }); panel.add(curveSelectionBox, "growx"); - - final JPopupMenu popup = new JPopupMenu(); - popup.add( motorInformationPanel ); - JButton showDetailsButton = new JButton(trans.get("TCMotorSelPan.btn.details")); - showDetailsButton.addMouseListener(new MouseListener() { - @Override - public void mouseClicked(MouseEvent e) { - } - @Override - public void mousePressed(MouseEvent e) { - } - @Override - public void mouseReleased(MouseEvent e) { - popup.show(e.getComponent(), e.getX(), e.getY()); - } - @Override - public void mouseEntered(MouseEvent e) { - } - @Override - public void mouseExited(MouseEvent e) { - } - }); - panel.add(showDetailsButton, "gapleft para, wrap"); - } // Ejection charge delay: @@ -214,7 +190,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec setDelays(false); } }); - panel.add(delayBox, "growx"); + panel.add(delayBox, "split 2, growx"); //// (Number of seconds or \"None\") panel.add(new StyledLabel(trans.get("TCMotorSelPan.lbl.NumberofsecondsorNone"), -3), "wrap para"); setDelays(false); From e5679259faa5c79983086aaf2aec32b598c475b2 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Mon, 7 Oct 2013 18:47:10 -0500 Subject: [PATCH 14/17] Rework the impulse and diameter to use a two thumbed slider. --- .../motor/thrustcurve/ImpulseClass.java | 13 +- .../motor/thrustcurve/MotorFilterPanel.java | 234 +++---- .../motor/thrustcurve/MotorRowFilter.java | 73 +-- .../openrocket/gui/widgets/MultiSlider.java | 553 ++++++++++++++++ .../openrocket/gui/widgets/MultiSliderUI.java | 612 ++++++++++++++++++ 5 files changed, 1301 insertions(+), 184 deletions(-) create mode 100644 swing/src/net/sf/openrocket/gui/widgets/MultiSlider.java create mode 100644 swing/src/net/sf/openrocket/gui/widgets/MultiSliderUI.java diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ImpulseClass.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ImpulseClass.java index 6b8fc6a9f..8f639c893 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ImpulseClass.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ImpulseClass.java @@ -1,9 +1,5 @@ package net.sf.openrocket.gui.dialogs.motor.thrustcurve; -import java.text.DecimalFormat; -import java.text.NumberFormat; - -import net.sf.openrocket.database.motor.ThrustCurveMotorSet; public enum ImpulseClass { @@ -32,10 +28,13 @@ public enum ImpulseClass { public String toString() { return name; } + + public double getLow() { + return low; + } - public boolean isIn( ThrustCurveMotorSet m ) { - long motorImpulse = m.getTotalImpuse(); - return motorImpulse >= low && motorImpulse <= high; + public double getHigh() { + return high; } private double low; diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java index f39f4f7e8..0cd62ef92 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java @@ -7,6 +7,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.Hashtable; import java.util.List; import javax.swing.BorderFactory; @@ -32,6 +33,7 @@ import net.sf.openrocket.gui.components.UnitSelector; import net.sf.openrocket.gui.util.CheckList; import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.gui.util.SwingPreferences; +import net.sf.openrocket.gui.widgets.MultiSlider; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.motor.Manufacturer; import net.sf.openrocket.rocketcomponent.MotorMount; @@ -45,43 +47,52 @@ public abstract class MotorFilterPanel extends JPanel { private static final Translator trans = Application.getTranslator(); + private static Hashtable diameterLabels = new Hashtable(); + private static double[] diameterValues = new double[] { + 0, + .013, + .018, + .024, + .029, + .038, + .054, + .075, + .098, + 1.000 + }; + static { + for( int i = 0; i< diameterValues.length; i++ ) { + if( i == diameterValues.length-1) { + diameterLabels.put( i, new JLabel("+")); + } else { + diameterLabels.put( i, new JLabel(UnitGroup.UNITS_MOTOR_DIMENSIONS.toString(diameterValues[i]))); + } + } + } + + private static Hashtable impulseLabels = new Hashtable(); + static { + int i =0; + for( ImpulseClass impulseClass : ImpulseClass.values() ) { + impulseLabels.put(i, new JLabel( impulseClass.name() )); + i++; + } + } + private final CheckList manufacturerCheckList; - private final CheckList impulseCheckList; - private final MotorRowFilter filter; - + // Things we change the label on based on the MotorMount. private final JCheckBox maximumLengthCheckBox; - private final JRadioButton showSmallerDiametersButton; - private final JRadioButton showExactDiametersButton; - - private Double mountLength; - private final DoubleModel mountDiameter = new DoubleModel(1); - - private int showMode = SHOW_ALL; + private final MultiSlider diameterSlider; - private static final int SHOW_ALL = 0; - private static final int SHOW_SMALLER = 1; - private static final int SHOW_EXACT = 2; - private static final int SHOW_MAX = 2; + private Double mountLength; public MotorFilterPanel(Collection allManufacturers, MotorRowFilter filter ) { super(new MigLayout("fill", "[grow]")); this.filter = filter; - showMode = Application.getPreferences().getChoice(net.sf.openrocket.startup.Preferences.MOTOR_DIAMETER_FILTER, MotorFilterPanel.SHOW_MAX, MotorFilterPanel.SHOW_EXACT); - switch( showMode ) { - case SHOW_ALL: - filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.ALL); - break; - case SHOW_EXACT: - filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.EXACT); - break; - case SHOW_SMALLER: - filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.SMALLER); - break; - } List unselectedManusFromPreferences = ((SwingPreferences) Application.getPreferences()).getExcludedMotorManufacturers(); filter.setExcludedManufacturers(unselectedManusFromPreferences); @@ -152,121 +163,64 @@ public abstract class MotorFilterPanel extends JPanel { this.add(sub,"grow, wrap"); // Impulse selection - sub = new JPanel(new MigLayout("fill")); - border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.TOTAL_IMPULSE")); - GUIUtil.changeFontStyle(border, Font.BOLD); - sub.setBorder(border); - - impulseCheckList = new CheckList.Builder().build(); - impulseCheckList.setData(Arrays.asList(ImpulseClass.values())); - impulseCheckList.checkAll(); - impulseCheckList.getModel().addListDataListener( new ListDataListener() { - @Override - public void intervalAdded(ListDataEvent e) { - } - @Override - public void intervalRemoved(ListDataEvent e) { - } - @Override - public void contentsChanged(ListDataEvent e) { - MotorFilterPanel.this.filter.setExcludedImpulseClasses( impulseCheckList.getUncheckedItems() ); - onSelectionChanged(); - } - - }); - - sub.add(new JScrollPane(impulseCheckList.getList()), "grow,wrap"); - - JButton clearImpulse = new JButton(trans.get("TCMotorSelPan.btn.checkNone")); - clearImpulse.addActionListener( new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - MotorFilterPanel.this.impulseCheckList.clearAll(); - - } - }); - sub.add(clearImpulse,"split 2"); - - JButton selectImpulse = new JButton(trans.get("TCMotorSelPan.btn.checkAll")); - selectImpulse.addActionListener( new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - MotorFilterPanel.this.impulseCheckList.checkAll(); - - } - }); - sub.add(selectImpulse,"wrap"); + { + sub = new JPanel(new MigLayout("fill")); + border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.TOTAL_IMPULSE")); + GUIUtil.changeFontStyle(border, Font.BOLD); + sub.setBorder(border); + final MultiSlider impulseSlider = new MultiSlider(MultiSlider.HORIZONTAL,0, ImpulseClass.values().length-1,0, ImpulseClass.values().length-1); + impulseSlider.setBounded(true); // thumbs cannot cross + impulseSlider.setMajorTickSpacing(1); + impulseSlider.setPaintTicks(true); + impulseSlider.setLabelTable(impulseLabels); + impulseSlider.setPaintLabels(true); + impulseSlider.addChangeListener( new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + int minimpulse = impulseSlider.getValueAt(0); + MotorFilterPanel.this.filter.setMinimumImpulse(ImpulseClass.values()[minimpulse]); + int maximpulse = impulseSlider.getValueAt(1); + MotorFilterPanel.this.filter.setMaximumImpulse(ImpulseClass.values()[maximpulse]); + onSelectionChanged(); + } + }); + sub.add( impulseSlider, "growx, wrap"); + } this.add(sub,"grow, wrap"); - + + // Diameter selection - sub = new JPanel(new MigLayout("fill")); TitledBorder diameterTitleBorder = BorderFactory.createTitledBorder(trans.get("TCMotorSelPan.MotorSize")); GUIUtil.changeFontStyle(diameterTitleBorder, Font.BOLD); sub.setBorder(diameterTitleBorder); - JRadioButton showAllDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc1") ); - showAllDiametersButton.addActionListener( new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - showMode = SHOW_ALL; - MotorFilterPanel.this.filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.ALL); - saveMotorDiameterMatchPrefence(); - onSelectionChanged(); - } - }); - showAllDiametersButton.setSelected( showMode == SHOW_ALL); - sub.add(showAllDiametersButton, "growx,wrap"); - - showSmallerDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc2") ); - showSmallerDiametersButton.addActionListener( new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - showMode = SHOW_SMALLER; - MotorFilterPanel.this.filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.SMALLER); - saveMotorDiameterMatchPrefence(); - onSelectionChanged(); - } - }); - showSmallerDiametersButton.setSelected( showMode == SHOW_SMALLER); - sub.add(showSmallerDiametersButton, "growx,wrap"); - - showExactDiametersButton = new JRadioButton( trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc3") ); - showExactDiametersButton.addActionListener( new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - showMode = SHOW_EXACT; - MotorFilterPanel.this.filter.setDiameterControl(MotorRowFilter.DiameterFilterControl.EXACT); - saveMotorDiameterMatchPrefence(); - onSelectionChanged(); - } - }); - showExactDiametersButton.setSelected( showMode == SHOW_EXACT ); - sub.add(showExactDiametersButton, "growx,wrap"); - ButtonGroup comboGroup = new ButtonGroup(); - comboGroup.add( showAllDiametersButton ); - comboGroup.add( showSmallerDiametersButton ); - comboGroup.add( showExactDiametersButton ); - { - sub.add( new JLabel("Minimum diameter"), "split 4"); - final DoubleModel minDiameter = new DoubleModel(0, UnitGroup.UNITS_MOTOR_DIMENSIONS, 0, .2); - minDiameter.addChangeListener( new ChangeListener() { + sub.add( new JLabel("Minimum diameter"), "split 2, wrap"); + diameterSlider = new MultiSlider(MultiSlider.HORIZONTAL,0, diameterValues.length-1, 0, diameterValues.length-1); + diameterSlider.setBounded(true); // thumbs cannot cross + diameterSlider.setMajorTickSpacing(1); + diameterSlider.setPaintTicks(true); + diameterSlider.setLabelTable(diameterLabels); + diameterSlider.setPaintLabels(true); + diameterSlider.addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { - MotorFilterPanel.this.filter.setMinimumDiameter(minDiameter.getValue()); + int minDiameter = diameterSlider.getValueAt(0); + MotorFilterPanel.this.filter.setMinimumDiameter(diameterValues[minDiameter]); + int maxDiameter = diameterSlider.getValueAt(1); + if( maxDiameter == diameterValues.length-1 ) { + MotorFilterPanel.this.filter.setMaximumDiameter(null); + } else { + MotorFilterPanel.this.filter.setMaximumDiameter(diameterValues[maxDiameter]); + } onSelectionChanged(); } }); - JSpinner spin = new JSpinner(minDiameter.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - sub.add(spin, "growx"); - - sub.add(new UnitSelector(minDiameter)); - sub.add(new BasicSlider(minDiameter.getSliderModel(0,0.5, mountDiameter)), "w 100lp, wrap"); + sub.add( diameterSlider, "growx, wrap"); } - + { maximumLengthCheckBox = new JCheckBox(trans.get("TCMotorSelPan.limitByLength")); maximumLengthCheckBox.addChangeListener( new ChangeListener() { @@ -279,7 +233,7 @@ public abstract class MotorFilterPanel extends JPanel { } onSelectionChanged(); } - + }); sub.add(maximumLengthCheckBox); } @@ -292,28 +246,30 @@ public abstract class MotorFilterPanel extends JPanel { onSelectionChanged(); if ( mount == null ) { // Disable diameter controls? - showSmallerDiametersButton.setText(trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc2")); - showExactDiametersButton.setText(trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc3")); maximumLengthCheckBox.setText("Limit by length"); - mountDiameter.setValue(1.0); mountLength = null; } else { - mountDiameter.setValue(mount.getMotorMountDiameter()); mountLength = ((RocketComponent)mount).getLength(); - showSmallerDiametersButton.setText(trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc2") - + " " + UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(mount.getMotorMountDiameter())+ ")"); - showExactDiametersButton.setText(trans.get("TCMotorSelPan.SHOW_DESCRIPTIONS.desc3") - + " (" + UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(mount.getMotorMountDiameter())+ ")"); + double mountDiameter = mount.getMotorMountDiameter(); + // find the next largest diameter + int i; + for( i =0; i< diameterValues.length; i++ ) { + if ( mountDiameter<= diameterValues[i] ) { + break; + } + } + if( i >= diameterValues.length-1 ) { + diameterSlider.setValueAt(1, diameterValues.length-1); + } else { + diameterSlider.setValueAt(1, i) ; + } + diameterSlider.setValueAt(1, i); maximumLengthCheckBox.setText("Limit by length" + " (" + UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(((RocketComponent)mount).getLength()) +")"); } } - private void saveMotorDiameterMatchPrefence() { - Application.getPreferences().putChoice("MotorDiameterMatch", showMode ); - } - public abstract void onSelectionChanged(); } diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java index 513179f5f..ca6dbeed7 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java @@ -22,15 +22,8 @@ import net.sf.openrocket.rocketcomponent.MotorMount; */ class MotorRowFilter extends RowFilter { - public enum DiameterFilterControl { - ALL, - EXACT, - SMALLER - }; - // configuration data used in the filter process private final ThrustCurveMotorDatabaseModel model; - private Double diameter; private List usedMotors = new ArrayList(); // things which can be changed to modify filter behavior @@ -39,21 +32,22 @@ class MotorRowFilter extends RowFilter { // Limit motors based on minimum diameter private Double minimumDiameter; + + private Double maximumDiameter; // Collection of strings which match text in the motor private List searchTerms = Collections. emptyList(); - // Limit motors based on diameter of the motor mount - private DiameterFilterControl diameterControl = DiameterFilterControl.ALL; - // Boolean which hides motors in the usedMotors list private boolean hideUsedMotors = false; // List of manufacturers to exclude. private List excludedManufacturers = new ArrayList(); - // List of ImpulseClasses to exclude. - private List excludedImpulseClass = new ArrayList(); + // Impulse class filtering + private ImpulseClass minimumImpulse; + private ImpulseClass maximumImpulse; + public MotorRowFilter(ThrustCurveMotorDatabaseModel model) { super(); @@ -62,12 +56,9 @@ class MotorRowFilter extends RowFilter { public void setMotorMount( MotorMount mount ) { if (mount != null) { - this.diameter = mount.getMotorMountDiameter(); for (MotorConfiguration m : mount.getMotorConfiguration()) { this.usedMotors.add((ThrustCurveMotor) m.getMotor()); } - } else { - this.diameter = null; } } @@ -97,12 +88,12 @@ class MotorRowFilter extends RowFilter { this.minimumDiameter = minimumDiameter; } - DiameterFilterControl getDiameterControl() { - return diameterControl; + Double getMaximumDiameter() { + return maximumDiameter; } - void setDiameterControl(DiameterFilterControl diameterControl) { - this.diameterControl = diameterControl; + void setMaximumDiameter(Double maximumDiameter) { + this.maximumDiameter = maximumDiameter; } void setHideUsedMotors(boolean hideUsedMotors) { @@ -118,9 +109,20 @@ class MotorRowFilter extends RowFilter { this.excludedManufacturers.addAll(excludedManufacturers); } - void setExcludedImpulseClasses(Collection excludedImpulseClasses ) { - this.excludedImpulseClass.clear(); - this.excludedImpulseClass.addAll(excludedImpulseClasses); + ImpulseClass getMinimumImpulse() { + return minimumImpulse; + } + + void setMinimumImpulse(ImpulseClass minimumImpulse) { + this.minimumImpulse = minimumImpulse; + } + + ImpulseClass getMaximumImpulse() { + return maximumImpulse; + } + + void setMaximumImpulse(ImpulseClass maximumImpulse) { + this.maximumImpulse = maximumImpulse; } @Override @@ -158,20 +160,8 @@ class MotorRowFilter extends RowFilter { } } - if (diameter != null) { - switch (diameterControl) { - default: - case ALL: - break; - case EXACT: - if ((m.getDiameter() <= diameter + 0.0004) && (m.getDiameter() >= diameter - 0.0015)) { - break; - } - return false; - case SMALLER: - if (m.getDiameter() <= diameter + 0.0004) { - break; - } + if ( maximumDiameter != null ) { + if ( m.getDiameter() >= maximumDiameter + 0.0004 ) { return false; } } @@ -199,11 +189,18 @@ class MotorRowFilter extends RowFilter { } private boolean filterByImpulseClass(ThrustCurveMotorSet m) { - for( ImpulseClass c : excludedImpulseClass ) { - if (c.isIn(m) ) { + if ( minimumImpulse != null ) { + if( m.getTotalImpuse() < minimumImpulse.getLow() ) { return false; } } + + if ( maximumImpulse != null ) { + if( m.getTotalImpuse() > maximumImpulse.getHigh() ) { + return false; + } + } + return true; } diff --git a/swing/src/net/sf/openrocket/gui/widgets/MultiSlider.java b/swing/src/net/sf/openrocket/gui/widgets/MultiSlider.java new file mode 100644 index 000000000..5b956c5a6 --- /dev/null +++ b/swing/src/net/sf/openrocket/gui/widgets/MultiSlider.java @@ -0,0 +1,553 @@ +package net.sf.openrocket.gui.widgets; +/* ------------------------------------------------------------------- + * GeoVISTA Center (Penn State, Dept. of Geography) + * + * Java source file for the class MultiSlider + * + * Copyright (c), 1999 - 2002, Masahiro Takatsuka and GeoVISTA Center + * All Rights Researved. + * + * Original Author: Masahiro Takatsuka + * $Author: eytanadar $ + * + * $Date: 2005/10/05 20:19:52 $ + * + * + * Reference: Document no: + * ___ ___ + * + * To Do: + * ___ + * + ------------------------------------------------------------------- */ + +/* --------------------------- Package ---------------------------- */ + +import java.awt.Color; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleState; +import javax.swing.BoundedRangeModel; +import javax.swing.DefaultBoundedRangeModel; +import javax.swing.JComponent; +import javax.swing.JSlider; +import javax.swing.plaf.SliderUI; + +/*==================================================================== + Implementation of class MultiSlider + ====================================================================*/ +/*** + * A component that lets the user graphically select values by slding + * multiple thumbs within a bounded interval. MultiSlider inherits all + * fields and methods from javax.swing.JSlider. + *

+ * + * @version $Revision: 1.1 $ + * @author Masahiro Takatsuka (masa@jbeans.net) + * @see JSlider + */ + +public class MultiSlider extends JSlider { + /*** + * @see #getUIClassID + * @see #readObject + */ + private static final String uiClassID = "MultiSliderUI"; + + /*** + * An array of data models that handle the numeric maximum values, + * minimum values, and current-position values for the multi slider. + */ + private BoundedRangeModel[] sliderModels; + + /*** + * If it is true, a thumb is bounded by adjacent thumbs. + */ + private boolean bounded = false; + + /*** + * This is a color to paint the current thumb + */ + private Color currentThumbColor = Color.red; + + transient private int valueBeforeStateChange; + + /*** + * Creates a slider with the specified orientation and the + * specified mimimum, maximum, and initial values. + * + * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL + * + * @see #setOrientation + * @see #setMinimum + * @see #setMaximum + * @see #setValue + */ + public MultiSlider(int orientation, int min, int max, + int val1, int val2) { + checkOrientation(orientation); + this.orientation = orientation; + setNumberOfThumbs(min,max,new int[]{val1,val2}); + } + + /*** + * Creates a slider with the specified orientation and the + * specified mimimum, maximum, and the number of thumbs. + * + * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL + * + * @see #setOrientation + * @see #setMinimum + * @see #setMaximum + * @see #setValue + */ + public MultiSlider(int orientation, int min, int max) { + checkOrientation(orientation); + this.orientation = orientation; + setNumberOfThumbs(min, max, 2); + } + + /*** + * Creates a horizontal slider with the range 0 to 100 and + * an intitial value of 50. + */ + public MultiSlider() { + this(HORIZONTAL, 0, 100); + } + + + /*** + * Creates a slider using the specified orientation with the + * range 0 to 100 and an intitial value of 50. + */ + public MultiSlider(int orientation) { + this(orientation, 0, 100); + } + + + /*** + * Creates a horizontal slider using the specified min and max + * with an intitial value of 50. + */ + public MultiSlider(int min, int max) { + this(HORIZONTAL, min, max); + } + + public void setCurrentThumbColor(Color c) { + this.currentThumbColor = c; + } + + public Color getCurrentThumbColor() { + return this.currentThumbColor; + } + + public int getTrackBuffer() { + return ((MultiSliderUI) this.ui).getTrackBuffer(); + } + + /*** + * Validates the orientation parameter. + */ + private void checkOrientation(int orientation) { + switch (orientation) { + case VERTICAL: + case HORIZONTAL: + break; + default: + throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL"); + } + } + + /*** + * Notification from the UIFactory that the L&F has changed. + * Called to replace the UI with the latest version from the + * default UIFactory. + * + * @see JComponent#updateUI + */ + public void updateUI() { + updateLabelUIs(); + MultiSliderUI ui = new MultiSliderUI(); + if (this.sliderModels != null) { + ui.setThumbCount(this.sliderModels.length); + } + setUI((SliderUI) ui); + } + + /*** + * Returns the number of thumbs in the slider. + */ + public int getNumberOfThumbs() { + return this.sliderModels.length; + } + + /*** + * Sets the number of thumbs with the specified parameters. + */ + private void setNumberOfThumbs(int min, int max, int num, boolean useEndPoints) { + int [] values = createDefaultValues(min, max, num, useEndPoints); + setNumberOfThumbs(min, max, values); + } + + /*** + * Sets the number of thumbs with the specified parameters. + */ + private void setNumberOfThumbs(int min, int max, int num) { + setNumberOfThumbs(min, max, num, false); + } + + /*** + * Sets the number of thumbs with the specified parameters. + */ + private void setNumberOfThumbs(int min, int max, int[] values) { + if (values == null || values.length < 1) { + values = new int[] {50}; + } + int num = values.length; + this.sliderModels = new BoundedRangeModel[num]; + for (int i = 0; i < num; i++) { + this.sliderModels[i] = new DefaultBoundedRangeModel(values[i], 0, min, max); + this.sliderModels[i].addChangeListener(changeListener); + } + updateUI(); + } + + /*** + * Sets the number of thumbs. + */ + private void setNumberOfThumbs(int num) { + setNumberOfThumbs(num, false); + } + + /*** + * Sets the number of thumbs. + */ + private void setNumberOfThumbs(int num, boolean useEndPoints) { + if (getNumberOfThumbs() != num) { + setNumberOfThumbs(getMinimum(), getMaximum(), num, useEndPoints); + } + } + + /*** + * Sets the number of thumbs by specifying the initial values. + */ + private void setNumberOfThumbs(int[] values) { + setNumberOfThumbs(getMinimum(), getMaximum(), values); + } + + /*** + * creates evenly spaced values for thumbs. + */ + private int[] createDefaultValues(int min, int max, int num_of_values, boolean useEndPoints) { + int[] values = new int[num_of_values]; + int range = max - min; + + if (!useEndPoints) { + int step = range / (num_of_values + 1); + for (int i = 0; i < num_of_values; i++) { + values[i] = min + (i + 1) * step; + } + } else { + if (num_of_values < 1) { + return new int[0]; + } + values[0] = getMinimum(); + values[num_of_values - 1] = getMaximum(); + int[] def = createDefaultValues(getMinimum(), getMaximum(), num_of_values - 2, false); + for (int i = 0; i < def.length; i++) { + values[i + 1] = def[i]; + } + } + return values; + } + + /*** + * Returns the index number of currently operated thumb. + */ + public int getCurrentThumbIndex() { + return ((MultiSliderUI)ui).getCurrentIndex(); + } + + /*** + * Returns data model that handles the sliders three + * fundamental properties: minimum, maximum, value. + * + * @see #setModel + */ + public BoundedRangeModel getModel() { + return getModelAt(getCurrentThumbIndex()); + } + + /*** + * Returns data model that handles the sliders three + * fundamental properties: minimum, maximum, value. + * + * @see #setModel + */ + public BoundedRangeModel getModelAt(int index) { + if (this.sliderModels == null || index >= this.sliderModels.length) { + return null; + } + return this.sliderModels[index]; + } + + /*** + * Returns data model that handles the sliders three + * fundamental properties: minimum, maximum, value. + * + * @see #setModel + */ + public BoundedRangeModel[] getModels() { + return this.sliderModels; + } + + /*** + * Sets the model that handles the sliders three + * fundamental properties: minimum, maximum, value. + * + * @see #getModel + * @beaninfo + * bound: true + * description: The sliders BoundedRangeModel. + */ + public void setModel(BoundedRangeModel newModel) { + setModelAt(getCurrentThumbIndex(), newModel); + } + + /*** + * Sets the model that handles the sliders three + * fundamental properties: minimum, maximum, value. + * + * @see #getModel + * @beaninfo + * bound: true + * description: The sliders BoundedRangeModel. + */ + public void setModelAt(int index, BoundedRangeModel newModel) { + BoundedRangeModel oldModel = getModelAt(index); + + if (oldModel != null) { + oldModel.removeChangeListener(changeListener); + } + + this.sliderModels[index] = newModel; + + if (newModel != null) { + newModel.addChangeListener(changeListener); + + if (accessibleContext != null) { + accessibleContext.firePropertyChange( + AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, + (oldModel == null + ? null : new Integer(oldModel.getValue())), + (newModel == null + ? null : new Integer(newModel.getValue()))); + } + } + + firePropertyChange("model", oldModel, this.sliderModels[index]); + } + + /*** + * Sets the models minimum property. + * + * @see #getMinimum + * @see BoundedRangeModel#setMinimum + * @beaninfo + * bound: true + * preferred: true + * description: The sliders minimum value. + */ + public void setMinimum(int minimum) { + int count = getNumberOfThumbs(); + int oldMin = getModel().getMinimum(); + for (int i = 0; i < count; i++) { + getModelAt(i).setMinimum(minimum); + } + firePropertyChange( "minimum", new Integer( oldMin ), new Integer( minimum ) ); + } + + /*** + * Sets the models maximum property. + * + * @see #getMaximum + * @see BoundedRangeModel#setMaximum + * @beaninfo + * bound: true + * preferred: true + * description: The sliders maximum value. + */ + public void setMaximum(int maximum) { + int count = getNumberOfThumbs(); + int oldMax = getModel().getMaximum(); + for (int i = 0; i < count; i++) { + getModelAt(i).setMaximum(maximum); + } + firePropertyChange( "maximum", new Integer( oldMax ), new Integer( maximum ) ); + } + + /*** + * Returns the sliders value. + * @return the models value property + * @see #setValue + */ + public int getValue() { + return getValueAt(getCurrentThumbIndex()); + } + + /*** + * Returns the sliders value. + * @return the models value property + * @see #setValue + */ + public int getValueAt(int index) { + return getModelAt(index).getValue(); + } + + /*** + * Sets the sliders current value. This method just forwards + * the value to the model. + * + * @see #getValue + * @beaninfo + * preferred: true + * description: The sliders current value. + */ + public void setValue(int n) { + setValueAt(getCurrentThumbIndex(), n); + } + + /*** + * Sets the sliders current value. This method just forwards + * the value to the model. + * + * @see #getValue + * @beaninfo + * preferred: true + * description: The sliders current value. + */ + public void setValueAt(int index, int n) { + BoundedRangeModel m = getModelAt(index); + int oldValue = m.getValue(); + m.setValue(n); + + if (accessibleContext != null) { + accessibleContext.firePropertyChange( + AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, + new Integer(oldValue), + new Integer(m.getValue())); + } + } + + /*** + * True if the slider knob is being dragged. + * + * @return the value of the models valueIsAdjusting property + * @see #setValueIsAdjusting + */ + public boolean getValueIsAdjusting() { + boolean result = false; + int count = getNumberOfThumbs(); + for (int i = 0; i < count; i++) { + result = (result || getValueIsAdjustingAt(i)); + } + return result; + } + + /*** + * True if the slider knob is being dragged. + */ + public boolean getValueIsAdjustingAt(int index) { + return getModelAt(index).getValueIsAdjusting(); + } + + /*** + * Sets the models valueIsAdjusting property. Slider look and + * feel implementations should set this property to true when + * a knob drag begins, and to false when the drag ends. The + * slider model will not generate ChangeEvents while + * valueIsAdjusting is true. + * + * @see #getValueIsAdjusting + * @see BoundedRangeModel#setValueIsAdjusting + * @beaninfo + * expert: true + * description: True if the slider knob is being dragged. + */ + public void setValueIsAdjusting(boolean b) { + setValueIsAdjustingAt(getCurrentThumbIndex(), b); + } + + /*** + * Sets the models valueIsAdjusting property. Slider look and + * feel implementations should set this property to true when + * a knob drag begins, and to false when the drag ends. The + * slider model will not generate ChangeEvents while + * valueIsAdjusting is true. + */ + public void setValueIsAdjustingAt(int index, boolean b) { + BoundedRangeModel m = getModelAt(index); + boolean oldValue = m.getValueIsAdjusting(); + m.setValueIsAdjusting(b); + + if ((oldValue != b) && (accessibleContext != null)) { + accessibleContext.firePropertyChange( + AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + ((oldValue) ? AccessibleState.BUSY : null), + ((b) ? AccessibleState.BUSY : null)); + } + } + + /*** + * Sets the size of the range "covered" by the knob. Most look + * and feel implementations will change the value by this amount + * if the user clicks on either side of the knob. + * + * @see #getExtent + * @see BoundedRangeModel#setExtent + * @beaninfo + * expert: true + * description: Size of the range covered by the knob. + */ + public void setExtent(int extent) { + int count = getNumberOfThumbs(); + for (int i = 0; i < count; i++) { + getModelAt(i).setExtent(extent); + } + } + + + /*** + * Sets a bounded attribute of a slider thumb. + *

+     * 
+ * + * @param b + * @return void + */ + public void setBounded(boolean b) { + this.bounded = b; + } + + /*** + * Returns a bounded attribute of a slider thumb. + *
+     * 
+ * + * @return boolean + */ + public boolean isBounded() { + return this.bounded; + } + + public int getValueBeforeStateChange() { + return this.valueBeforeStateChange; + } + + void setValueBeforeStateChange(int v) { + this.valueBeforeStateChange = v; + } +} + + + diff --git a/swing/src/net/sf/openrocket/gui/widgets/MultiSliderUI.java b/swing/src/net/sf/openrocket/gui/widgets/MultiSliderUI.java new file mode 100644 index 000000000..5bbfa31d4 --- /dev/null +++ b/swing/src/net/sf/openrocket/gui/widgets/MultiSliderUI.java @@ -0,0 +1,612 @@ +package net.sf.openrocket.gui.widgets; +/* ------------------------------------------------------------------- + * GeoVISTA Center (Penn State, Dept. of Geography) + * + * Java source file for the class MultiSliderUI + * + * Copyright (c), 1999 - 2002, Masahiro Takatsuka and GeoVISTA Center + * All Rights Researved. + * + * Original Author: Masahiro Takatsuka + * $Author: eytanadar $ + * + * $Date: 2005/10/05 20:19:52 $ + * + * + * Reference: Document no: + * ___ ___ + * + * To Do: + * ___ + * +------------------------------------------------------------------- */ + +/* --------------------------- Package ---------------------------- */ +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.MouseEvent; + +import javax.swing.AbstractAction; +import javax.swing.BoundedRangeModel; +import javax.swing.JComponent; +import javax.swing.JSlider; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicSliderUI; +import javax.swing.plaf.metal.MetalSliderUI; + +/*==================================================================== + Implementation of class MultiSliderUI + ====================================================================*/ +/*** + * A Basic L&F implementation of SliderUI. + * + * @version $Revision: 1.1 $ + * @author Masahiro Takatsuka (masa@jbeans.net) + * @see MetalSliderUI + */ + +class MultiSliderUI extends BasicSliderUI { + private Rectangle[] thumbRects = null; + + private int thumbCount; + transient private int currentIndex = 0; + + transient private boolean isDragging; + transient private int[] minmaxIndices = new int[2]; + + /*** + * ComponentUI Interface Implementation methods + */ + public static ComponentUI createUI(JComponent b) { + return new MultiSliderUI(); + } + + /*** + * Construct a new MultiSliderUI object. + */ + public MultiSliderUI() { + super(null); + } + + int getTrackBuffer() { + return this.trackBuffer; + } + + /*** + * Sets the number of Thumbs. + */ + public void setThumbCount(int count) { + this.thumbCount = count; + } + + /*** + * Returns the index number of the thumb currently operated. + */ + protected int getCurrentIndex() { + return this.currentIndex; + } + + public void installUI(JComponent c) { + this.thumbRects = new Rectangle[this.thumbCount]; + for (int i = 0; i < this.thumbCount; i++) { + this.thumbRects[i] = new Rectangle(); + } + this.currentIndex = 0; + if (this.thumbCount > 0) { + thumbRect = this.thumbRects[this.currentIndex]; + } + super.installUI(c); + } + + public void uninstallUI(JComponent c) { + super.uninstallUI(c); + for (int i = 0; i < this.thumbCount; i++) { + this.thumbRects[i] = null; + } + this.thumbRects = null; + } + + protected void installListeners( JSlider slider ) { + slider.addMouseListener(trackListener); + slider.addMouseMotionListener(trackListener); + slider.addFocusListener(focusListener); + slider.addComponentListener(componentListener); + slider.addPropertyChangeListener( propertyChangeListener ); + for (int i = 0; i < this.thumbCount; i++) { + ((MultiSlider)slider).getModelAt(i).addChangeListener(changeListener); + } + } + + protected void uninstallListeners( JSlider slider ) { + slider.removeMouseListener(trackListener); + slider.removeMouseMotionListener(trackListener); + slider.removeFocusListener(focusListener); + slider.removeComponentListener(componentListener); + slider.removePropertyChangeListener( propertyChangeListener ); + for (int i = 0; i < this.thumbCount; i++) { + BoundedRangeModel model = ((MultiSlider)slider).getModelAt(i); + if (model != null) { + model.removeChangeListener(changeListener); + } + } + } + + protected void calculateThumbSize() { + Dimension size = getThumbSize(); + for (int i = 0; i < this.thumbCount; i++) { + this.thumbRects[i].setSize(size.width, size.height); + } + thumbRect.setSize(size.width, size.height); + } + + protected void calculateThumbLocation() { + MultiSlider slider = (MultiSlider) this.slider; + int majorTickSpacing = slider.getMajorTickSpacing(); + int minorTickSpacing = slider.getMinorTickSpacing(); + int tickSpacing = 0; + + if (minorTickSpacing > 0) { + tickSpacing = minorTickSpacing; + } else if (majorTickSpacing > 0) { + tickSpacing = majorTickSpacing; + } + for (int i = 0; i < this.thumbCount; i++) { + if (slider.getSnapToTicks()) { + int sliderValue = slider.getValueAt(i); + int snappedValue = sliderValue; + if (tickSpacing != 0) { + // If it's not on a tick, change the value + if ((sliderValue - slider.getMinimum()) % tickSpacing != 0 ) { + float temp = (float)(sliderValue - slider.getMinimum()) / (float)tickSpacing; + int whichTick = Math.round(temp); + snappedValue = slider.getMinimum() + (whichTick * tickSpacing); + } + + if( snappedValue != sliderValue ) { + slider.setValueAt(i, snappedValue); + } + } + } + + if (slider.getOrientation() == JSlider.HORIZONTAL) { + int valuePosition = xPositionForValue(slider.getValueAt(i)); + this.thumbRects[i].x = valuePosition - (this.thumbRects[i].width / 2); + this.thumbRects[i].y = trackRect.y; + } else { + int valuePosition = yPositionForValue(slider.getValueAt(i)); + this.thumbRects[i].x = trackRect.x; + this.thumbRects[i].y = valuePosition - (this.thumbRects[i].height / 2); + } + } + } + + public void paint(Graphics g, JComponent c) { + recalculateIfInsetsChanged(); + recalculateIfOrientationChanged(); + Rectangle clip = g.getClipBounds(); + + if (slider.getPaintTrack() && clip.intersects(trackRect)) { + paintTrack( g ); + } + if (slider.getPaintTicks() && clip.intersects(tickRect)) { + paintTicks( g ); + } + if (slider.getPaintLabels() && clip.intersects(labelRect)) { + paintLabels( g ); + } + if (slider.hasFocus() && clip.intersects(focusRect)) { + paintFocus( g ); + } + + // first paint unfocused thumbs. + for (int i = 0; i < this.thumbCount; i++) { + if (i != this.currentIndex) { + if (clip.intersects(this.thumbRects[i])) { + thumbRect = this.thumbRects[i]; + paintThumb(g); + } + } + } + // then paint currently focused thumb. + if (clip.intersects(this.thumbRects[this.currentIndex])) { + thumbRect = this.thumbRects[this.currentIndex]; + paintThumb(g); + } + } + + public void paintThumb(Graphics g) { + super.paintThumb(g); + } + + public void paintTrack(Graphics g) { + super.paintTrack(g); + } + + public void scrollByBlock(int direction) { + synchronized(slider) { + int oldValue = ((MultiSlider)slider).getValueAt(this.currentIndex); + int blockIncrement = slider.getMaximum() / 10; + int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL); + ((MultiSlider)slider).setValueAt(this.currentIndex, oldValue + delta); + } + } + + public void scrollByUnit(int direction) { + synchronized(slider) { + int oldValue = ((MultiSlider)slider).getValueAt(this.currentIndex); + int delta = 1 * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL); + ((MultiSlider)slider).setValueAt(this.currentIndex, oldValue + delta); + } + } + + protected TrackListener createTrackListener( JSlider slider ) { + return new MultiTrackListener(); + } + + /*** + * Track Listener Class tracks mouse movements. + */ + class MultiTrackListener extends BasicSliderUI.TrackListener { + int _trackTop; + int _trackBottom; + int _trackLeft; + int _trackRight; + transient private int[] firstXY = new int[2]; + + /*** + * If the mouse is pressed above the "thumb" component + * then reduce the scrollbars value by one page ("page up"), + * otherwise increase it by one page. If there is no + * thumb then page up if the mouse is in the upper half + * of the track. + */ + public void mousePressed(MouseEvent e) { + int[] neighbours = new int[2]; + boolean bounded = ((MultiSlider)slider).isBounded(); + if (!slider.isEnabled()) { + return; + } + + currentMouseX = e.getX(); + currentMouseY = e.getY(); + firstXY[0] = currentMouseX; + firstXY[1] = currentMouseY; + + slider.requestFocus(); + // Clicked in the Thumb area? + minmaxIndices[0] = -1; + minmaxIndices[1] = -1; + for (int i = 0; i < MultiSliderUI.this.thumbCount; i++) { + if (MultiSliderUI.this.thumbRects[i].contains(currentMouseX, currentMouseY)) { + if (minmaxIndices[0] == -1) { + minmaxIndices[0] = i; + MultiSliderUI.this.currentIndex = i; + } + if (minmaxIndices[1] < i) { + minmaxIndices[1] = i; + } + switch (slider.getOrientation()) { + case JSlider.VERTICAL: + offset = currentMouseY - MultiSliderUI.this.thumbRects[i].y; + break; + case JSlider.HORIZONTAL: + offset = currentMouseX - MultiSliderUI.this.thumbRects[i].x; + break; + } + MultiSliderUI.this.isDragging = true; + thumbRect = MultiSliderUI.this.thumbRects[i]; + if (bounded) { + neighbours[0] = ((i - 1) < 0) ? -1 : (i - 1); + neighbours[1] = ((i + 1) >= MultiSliderUI.this.thumbCount) ? -1 : (i + 1); + //findClosest(currentMouseX, currentMouseY, neighbours, i); + } else { + MultiSliderUI.this.currentIndex = i; + ((MultiSlider)slider).setValueIsAdjustingAt(i, true); + neighbours[0] = -1; + neighbours[1] = -1; + } + setThumbBounds(neighbours); + //return; + } + } + if (minmaxIndices[0] > -1) { + return; + } + + MultiSliderUI.this.currentIndex = findClosest(currentMouseX, currentMouseY, neighbours, -1); + thumbRect = MultiSliderUI.this.thumbRects[MultiSliderUI.this.currentIndex]; + MultiSliderUI.this.isDragging = false; + ((MultiSlider)slider).setValueIsAdjustingAt(MultiSliderUI.this.currentIndex, true); + + Dimension sbSize = slider.getSize(); + int direction = POSITIVE_SCROLL; + + switch (slider.getOrientation()) { + case JSlider.VERTICAL: + if (thumbRect.isEmpty()) { + int scrollbarCenter = sbSize.height / 2; + if (!drawInverted()) { + direction = (currentMouseY < scrollbarCenter) ? POSITIVE_SCROLL : NEGATIVE_SCROLL; + } else { + direction = (currentMouseY < scrollbarCenter) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; + } + } else { + int thumbY = thumbRect.y; + if (!drawInverted()) { + direction = (currentMouseY < thumbY) ? POSITIVE_SCROLL : NEGATIVE_SCROLL; + } else { + direction = (currentMouseY < thumbY) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; + } + } + break; + case JSlider.HORIZONTAL: + if (thumbRect.isEmpty() ) { + int scrollbarCenter = sbSize.width / 2; + if (!drawInverted()) { + direction = (currentMouseX < scrollbarCenter) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; + } else { + direction = (currentMouseX < scrollbarCenter) ? POSITIVE_SCROLL : NEGATIVE_SCROLL; + } + } else { + int thumbX = thumbRect.x; + if (!drawInverted()) { + direction = (currentMouseX < thumbX) ? NEGATIVE_SCROLL : POSITIVE_SCROLL; + } else { + direction = (currentMouseX < thumbX) ? POSITIVE_SCROLL : NEGATIVE_SCROLL; + } + } + break; + } + scrollDueToClickInTrack(direction); + Rectangle r = thumbRect; + if ( !r.contains(currentMouseX, currentMouseY) ) { + if (shouldScroll(direction) ) { + scrollTimer.stop(); + scrollListener.setDirection(direction); + scrollTimer.start(); + } + } + } + + /*** + * Sets a track bound for th thumb currently operated. + */ + private void setThumbBounds(int[] neighbours) { + int halfThumbWidth = thumbRect.width / 2; + int halfThumbHeight = thumbRect.height / 2; + + switch (slider.getOrientation()) { + case JSlider.VERTICAL: + _trackTop = (neighbours[1] == -1) ? trackRect.y : MultiSliderUI.this.thumbRects[neighbours[1]].y + halfThumbHeight; + _trackBottom = (neighbours[0] == -1) ? trackRect.y + (trackRect.height - 1) : MultiSliderUI.this.thumbRects[neighbours[0]].y + halfThumbHeight; + break; + case JSlider.HORIZONTAL: + _trackLeft = (neighbours[0] == -1) ? trackRect.x : MultiSliderUI.this.thumbRects[neighbours[0]].x + halfThumbWidth; + _trackRight = (neighbours[1] == -1) ? trackRect.x + (trackRect.width - 1) : MultiSliderUI.this.thumbRects[neighbours[1]].x + halfThumbWidth; + break; + } + } + + /* + * this is a very lazy way to find the closest. One might want to + * implement a much faster algorithm. + */ + private int findClosest(int x, int y, int[] neighbours, int excluded) { + int orientation = slider.getOrientation(); + int rightmin = Integer.MAX_VALUE; // for dxw, dy + int leftmin = -Integer.MAX_VALUE; // for dx, dyh + int dx = 0; + int dxw = 0; + int dy = 0; + int dyh = 0; + neighbours[0] = -1; // left + neighbours[1] = -1; // right + for (int i = 0; i < MultiSliderUI.this.thumbCount; i++) { + if (i == excluded) { + continue; + } + switch (orientation) { + case JSlider.VERTICAL: + dy = MultiSliderUI.this.thumbRects[i].y - y; + dyh = (MultiSliderUI.this.thumbRects[i].y + MultiSliderUI.this.thumbRects[i].height) - y; + if (dyh <= 0) { + if (dyh > leftmin) { // has to be > and not >= + leftmin = dyh; + neighbours[0] = i; + } + } + if (dy >= 0) { + if (dy <= rightmin) { + rightmin = dy; + neighbours[1] = i; + } + } + break; + case JSlider.HORIZONTAL: + dx = MultiSliderUI.this.thumbRects[i].x - x; + dxw = (MultiSliderUI.this.thumbRects[i].x + MultiSliderUI.this.thumbRects[i].width) - x; + if (dxw <= 0) { + if (dxw >= leftmin) { + leftmin = dxw; + neighbours[0] = i; + } + } + if (dx >= 0) { + if (dx < rightmin) { // has to be < and not <= + rightmin = dx; + neighbours[1] = i; + } + } + break; + } + } + //System.out.println("neighbours = " + neighbours[0] + ", " + neighbours[1]); + int closest = (Math.abs(leftmin) <= Math.abs(rightmin)) ? neighbours[0] : neighbours[1]; + return (closest == -1) ? 0 : closest; + } + + /*** + * Set the models value to the position of the top/left + * of the thumb relative to the origin of the track. + */ + public void mouseDragged( MouseEvent e ) { + ((MultiSlider) MultiSliderUI.this.slider).setValueBeforeStateChange(((MultiSlider) MultiSliderUI.this.slider).getValueAt(MultiSliderUI.this.currentIndex)); + int thumbMiddle = 0; + boolean bounded = ((MultiSlider)slider).isBounded(); + + if (!slider.isEnabled()) { + return; + } + + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + if (! MultiSliderUI.this.isDragging) { + return; + } + + switch (slider.getOrientation()) { + case JSlider.VERTICAL: + int halfThumbHeight = thumbRect.height / 2; + int thumbTop = e.getY() - offset; + if (bounded) { + int[] neighbours = new int[2]; + int idx = -1; + int diff = e.getY() - firstXY[1]; + //System.out.println("diff = " + diff); + if (e.getY() - firstXY[1] > 0) { + idx = minmaxIndices[0]; + } else { + idx = minmaxIndices[1]; + } + minmaxIndices[0] = minmaxIndices[1] = idx; + //System.out.println("idx = " + idx); + if (idx == -1) { + break; + } + + //System.out.println("thumbTop = " + thumbTop); + neighbours[0] = ((idx - 1) < 0) ? -1 : (idx - 1); + neighbours[1] = ((idx + 1) >= MultiSliderUI.this.thumbCount) ? -1 : (idx + 1); + thumbRect = MultiSliderUI.this.thumbRects[idx]; + MultiSliderUI.this.currentIndex = idx; + ((MultiSlider)slider).setValueIsAdjustingAt(idx, true); + setThumbBounds(neighbours); + } + + thumbTop = Math.max(thumbTop, _trackTop - halfThumbHeight); + thumbTop = Math.min(thumbTop, _trackBottom - halfThumbHeight); + + setThumbLocation(thumbRect.x, thumbTop); + + thumbMiddle = thumbTop + halfThumbHeight; + ((MultiSlider)slider).setValueAt(MultiSliderUI.this.currentIndex, valueForYPosition(thumbMiddle) ); + break; + case JSlider.HORIZONTAL: + int halfThumbWidth = thumbRect.width / 2; + int thumbLeft = e.getX() - offset; + if (bounded) { + int[] neighbours = new int[2]; + int idx = -1; + if (e.getX() - firstXY[0] <= 0) { + idx = minmaxIndices[0]; + } else { + idx = minmaxIndices[1]; + } + minmaxIndices[0] = minmaxIndices[1] = idx; + //System.out.println("idx = " + idx); + if (idx == -1) { + break; + } + //System.out.println("thumbLeft = " + thumbLeft); + neighbours[0] = ((idx - 1) < 0) ? -1 : (idx - 1); + neighbours[1] = ((idx + 1) >= MultiSliderUI.this.thumbCount) ? -1 : (idx + 1); + thumbRect = MultiSliderUI.this.thumbRects[idx]; + MultiSliderUI.this.currentIndex = idx; + ((MultiSlider)slider).setValueIsAdjustingAt(idx, true); + setThumbBounds(neighbours); + } + + thumbLeft = Math.max(thumbLeft, _trackLeft - halfThumbWidth); + thumbLeft = Math.min(thumbLeft, _trackRight - halfThumbWidth); + + setThumbLocation(thumbLeft, thumbRect.y); + + thumbMiddle = thumbLeft + halfThumbWidth; + + ((MultiSlider)slider).setValueAt(MultiSliderUI.this.currentIndex, valueForXPosition(thumbMiddle)); + break; + default: + return; + } + } + + public void mouseReleased(MouseEvent e) { + if (!slider.isEnabled()) { + return; + } + + offset = 0; + scrollTimer.stop(); + + if (slider.getSnapToTicks()) { + MultiSliderUI.this.isDragging = false; + ((MultiSlider)slider).setValueIsAdjustingAt(MultiSliderUI.this.currentIndex, false); + } else { + ((MultiSlider)slider).setValueIsAdjustingAt(MultiSliderUI.this.currentIndex, false); + MultiSliderUI.this.isDragging = false; + } + + slider.repaint(); + } + } + + /*** + * A static version of the above. + */ + static class SharedActionScroller extends AbstractAction { + int _dir; + boolean _block; + + public SharedActionScroller(int dir, boolean block) { + _dir = dir; + _block = block; + } + + public void actionPerformed(ActionEvent e) { + JSlider slider = (JSlider)e.getSource(); + MultiSliderUI ui = (MultiSliderUI)slider.getUI(); + if ( _dir == NEGATIVE_SCROLL || _dir == POSITIVE_SCROLL ) { + int realDir = _dir; + if (slider.getInverted()) { + realDir = _dir == NEGATIVE_SCROLL ? POSITIVE_SCROLL : NEGATIVE_SCROLL; + } + if (_block) { + ui.scrollByBlock(realDir); + } else { + ui.scrollByUnit(realDir); + } + } else { + if (slider.getInverted()) { + if (_dir == MIN_SCROLL) { + ((MultiSlider)slider).setValueAt(ui.currentIndex, + slider.getMaximum()); + } else if (_dir == MAX_SCROLL) { + ((MultiSlider)slider).setValueAt(ui.currentIndex, + slider.getMinimum()); + } + } else { + if (_dir == MIN_SCROLL) { + ((MultiSlider)slider).setValueAt(ui.currentIndex, + slider.getMinimum()); + } else if (_dir == MAX_SCROLL) { + ((MultiSlider)slider).setValueAt(ui.currentIndex, + slider.getMaximum()); + } + } + } + } + } +} From 3e57ef205d9ee67b953658ea36c7fb5b342aeaf0 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Mon, 7 Oct 2013 22:18:22 -0500 Subject: [PATCH 15/17] Be smart about displaying decimals. --- core/src/net/sf/openrocket/unit/Unit.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/net/sf/openrocket/unit/Unit.java b/core/src/net/sf/openrocket/unit/Unit.java index 7ac073a8d..a0522c2ba 100644 --- a/core/src/net/sf/openrocket/unit/Unit.java +++ b/core/src/net/sf/openrocket/unit/Unit.java @@ -103,6 +103,10 @@ public abstract class Unit { } val = roundForDecimalFormat(val); + // Check for approximate integer + if (Math.abs(val - Math.floor(val)) < 0.001) { + return intFormat.format(val); + } return decFormat.format(val); } From 2127908b2a2a3406fe1471f585c8bb020c46f30b Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Mon, 7 Oct 2013 22:19:07 -0500 Subject: [PATCH 16/17] Wire up motor length filter using ChangeListener and DoubleModel. --- core/resources/l10n/messages.properties | 8 +- .../motor/thrustcurve/MotorFilterPanel.java | 86 ++++++++++++------- .../motor/thrustcurve/MotorRowFilter.java | 65 ++++++++++---- 3 files changed, 109 insertions(+), 50 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 09e96ae34..82dbfbc26 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -1091,11 +1091,9 @@ TCMotorSelPan.checkbox.hideUsed = Hide motors already used in the mount TCMotorSelPan.btn.details = Show Details TCMotorSelPan.btn.filter = Filter Motors TCMotorSelPan.MotorSize = Motor Dimensions -TCMotorSelPan.limitByLength = Limit motors to motor mount length -TCMotorSelPan.SHOW_DESCRIPTIONS.desc1 = Show all motors -TCMotorSelPan.SHOW_DESCRIPTIONS.desc2 = Show motors with diameter less than that of the motor mount -TCMotorSelPan.SHOW_DESCRIPTIONS.desc3 = Show motors with diameter equal to that of the motor mount -TCMotorSelPan.lbl.Motormountdia = Motor mount diameter: +TCMotorSelPan.Diameter = Daimeter +TCMotorSelPan.Length = Length +TCMotorSelPan.MotorMountDimensions = Motor mount dimensions: TCMotorSelPan.lbl.Search = Search: TCMotorSelPan.lbl.Selectthrustcurve = Select thrust curve: TCMotorSelPan.lbl.Ejectionchargedelay = Ejection charge delay: diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java index 0cd62ef92..485c693a4 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java @@ -3,7 +3,6 @@ package net.sf.openrocket.gui.dialogs.motor.thrustcurve; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -11,12 +10,9 @@ import java.util.Hashtable; import java.util.List; import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; import javax.swing.JButton; -import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; -import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.border.TitledBorder; @@ -28,7 +24,6 @@ import javax.swing.event.ListDataListener; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.gui.SpinnerEditor; import net.sf.openrocket.gui.adaptors.DoubleModel; -import net.sf.openrocket.gui.components.BasicSlider; import net.sf.openrocket.gui.components.UnitSelector; import net.sf.openrocket.gui.util.CheckList; import net.sf.openrocket.gui.util.GUIUtil; @@ -84,11 +79,10 @@ public abstract class MotorFilterPanel extends JPanel { private final MotorRowFilter filter; // Things we change the label on based on the MotorMount. - private final JCheckBox maximumLengthCheckBox; + private final JLabel motorMountDimension; + private final MultiSlider lengthSlider; private final MultiSlider diameterSlider; - private Double mountLength; - public MotorFilterPanel(Collection allManufacturers, MotorRowFilter filter ) { super(new MigLayout("fill", "[grow]")); this.filter = filter; @@ -188,16 +182,19 @@ public abstract class MotorFilterPanel extends JPanel { sub.add( impulseSlider, "growx, wrap"); } this.add(sub,"grow, wrap"); - - + + // Diameter selection sub = new JPanel(new MigLayout("fill")); TitledBorder diameterTitleBorder = BorderFactory.createTitledBorder(trans.get("TCMotorSelPan.MotorSize")); GUIUtil.changeFontStyle(diameterTitleBorder, Font.BOLD); sub.setBorder(diameterTitleBorder); + motorMountDimension = new JLabel(); + GUIUtil.changeFontSize(motorMountDimension, -1); + sub.add(motorMountDimension,"growx,wrap"); { - sub.add( new JLabel("Minimum diameter"), "split 2, wrap"); + sub.add( new JLabel("Diameter"), "split 2, wrap"); diameterSlider = new MultiSlider(MultiSlider.HORIZONTAL,0, diameterValues.length-1, 0, diameterValues.length-1); diameterSlider.setBounded(true); // thumbs cannot cross diameterSlider.setMajorTickSpacing(1); @@ -222,20 +219,49 @@ public abstract class MotorFilterPanel extends JPanel { } { - maximumLengthCheckBox = new JCheckBox(trans.get("TCMotorSelPan.limitByLength")); - maximumLengthCheckBox.addChangeListener( new ChangeListener() { + sub.add( new JLabel(trans.get("TCMotorSelPan.Length")), "split 2, wrap"); + + final DoubleModel minimumLength = new DoubleModel(filter, "MinimumLength", UnitGroup.UNITS_MOTOR_DIMENSIONS, 0); + final DoubleModel maximumLength = new DoubleModel(filter, "MaximumLength", UnitGroup.UNITS_MOTOR_DIMENSIONS, 0); + + JSpinner spin = new JSpinner(minimumLength.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + sub.add(spin, "split 5, growx"); + + sub.add(new UnitSelector(minimumLength), ""); + + lengthSlider = new MultiSlider(MultiSlider.HORIZONTAL,0, 1000, 0, 1000); + lengthSlider.setBounded(true); // thumbs cannot cross + lengthSlider.setMajorTickSpacing(100); + lengthSlider.setPaintTicks(true); + lengthSlider.setLabelTable(diameterLabels); + lengthSlider.addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { - if (maximumLengthCheckBox.isSelected() ) { - MotorFilterPanel.this.filter.setMaximumLength( mountLength ); - } else { - MotorFilterPanel.this.filter.setMaximumLength(null); - } + int minLength = lengthSlider.getValueAt(0); + minimumLength.setValue(minLength/1000.0); + int maxLength = lengthSlider.getValueAt(1); + maximumLength.setValue(maxLength/1000.0); onSelectionChanged(); } + }); + + minimumLength.addChangeListener( new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + lengthSlider.setValueAt(0, (int)(1000* minimumLength.getValue())); + lengthSlider.setValueAt(1, (int) (1000* maximumLength.getValue())); + } }); - sub.add(maximumLengthCheckBox); + + sub.add( lengthSlider, "growx"); + + spin = new JSpinner(maximumLength.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + sub.add(spin, "growx"); + + sub.add(new UnitSelector(maximumLength), "wrap"); } this.add(sub, "grow,wrap"); @@ -246,27 +272,27 @@ public abstract class MotorFilterPanel extends JPanel { onSelectionChanged(); if ( mount == null ) { // Disable diameter controls? - maximumLengthCheckBox.setText("Limit by length"); - mountLength = null; + lengthSlider.setValueAt(1, 1000); + motorMountDimension.setText(""); } else { - mountLength = ((RocketComponent)mount).getLength(); + double mountLength = ((RocketComponent)mount).getLength(); + lengthSlider.setValueAt(1, (int) Math.min(1000,Math.round(1000*mountLength))); + double mountDiameter = mount.getMotorMountDiameter(); // find the next largest diameter int i; for( i =0; i< diameterValues.length; i++ ) { - if ( mountDiameter<= diameterValues[i] ) { + if ( mountDiameter< diameterValues[i] ) { break; } } - if( i >= diameterValues.length-1 ) { - diameterSlider.setValueAt(1, diameterValues.length-1); - } else { - diameterSlider.setValueAt(1, i) ; + if (i >= diameterValues.length ) { + i--; } - diameterSlider.setValueAt(1, i); - maximumLengthCheckBox.setText("Limit by length" - + " (" + UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(((RocketComponent)mount).getLength()) +")"); + diameterSlider.setValueAt(1, i-1); + motorMountDimension.setText( trans.get("TCMotorSelPan.MotorMountDimensions") + " " + + UnitGroup.UNITS_MOTOR_DIMENSIONS.toStringUnit(mountDiameter)+ "x" + UnitGroup.UNITS_MOTOR_DIMENSIONS.toStringUnit(mountLength)); } } diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java index ca6dbeed7..b4ac85e9f 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorRowFilter.java @@ -14,25 +14,32 @@ import net.sf.openrocket.motor.Manufacturer; import net.sf.openrocket.motor.ThrustCurveMotor; import net.sf.openrocket.rocketcomponent.MotorConfiguration; import net.sf.openrocket.rocketcomponent.MotorMount; +import net.sf.openrocket.util.AbstractChangeSource; +import net.sf.openrocket.util.ChangeSource; +import net.sf.openrocket.util.StateChangeListener; //////// Row filters /** * Abstract adapter class. */ -class MotorRowFilter extends RowFilter { +public class MotorRowFilter extends RowFilter implements ChangeSource { // configuration data used in the filter process private final ThrustCurveMotorDatabaseModel model; private List usedMotors = new ArrayList(); + private final AbstractChangeSource changeSourceDelegate = new AbstractChangeSource(); + private final Object change = new Object(); + // things which can be changed to modify filter behavior - private Double maximumLength; + // Limit motors based on length + private double minimumLength = 0; + private double maximumLength = Double.MAX_VALUE; - // Limit motors based on minimum diameter + // Limit motors based on diameter private Double minimumDiameter; - private Double maximumDiameter; // Collection of strings which match text in the motor @@ -47,7 +54,7 @@ class MotorRowFilter extends RowFilter { // Impulse class filtering private ImpulseClass minimumImpulse; private ImpulseClass maximumImpulse; - + public MotorRowFilter(ThrustCurveMotorDatabaseModel model) { super(); @@ -72,12 +79,26 @@ class MotorRowFilter extends RowFilter { } } - Double getMaximumLength() { + public double getMinimumLength() { + return minimumLength; + } + + public void setMinimumLength(double minimumLength) { + if ( this.minimumLength != minimumLength ) { + this.minimumLength = minimumLength; + fireChangeEvent(change); + } + } + + public double getMaximumLength() { return maximumLength; } - void setMaximumLength(Double maximumLength) { - this.maximumLength = maximumLength; + public void setMaximumLength(double maximumLength) { + if ( this.maximumLength != maximumLength ) { + this.maximumLength = maximumLength; + fireChangeEvent(change); + } } Double getMinimumDiameter() { @@ -165,13 +186,15 @@ class MotorRowFilter extends RowFilter { return false; } } - - if ( maximumLength != null ) { - if ( m.getLength() > maximumLength ) { - return false; - } + + if ( m.getLength() > maximumLength ) { + return false; } - + + if ( m.getLength() < minimumLength ) { + return false; + } + return true; } @@ -194,7 +217,7 @@ class MotorRowFilter extends RowFilter { return false; } } - + if ( maximumImpulse != null ) { if( m.getTotalImpuse() > maximumImpulse.getHigh() ) { return false; @@ -204,4 +227,16 @@ class MotorRowFilter extends RowFilter { return true; } + public final void addChangeListener(StateChangeListener listener) { + changeSourceDelegate.addChangeListener(listener); + } + + public final void removeChangeListener(StateChangeListener listener) { + changeSourceDelegate.removeChangeListener(listener); + } + + public void fireChangeEvent(Object source) { + changeSourceDelegate.fireChangeEvent(source); + } + } From 9420390ea8a2e21fc517ec9ff6add0c50d6699db Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Tue, 8 Oct 2013 21:08:05 -0500 Subject: [PATCH 17/17] Final tweaking of motor filter in the MotorChooserPanel. --- .../gui/dialogs/motor/MotorChooserDialog.java | 2 +- .../motor/thrustcurve/MotorFilterPanel.java | 18 +++- .../ThrustCurveMotorSelectionPanel.java | 85 ++++++++----------- 3 files changed, 53 insertions(+), 52 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java index a6718116f..5ff870e1b 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java @@ -39,7 +39,7 @@ public class MotorChooserDialog extends JDialog implements CloseableDialog { selectionPanel = new ThrustCurveMotorSelectionPanel(); - panel.add(selectionPanel, "grow, wrap para"); + panel.add(selectionPanel, "grow, wrap"); // OK / Cancel buttons diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java index 485c693a4..e23216b68 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorFilterPanel.java @@ -11,6 +11,7 @@ import java.util.List; import javax.swing.BorderFactory; import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -90,6 +91,21 @@ public abstract class MotorFilterPanel extends JPanel { List unselectedManusFromPreferences = ((SwingPreferences) Application.getPreferences()).getExcludedMotorManufacturers(); filter.setExcludedManufacturers(unselectedManusFromPreferences); + //// Hide used motor files + { + final JCheckBox hideUsedBox = new JCheckBox(trans.get("TCMotorSelPan.checkbox.hideUsed")); + GUIUtil.changeFontSize(hideUsedBox, -1); + hideUsedBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + MotorFilterPanel.this.filter.setHideUsedMotors(hideUsedBox.isSelected()); + onSelectionChanged(); + } + }); + this.add(hideUsedBox, "gapleft para, spanx, growx, wrap"); + } + + // Manufacturer selection JPanel sub = new JPanel(new MigLayout("fill")); TitledBorder border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.MANUFACTURER")); @@ -292,7 +308,7 @@ public abstract class MotorFilterPanel extends JPanel { diameterSlider.setValueAt(1, i-1); motorMountDimension.setText( trans.get("TCMotorSelPan.MotorMountDimensions") + " " + - UnitGroup.UNITS_MOTOR_DIMENSIONS.toStringUnit(mountDiameter)+ "x" + UnitGroup.UNITS_MOTOR_DIMENSIONS.toStringUnit(mountLength)); + UnitGroup.UNITS_MOTOR_DIMENSIONS.toStringUnit(mountDiameter)+ " x " + UnitGroup.UNITS_MOTOR_DIMENSIONS.toStringUnit(mountLength)); } } diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java index 2091f33d5..e12b07dd9 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java @@ -164,7 +164,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec } } }); - panel.add(curveSelectionBox, "growx"); + panel.add(curveSelectionBox, "growx, wrap"); } // Ejection charge delay: @@ -190,40 +190,25 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec setDelays(false); } }); - panel.add(delayBox, "split 2, growx"); + panel.add(delayBox, "growx,wrap"); //// (Number of seconds or \"None\") - panel.add(new StyledLabel(trans.get("TCMotorSelPan.lbl.NumberofsecondsorNone"), -3), "wrap para"); + panel.add(new StyledLabel(trans.get("TCMotorSelPan.lbl.NumberofsecondsorNone"), -3), "skip, wrap"); setDelays(false); } - // Search field + //// Hide very similar thrust curves { - //// Search: - StyledLabel label = new StyledLabel(trans.get("TCMotorSelPan.lbl.Search")); - panel.add(label); - searchField = new JTextField(); - searchField.getDocument().addDocumentListener(new DocumentListener() { + hideSimilarBox = new JCheckBox(trans.get("TCMotorSelPan.checkbox.hideSimilar")); + GUIUtil.changeFontSize(hideSimilarBox, -1); + hideSimilarBox.setSelected(Application.getPreferences().getBoolean(net.sf.openrocket.startup.Preferences.MOTOR_HIDE_SIMILAR, true)); + hideSimilarBox.addActionListener(new ActionListener() { @Override - public void changedUpdate(DocumentEvent e) { - update(); - } - @Override - public void insertUpdate(DocumentEvent e) { - update(); - } - @Override - public void removeUpdate(DocumentEvent e) { - update(); - } - private void update() { - String text = searchField.getText().trim(); - String[] split = text.split("\\s+"); - rowFilter.setSearchTerms(Arrays.asList(split)); - sorter.sort(); - scrollSelectionVisible(); + public void actionPerformed(ActionEvent e) { + Application.getPreferences().putBoolean(net.sf.openrocket.startup.Preferences.MOTOR_HIDE_SIMILAR, hideSimilarBox.isSelected()); + updateData(); } }); - panel.add(searchField, "span, growx, wrap"); + panel.add(hideSimilarBox, "gapleft para, spanx, growx, wrap"); } //// Motor selection table @@ -285,38 +270,38 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec } - //// Hide used motor files + // Search field { - final JCheckBox hideUsedBox = new JCheckBox(trans.get("TCMotorSelPan.checkbox.hideUsed")); - GUIUtil.changeFontSize(hideUsedBox, -1); - hideUsedBox.addActionListener(new ActionListener() { + //// Search: + StyledLabel label = new StyledLabel(trans.get("TCMotorSelPan.lbl.Search")); + panel.add(label); + searchField = new JTextField(); + searchField.getDocument().addDocumentListener(new DocumentListener() { @Override - public void actionPerformed(ActionEvent e) { - rowFilter.setHideUsedMotors(hideUsedBox.isSelected()); + public void changedUpdate(DocumentEvent e) { + update(); + } + @Override + public void insertUpdate(DocumentEvent e) { + update(); + } + @Override + public void removeUpdate(DocumentEvent e) { + update(); + } + private void update() { + String text = searchField.getText().trim(); + String[] split = text.split("\\s+"); + rowFilter.setSearchTerms(Arrays.asList(split)); sorter.sort(); scrollSelectionVisible(); } }); - panel.add(hideUsedBox, "gapleft para, spanx, growx, wrap"); - } - - //// Hide very similar thrust curves - { - hideSimilarBox = new JCheckBox(trans.get("TCMotorSelPan.checkbox.hideSimilar")); - GUIUtil.changeFontSize(hideSimilarBox, -1); - hideSimilarBox.setSelected(Application.getPreferences().getBoolean(net.sf.openrocket.startup.Preferences.MOTOR_HIDE_SIMILAR, true)); - hideSimilarBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Application.getPreferences().putBoolean(net.sf.openrocket.startup.Preferences.MOTOR_HIDE_SIMILAR, hideSimilarBox.isSelected()); - updateData(); - } - }); - panel.add(hideSimilarBox, "gapleft para, spanx, growx, wrap"); + panel.add(searchField, "span, growx"); } + this.add(panel, "grow"); // Vertical split - this.add(panel, "grow"); this.add(new JSeparator(JSeparator.VERTICAL), "growy, gap para para"); JTabbedPane rightSide = new JTabbedPane();