diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties
index 842f0fdc7..57645d9c8 100644
--- a/core/resources/l10n/messages.properties
+++ b/core/resources/l10n/messages.properties
@@ -949,8 +949,12 @@ CenteringRingCfg.tab.Generalproperties = General properties
!ComponentConfigDialog
ComponentCfgDlg.configuration = configuration
-ComponentCfgDlg.configuration1 =
+ComponentCfgDlg.MultiComponent = Multi-component
+ComponentCfgDlg.MultiComponentConfig = Multi-component configuration
+ComponentCfgDlg.MultiComponentEdit = Multi-component edit
+ComponentCfgDlg.MultiComponentEdit.ttip = You are editing the following components:
ComponentCfgDlg.Modify = Modify
+ComponentCfgDlg.ModifyComponents = Modify components
!StageConfig
StageConfig.tab.Separation = Separation
diff --git a/core/resources/l10n/messages_cs.properties b/core/resources/l10n/messages_cs.properties
index c6354d4a8..f5b5933f7 100644
--- a/core/resources/l10n/messages_cs.properties
+++ b/core/resources/l10n/messages_cs.properties
@@ -678,7 +678,6 @@ CenteringRingCfg.tab.Generalproperties = Obecn
!ComponentConfigDialog
ComponentCfgDlg.configuration = konfigurace
-ComponentCfgDlg.configuration1 =
ComponentCfgDlg.Modify = Uprav
!StageConfig
diff --git a/core/resources/l10n/messages_de.properties b/core/resources/l10n/messages_de.properties
index 442081510..45f91eda5 100644
--- a/core/resources/l10n/messages_de.properties
+++ b/core/resources/l10n/messages_de.properties
@@ -734,7 +734,6 @@ CenteringRingCfg.tab.Generalproperties = Allgemeine Eigenschaften
!ComponentConfigDialog
ComponentCfgDlg.configuration = Konfiguration
-ComponentCfgDlg.configuration1 =
ComponentCfgDlg.Modify = Verändern
!StageConfig
diff --git a/core/resources/l10n/messages_es.properties b/core/resources/l10n/messages_es.properties
index 9d0e5b2c3..255e26369 100644
--- a/core/resources/l10n/messages_es.properties
+++ b/core/resources/l10n/messages_es.properties
@@ -130,8 +130,7 @@ CompassSelectionButton.lbl.W = O
ComponentCfgDlg.Modify = Modificar
!ComponentConfigDialog
-ComponentCfgDlg.configuration =
-ComponentCfgDlg.configuration1 = Configuraci\u00f3n
+ComponentCfgDlg.configuration = Configuraci\u00f3n
ComponentIcons.Bodytube = Cuerpo tubular
ComponentIcons.Bulkhead = Disco de enganche
diff --git a/core/resources/l10n/messages_fr.properties b/core/resources/l10n/messages_fr.properties
index ab7fb5544..d4cee80d0 100644
--- a/core/resources/l10n/messages_fr.properties
+++ b/core/resources/l10n/messages_fr.properties
@@ -121,7 +121,6 @@ CompassSelectionButton.lbl.W = O
ComponentCfgDlg.Modify = Modifier
!ComponentConfigDialog
ComponentCfgDlg.configuration = configuration
-ComponentCfgDlg.configuration1 = configuration
ComponentIcons.Bodytube = Tube
ComponentIcons.Bulkhead = Cloison
diff --git a/core/resources/l10n/messages_it.properties b/core/resources/l10n/messages_it.properties
index ef7a5d226..f99e43eb3 100644
--- a/core/resources/l10n/messages_it.properties
+++ b/core/resources/l10n/messages_it.properties
@@ -736,7 +736,6 @@ CenteringRingCfg.tab.Generalproperties = Proprieta' generali
!ComponentConfigDialog
ComponentCfgDlg.configuration = (configurazione)
-ComponentCfgDlg.configuration1 =
ComponentCfgDlg.Modify = Modifica
!StageConfig
diff --git a/core/resources/l10n/messages_ja.properties b/core/resources/l10n/messages_ja.properties
index 8cf8b6b03..2417dd0c0 100644
--- a/core/resources/l10n/messages_ja.properties
+++ b/core/resources/l10n/messages_ja.properties
@@ -766,7 +766,6 @@ CenteringRingCfg.tab.Generalproperties = \u4E00\u822C
!ComponentConfigDialog
ComponentCfgDlg.configuration = \u30B3\u30F3\u30D5\u30A3\u30AE\u30E5\u30EC\u30FC\u30B7\u30E7\u30F3
-ComponentCfgDlg.configuration1 =
ComponentCfgDlg.Modify = \u5909\u66F4
!StageConfig
diff --git a/core/resources/l10n/messages_nl.properties b/core/resources/l10n/messages_nl.properties
index 0b7e783f8..b32a8d0a5 100644
--- a/core/resources/l10n/messages_nl.properties
+++ b/core/resources/l10n/messages_nl.properties
@@ -889,7 +889,6 @@ CenteringRingCfg.tab.Generalproperties = Algemene eigenschappen
!ComponentConfigDialog
ComponentCfgDlg.configuration = configuratie
-ComponentCfgDlg.configuration1 =
ComponentCfgDlg.Modify = Wijzigen
!StageConfig
diff --git a/core/resources/l10n/messages_pl.properties b/core/resources/l10n/messages_pl.properties
index 05127de1c..08bcaec77 100644
--- a/core/resources/l10n/messages_pl.properties
+++ b/core/resources/l10n/messages_pl.properties
@@ -680,7 +680,6 @@ update.dlg.latestVersion = Korzystasz z najnowszej wersji OpenRocket: %s.
!ComponentConfigDialog
ComponentCfgDlg.configuration = konfiguracja
- ComponentCfgDlg.configuration1 =
ComponentCfgDlg.Modify = Zmodyfikuj
!StageConfig
diff --git a/core/resources/l10n/messages_ru.properties b/core/resources/l10n/messages_ru.properties
index 90883b5c1..cc5d08328 100644
--- a/core/resources/l10n/messages_ru.properties
+++ b/core/resources/l10n/messages_ru.properties
@@ -951,7 +951,6 @@ CenteringRingCfg.tab.Generalproperties = \u041E\u0441\u043D\u043E\u0432\u043D\u0
!ComponentConfigDialog
ComponentCfgDlg.configuration = \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B
-ComponentCfgDlg.configuration1 =
ComponentCfgDlg.Modify = \u0418\u0437\u043C\u0435\u043D\u0438\u0442\u044C
!StageConfig
diff --git a/core/resources/l10n/messages_uk_UA.properties b/core/resources/l10n/messages_uk_UA.properties
index 8a06a77ef..5d7147134 100644
--- a/core/resources/l10n/messages_uk_UA.properties
+++ b/core/resources/l10n/messages_uk_UA.properties
@@ -838,7 +838,6 @@ CenteringRingCfg.tab.Generalproperties = General properties
!ComponentConfigDialog
ComponentCfgDlg.configuration = configuration
-ComponentCfgDlg.configuration1 =
ComponentCfgDlg.Modify = Modify
!StageConfig
diff --git a/core/src/net/sf/openrocket/appearance/AppearanceBuilder.java b/core/src/net/sf/openrocket/appearance/AppearanceBuilder.java
index 230c80ebd..3763eae0e 100644
--- a/core/src/net/sf/openrocket/appearance/AppearanceBuilder.java
+++ b/core/src/net/sf/openrocket/appearance/AppearanceBuilder.java
@@ -1,10 +1,14 @@
package net.sf.openrocket.appearance;
import net.sf.openrocket.appearance.Decal.EdgeMode;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.AbstractChangeSource;
import net.sf.openrocket.util.Color;
import net.sf.openrocket.util.Coordinate;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
/**
* Use this class to build an immutable Appearance object in a friendly way. Set
* the various values one at a time with the setter methods and then call
@@ -28,6 +32,13 @@ public class AppearanceBuilder extends AbstractChangeSource {
private Decal.EdgeMode edgeMode;
private boolean batch;
+
+ /**
+ * List of appearance builders that will set their appearance properties to the same as the current appearance
+ */
+ private final Map configListeners = new LinkedHashMap<>();
+ // If true, appearance change events will not be fired
+ private boolean bypassAppearanceChangeEvent = false;
/**
* Default constructor
@@ -59,7 +70,9 @@ public class AppearanceBuilder extends AbstractChangeSource {
rotation = 0;
image = null;
edgeMode = EdgeMode.REPEAT;
- fireChangeEvent();//shouldn't this fire change event?
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
@@ -88,6 +101,9 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @param d The decal
*/
public void setDecal(Decal d){
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setDecal(d);
+ }
if (d != null) {
setOffset(d.getOffset().x, d.getOffset().y);
setCenter(d.getCenter().x, d.getCenter().y);
@@ -96,7 +112,9 @@ public class AppearanceBuilder extends AbstractChangeSource {
setEdgeMode(d.getEdgeMode());
setImage(d.getImage());
}
- fireChangeEvent();
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
@@ -137,9 +155,13 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @param paint the new color
*/
public void setPaint(Color paint) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setPaint(paint);
+ }
this.paint = paint;
- fireChangeEvent();
-
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
@@ -158,8 +180,13 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @param shine the new shine for template
*/
public void setShine(double shine) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setShine(shine);
+ }
this.shine = shine;
- fireChangeEvent();
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
@@ -179,6 +206,9 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @param opacity new opacity value expressed in a percentage, where 0 is fully transparent and 1 is fully opaque
*/
public void setOpacity(double opacity) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setOpacity(opacity);
+ }
if (this.paint == null) {
return;
}
@@ -186,8 +216,10 @@ public class AppearanceBuilder extends AbstractChangeSource {
// Clamp opacity between 0 and 1
opacity = Math.max(0, Math.min(1, opacity));
- this.paint.setAlpha((int) (opacity * 255));
- fireChangeEvent();
+ // Instead of simply setting the alpha, we need to create a new color with the new alpha value, otherwise undoing
+ // the setOpacity will not work correctly. (don't ask me why)
+ Color c = new Color(paint.getRed(), paint.getGreen(), paint.getBlue(), (int) (opacity * 255));
+ setPaint(c);
}
/**
@@ -207,8 +239,13 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @param offsetU the new offset to be used
*/
public void setOffsetU(double offsetU) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setOffsetU(offsetU);
+ }
this.offsetU = offsetU;
- fireChangeEvent();
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
@@ -227,8 +264,13 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @param offsetV the new offset to be used
*/
public void setOffsetV(double offsetV) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setOffsetV(offsetV);
+ }
this.offsetV = offsetV;
- fireChangeEvent();
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
@@ -259,8 +301,13 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @param centerU value of axis U for center
*/
public void setCenterU(double centerU) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setCenterU(centerU);
+ }
this.centerU = centerU;
- fireChangeEvent();
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
@@ -276,11 +323,16 @@ public class AppearanceBuilder extends AbstractChangeSource {
* set a new value for axis V for center in template
* fires change event
*
- * @param centerU value of axis V for center
+ * @return value of axis V for center
*/
public void setCenterV(double centerV) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setCenterV(centerV);
+ }
this.centerV = centerV;
- fireChangeEvent();
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
@@ -311,8 +363,13 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @param scaleU new value of scalling in axis U
*/
public void setScaleU(double scaleU) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setScaleU(scaleU);
+ }
this.scaleU = scaleU;
- fireChangeEvent();
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
@@ -331,8 +388,13 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @param scaleV new value of scalling in axis V
*/
public void setScaleV(double scaleV) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setScaleV(scaleV);
+ }
this.scaleV = scaleV;
- fireChangeEvent();
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
@@ -379,7 +441,7 @@ public class AppearanceBuilder extends AbstractChangeSource {
* sets a new value of axis Y for scalling in template
* fires change event
*
- * @param scaleX the new value for axis Y
+ * @param scaleY the new value for axis Y
*/
public void setScaleY(double scaleY) {
setScaleV(1.0 / scaleY);
@@ -401,14 +463,19 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @param rotation the new value for rotation in template
*/
public void setRotation(double rotation) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setRotation(rotation);
+ }
this.rotation = rotation;
- fireChangeEvent();
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
* gets the current image in template
*
- * @param the current image in template
+ * @return the current image in template
*/
public DecalImage getImage() {
return image;
@@ -421,8 +488,13 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @param image the new image to be used as template
*/
public void setImage(DecalImage image) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setImage(image);
+ }
this.image = image;
- fireChangeEvent();
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
@@ -441,8 +513,13 @@ public class AppearanceBuilder extends AbstractChangeSource {
* @param edgeMode the new edgeMode to be used
*/
public void setEdgeMode(Decal.EdgeMode edgeMode) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setEdgeMode(edgeMode);
+ }
this.edgeMode = edgeMode;
- fireChangeEvent();
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
}
/**
@@ -455,15 +532,55 @@ public class AppearanceBuilder extends AbstractChangeSource {
}
/**
- * function that garantees that chenges event only occurs after all changes are made
+ * function that guarantees that changes event only occurs after all changes are made
*
* param r the functor to be executed
*/
public void batch(Runnable r) {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.batch(r);
+ }
batch = true;
r.run();
batch = false;
- fireChangeEvent();
+ if (!bypassAppearanceChangeEvent) {
+ fireChangeEvent();
+ }
+ }
+
+ /**
+ * Add a new config listener that will undergo the same configuration changes as this AppearanceBuilder.
+ * @param component the component to add as a config listener
+ * @param ab new AppearanceBuilder config listener
+ * @return true if listener was successfully added, false if not
+ */
+ public boolean addConfigListener(RocketComponent component, AppearanceBuilder ab) {
+ if (component == null || ab == null) {
+ return false;
+ }
+ configListeners.put(component, ab);
+ ab.setBypassChangeEvent(true);
+ return true;
+ }
+
+ public void removeConfigListener(RocketComponent listener) {
+ configListeners.remove(listener);
+ listener.setBypassChangeEvent(false);
+ }
+
+ public void clearConfigListeners() {
+ for (AppearanceBuilder listener : configListeners.values()) {
+ listener.setBypassChangeEvent(false);
+ }
+ configListeners.clear();
+ }
+
+ public Map getConfigListeners() {
+ return configListeners;
+ }
+
+ public void setBypassChangeEvent(boolean newValue) {
+ this.bypassAppearanceChangeEvent = newValue;
}
}
diff --git a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java
index f03862f0a..4971e1525 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java
@@ -123,7 +123,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
private Appearance appearance = null;
// If true, component change events will not be fired
- private boolean ignoreComponentChange = false;
+ private boolean bypassComponentChangeEvent = false;
/**
@@ -464,10 +464,6 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
* @param appearance
*/
public void setAppearance(Appearance appearance) {
- for (RocketComponent listener : configListeners) {
- listener.setAppearance(appearance);
- }
-
this.appearance = appearance;
if (this.appearance != null) {
Decal d = this.appearance.getTexture();
@@ -581,9 +577,9 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
*/
public final void setMassOverridden(boolean o) {
for (RocketComponent listener : configListeners) {
- listener.setIgnoreComponentChange(false);
+ listener.setBypassChangeEvent(false);
listener.setMassOverridden(o);
- listener.setIgnoreComponentChange(false);
+ listener.setBypassChangeEvent(false);
}
if (massOverridden == o) {
@@ -655,9 +651,9 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
*/
public final void setCGOverridden(boolean o) {
for (RocketComponent listener : configListeners) {
- listener.setIgnoreComponentChange(false);
+ listener.setBypassChangeEvent(false);
listener.setCGOverridden(o);
- listener.setIgnoreComponentChange(true);
+ listener.setBypassChangeEvent(true);
}
if (cgOverridden == o) {
@@ -806,9 +802,9 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
*/
public final void setName(String name) {
for (RocketComponent listener : configListeners) {
- listener.setIgnoreComponentChange(false);
+ listener.setBypassChangeEvent(false);
listener.setName(name);
- listener.setIgnoreComponentChange(true);
+ listener.setBypassChangeEvent(true);
}
if (this.name.equals(name)) {
@@ -1671,6 +1667,24 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
}
return false;
}
+
+ /**
+ * Checks whether all components in the list have the same class as this component.
+ * @param components list to check
+ * @return true if all components are of the same class, false if not
+ */
+ public boolean checkAllClassesEqual(List components) {
+ if (components == null || components.size() == 0) {
+ return true;
+ }
+ Class extends RocketComponent> myClass = this.getClass();
+ for (RocketComponent c : components) {
+ if (!c.getClass().equals(myClass)) {
+ return false;
+ }
+ }
+ return true;
+ }
/**
* Get the root component of the component tree.
@@ -1936,7 +1950,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
*/
protected void fireComponentChangeEvent(ComponentChangeEvent e) {
checkState();
- if (parent == null || ignoreComponentChange) {
+ if (parent == null || bypassComponentChangeEvent) {
/* Ignore if root invalid. */
return;
}
@@ -1955,37 +1969,36 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
fireComponentChangeEvent(new ComponentChangeEvent(this, type));
}
- public void setIgnoreComponentChange(boolean newValue) {
- this.ignoreComponentChange = newValue;
+ public void setBypassChangeEvent(boolean newValue) {
+ this.bypassComponentChangeEvent = newValue;
}
- public boolean getIgnoreComponentChange() {
- return this.ignoreComponentChange;
+ public boolean getBypassComponentChangeEvent() {
+ return this.bypassComponentChangeEvent;
}
/**
- * Add a new config listener that will undergo the same configuration changes as this.component. Listener must be
- * of the same class as this.component.
+ * Add a new config listener that will undergo the same configuration changes as this.component.
* @param listener new config listener
* @return true if listener was successfully added, false if not
*/
public boolean addConfigListener(RocketComponent listener) {
- if (listener == null || !this.getClass().equals(listener.getClass())) {
+ if (listener == null) {
return false;
}
configListeners.add(listener);
- listener.setIgnoreComponentChange(true);
+ listener.setBypassChangeEvent(true);
return true;
}
public void removeConfigListener(RocketComponent listener) {
configListeners.remove(listener);
- listener.setIgnoreComponentChange(false);
+ listener.setBypassChangeEvent(false);
}
public void clearConfigListeners() {
for (RocketComponent listener : configListeners) {
- listener.setIgnoreComponentChange(false);
+ listener.setBypassChangeEvent(false);
}
configListeners.clear();
}
diff --git a/swing/src/net/sf/openrocket/gui/components/StyledLabel.java b/swing/src/net/sf/openrocket/gui/components/StyledLabel.java
index 70328411b..bf2a29314 100644
--- a/swing/src/net/sf/openrocket/gui/components/StyledLabel.java
+++ b/swing/src/net/sf/openrocket/gui/components/StyledLabel.java
@@ -1,5 +1,6 @@
package net.sf.openrocket.gui.components;
+import java.awt.Color;
import java.awt.Font;
import javax.swing.JLabel;
@@ -87,11 +88,9 @@ public class StyledLabel extends JLabel {
private void checkPreferredSize(float size, Style style) {
String str = this.getText();
- if (str.startsWith("") && str.indexOf("
") && !str.contains("
textureDropDown = new JComboBox(decalModel);
+ // We need to add this action listener that triggers a decalModel update when the same item is selected, because
+ // for multi-comp edits, the listeners' decals may not be updated otherwise
+ textureDropDown.addActionListener(new ActionListener() {
+ private DecalImage previousSelection = (DecalImage) decalModel.getSelectedItem();
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ DecalImage decal = (DecalImage) textureDropDown.getSelectedItem();
+ if (decal == previousSelection) {
+ decalModel.setSelectedItem(decal);
+ }
+ previousSelection = decal;
+ }
+ });
+
JButton colorButton = new SelectColorButton(new ColorIcon(builder.getPaint()));
colorButton.addActionListener(new ColorActionListener(builder, "Paint"));
@@ -464,13 +508,31 @@ public class AppearancePanel extends JPanel {
previousUserSelectedInsideAppearance = (builder == null) ? null
: builder.getAppearance();
}
+
+ // Set the listeners' appearance to the default appearance
+ for (RocketComponent listener : builder.getConfigListeners().keySet()) {
+ builder.getConfigListeners().get(listener).setAppearance(defaultAppearance);
+ listener.setAppearance(null);
+ }
+
+ // Set this component's appearance to the default appearance
builder.setAppearance(defaultAppearance);
c.setAppearance(null);
} else {
- if (!insideBuilder)
+ if (!insideBuilder) {
+ // Set the listeners' appearance to the previous user selected appearance
+ for (AppearanceBuilder listener : builder.getConfigListeners().values()) {
+ listener.setAppearance(previousUserSelectedAppearance);
+ }
builder.setAppearance(previousUserSelectedAppearance);
- else
+ }
+ else {
+ // Set the listeners' inside appearance to the previous user selected appearance
+ for (AppearanceBuilder listener : builder.getConfigListeners().values()) {
+ listener.setAppearance(previousUserSelectedInsideAppearance);
+ }
builder.setAppearance(previousUserSelectedInsideAppearance);
+ }
}
}
});
@@ -551,9 +613,9 @@ public class AppearancePanel extends JPanel {
mDefault.addEnableComponent(spinShine, false);
mDefault.addEnableComponent(unitShine, false);
- panel.add(spinShine, "split 3, w 50");
+ panel.add(spinShine, "split 3, w 60");
panel.add(unitShine);
- panel.add(slideShine, "w 50");
+ panel.add(slideShine, "w 50, growx");
// Offset
panel.add(new JLabel(trans.get("AppearanceCfg.lbl.texture.offset")));
@@ -585,9 +647,9 @@ public class AppearancePanel extends JPanel {
mDefault.addEnableComponent(spinOpacity, false);
mDefault.addEnableComponent(unitOpacity, false);
- panel.add(spinOpacity, "split 3, w 50");
+ panel.add(spinOpacity, "split 3, w 60");
panel.add(unitOpacity);
- panel.add(slideOpacity, "w 50");
+ panel.add(slideOpacity, "w 50, growx");
// Rotation
panel.add(new JLabel(trans.get("AppearanceCfg.lbl.texture.rotation")));
@@ -622,10 +684,24 @@ public class AppearancePanel extends JPanel {
opacityModel.stateChanged(null);
lastOpacity = builder.getOpacity();
}
- if (!insideBuilder)
+ if (!insideBuilder) {
+ // Set the listeners' outside appearance
+ for (RocketComponent listener : builder.getConfigListeners().keySet()) {
+ listener.setAppearance(builder.getConfigListeners().get(listener).getAppearance());
+ }
+ // Set this component's outside appearance
c.setAppearance(builder.getAppearance());
- else
- ((InsideColorComponent)c).getInsideColorComponentHandler().setInsideAppearance(builder.getAppearance());
+ }
+ else {
+ // Set the listeners' inside appearance
+ for (RocketComponent listener : builder.getConfigListeners().keySet()) {
+ if (!(listener instanceof InsideColorComponent)) continue;
+ ((InsideColorComponent) listener).getInsideColorComponentHandler()
+ .setInsideAppearance(builder.getConfigListeners().get(listener).getAppearance());
+ }
+ // Set this component's inside appearance
+ ((InsideColorComponent) c).getInsideColorComponentHandler().setInsideAppearance(builder.getAppearance());
+ }
decalModel.refresh();
}
});
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java b/swing/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java
index fbf92a046..7defaca26 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java
@@ -14,8 +14,10 @@ import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
+import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.BugException;
@@ -25,7 +27,7 @@ import net.sf.openrocket.util.Reflection;
* A dialog that contains the configuration elements of one component.
* The contents of the dialog are instantiated from CONFIGDIALOGPACKAGE according
* to the current component.
- *
+ *
* @author Sampo Niskanen
*/
@@ -33,26 +35,26 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
private static final long serialVersionUID = 1L;
private static final String CONFIGDIALOGPACKAGE = "net.sf.openrocket.gui.configdialog";
private static final String CONFIGDIALOGPOSTFIX = "Config";
-
+
// Static Value -- This is a singleton value, and we should only have zero or one active at any time
private static ComponentConfigDialog dialog = null;
-
- private OpenRocketDocument document = null;
- private RocketComponent component = null;
- private RocketComponentConfig configurator = null;
+ private OpenRocketDocument document = null;
+ protected RocketComponent component = null;
+ private RocketComponentConfig configurator = null;
+ protected static boolean clearConfigListeners = true;
private static String previousSelectedTab = null; // Name of the previous selected tab
-
+
+
private final Window parent;
private static final Translator trans = Application.getTranslator();
-
- private ComponentConfigDialog(Window parent, OpenRocketDocument document, RocketComponent component,
- List listeners) {
+
+ private ComponentConfigDialog(Window parent, OpenRocketDocument document, RocketComponent component) {
super(parent);
this.parent = parent;
-
+
setComponent(document, component);
-
+
GUIUtil.setDisposableDialogOptions(this, null);
GUIUtil.rememberWindowPosition(this);
@@ -63,33 +65,28 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
* In fact, it should trigger for any method of closing the dialog.
*/
public void windowClosed(WindowEvent e){
+ configurator.clearConfigListeners();
configurator.invalidate();
document.getRocket().removeComponentChangeListener(ComponentConfigDialog.this);
ComponentConfigDialog.this.dispose();
- component.clearConfigListeners();
+ if (clearConfigListeners) {
+ component.clearConfigListeners();
+ }
}
-
- public void windowClosing(WindowEvent e){}
@Override
public void windowOpened(WindowEvent e) {
super.windowOpened(e);
- // Add config listeners
- component.clearConfigListeners();
- if (listeners != null) {
- for (RocketComponent listener : listeners) {
- component.addConfigListener(listener);
- }
- }
+ clearConfigListeners = true;
}
});
}
-
-
+
+
/**
* Set the component being configured. The listening connections of the old configurator
* will be removed and the new ones created.
- *
+ *
* @param component Component to configure.
*/
private void setComponent(OpenRocketDocument document, RocketComponent component) {
@@ -97,24 +94,43 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
// Remove listeners by setting all applicable models to null
GUIUtil.setNullModels(configurator); // null-safe
}
-
+
this.document = document;
this.component = component;
this.document.getRocket().addComponentChangeListener(this);
-
+
configurator = getDialogContents();
this.setContentPane(configurator);
configurator.updateFields();
- // Set the selected tab
- configurator.setSelectedTab(previousSelectedTab);
-
+ List listeners = component.getConfigListeners();
+
+ // Set the default tab to 'Appearance' for a different-type multi-comp dialog (this is the most prominent use case)
+ if (listeners != null && listeners.size() > 0 && !component.checkAllClassesEqual(listeners)) {
+ configurator.setSelectedTabIndex(1);
+ } else {
+ configurator.setSelectedTab(previousSelectedTab);
+ }
+
//// configuration
- setTitle(trans.get("ComponentCfgDlg.configuration1") + " " + component.getComponentName() + " " + trans.get("ComponentCfgDlg.configuration"));
-
+ if (component.checkAllClassesEqual(listeners)) {
+ if (listeners != null && listeners.size() > 0) {
+ setTitle("(" + trans.get("ComponentCfgDlg.MultiComponent") + ") " +
+ component.getComponentName() + " " + trans.get("ComponentCfgDlg.configuration"));
+ } else {
+ setTitle(component.getComponentName() + " " + trans.get("ComponentCfgDlg.configuration"));
+ }
+ } else {
+ setTitle(trans.get("ComponentCfgDlg.MultiComponentConfig"));
+ }
+
this.pack();
}
+ public RocketComponent getComponent() {
+ return component;
+ }
+
public static ComponentConfigDialog getDialog() {
return dialog;
}
@@ -124,32 +140,36 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
* Return the configurator panel of the current component.
*/
private RocketComponentConfig getDialogContents() {
- Constructor extends RocketComponentConfig> c =
+ List listeners = component.getConfigListeners();
+ boolean isSameClass = component.checkAllClassesEqual(listeners);
+ if (!isSameClass) {
+ return new RocketComponentConfig(document, component);
+ }
+
+ Constructor extends RocketComponentConfig> constructor =
findDialogContentsConstructor(component);
- if (c != null) {
+ if (constructor != null) {
try {
- return c.newInstance(document, component);
- } catch (InstantiationException e) {
- throw new BugException("BUG in constructor reflection", e);
- } catch (IllegalAccessException e) {
+ return constructor.newInstance(document, component);
+ } catch (InstantiationException | IllegalAccessException e) {
throw new BugException("BUG in constructor reflection", e);
} catch (InvocationTargetException e) {
throw Reflection.handleWrappedException(e);
}
}
-
+
// Should never be reached, since RocketComponentConfig should catch all
// components without their own configurator.
throw new BugException("Unable to find any configurator for " + component);
}
-
+
@Override
public void componentChanged(ComponentChangeEvent e) {
if (e.isTreeChange() || e.isUndoChange()) {
-
+
// Hide dialog in case of tree or undo change
disposeDialog();
-
+
} else {
/*
* TODO: HIGH: The line below has caused a NullPointerException (without null check)
@@ -161,10 +181,10 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
configurator.updateFields();
}
}
-
-
+
+
/**
- * Finds the Constructor of the given component's config dialog panel in
+ * Finds the Constructor of the given component's config dialog panel in
* CONFIGDIALOGPACKAGE.
*/
@SuppressWarnings("unchecked")
@@ -172,10 +192,10 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
Class> currentclass;
String currentclassname;
String configclassname;
-
+
Class> configclass;
Constructor extends RocketComponentConfig> c;
-
+
currentclass = component.getClass();
while ((currentclass != null) && (currentclass != Object.class)) {
currentclassname = currentclass.getCanonicalName();
@@ -184,7 +204,7 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
currentclassname = currentclassname.substring(index + 1);
configclassname = CONFIGDIALOGPACKAGE + "." + currentclassname +
CONFIGDIALOGPOSTFIX;
-
+
try {
configclass = Class.forName(configclassname);
c = (Constructor extends RocketComponentConfig>)
@@ -192,69 +212,57 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
return c;
} catch (Exception ignore) {
}
-
+
currentclass = currentclass.getSuperclass();
}
return null;
}
-
-
+
+
////////// Static dialog /////////
-
+
/**
- * A singleton configuration dialog. Will create and show a new dialog if one has not
+ * A singleton configuration dialog. Will create and show a new dialog if one has not
* previously been used, or update the dialog and show it if a previous one exists.
- *
+ *
* @param document the document to configure.
* @param component the component to configure.
- * @param listeners config listeners for the component
* @param rememberPreviousTab if true, the previous tab will be remembered and used for the new dialog
*/
- public static void showDialog(Window parent, OpenRocketDocument document,
- RocketComponent component, List listeners, boolean rememberPreviousTab) {
+ public static void showDialog(Window parent, OpenRocketDocument document, RocketComponent component, boolean rememberPreviousTab) {
if (dialog != null) {
- previousSelectedTab = dialog.getSelectedTabName();
+ // Don't remember the previous tab for rockets or stages, because this will leave you in the override tab for
+ // the next component, which is generally not what you want.
+ if (dialog.getComponent() instanceof Rocket ||
+ (dialog.getComponent() instanceof AxialStage && !(component instanceof AxialStage))) {
+ previousSelectedTab = null;
+ } else {
+ previousSelectedTab = dialog.getSelectedTabName();
+ }
+ // If the component is the same as the ComponentConfigDialog component, and the dialog is still visible,
+ // that means that the user did a ctr/cmd click on a new component => don't remove the config listeners of component
+ if (component == dialog.getComponent()) {
+ ComponentConfigDialog.clearConfigListeners = false;
+ }
dialog.dispose();
}
+
final SwingPreferences preferences = (SwingPreferences) Application.getPreferences();
if (preferences.isAlwaysOpenLeftmostTab() || !rememberPreviousTab) {
previousSelectedTab = null;
}
- dialog = new ComponentConfigDialog(parent, document, component, listeners);
+ dialog = new ComponentConfigDialog(parent, document, component);
dialog.setVisible(true);
-
+
////Modify
- document.addUndoPosition(trans.get("ComponentCfgDlg.Modify") + " " + component.getComponentName());
- }
-
- /**
- * A singleton configuration dialog. Will create and show a new dialog if one has not
- * previously been used, or update the dialog and show it if a previous one exists.
- * By default, the previous tab is remembered.
- *
- * @param document the document to configure.
- * @param component the component to configure.
- * @param listeners config listeners for the component
- */
- public static void showDialog(Window parent, OpenRocketDocument document,
- RocketComponent component, List listeners) {
- ComponentConfigDialog.showDialog(parent, document, component, listeners, true);
- }
-
- /**
- * A singleton configuration dialog. Will create and show a new dialog if one has not
- * previously been used, or update the dialog and show it if a previous one exists.
- *
- * @param document the document to configure.
- * @param component the component to configure.
- * @param rememberPreviousTab if true, the previous tab will be remembered and used for the new dialog
- */
- public static void showDialog(Window parent, OpenRocketDocument document,
- RocketComponent component, boolean rememberPreviousTab) {
- ComponentConfigDialog.showDialog(parent, document, component, null, rememberPreviousTab);
+ if (component.getConfigListeners().size() == 0) {
+ document.addUndoPosition(trans.get("ComponentCfgDlg.Modify") + " " + component.getComponentName());
+ } else {
+ document.addUndoPosition(trans.get("ComponentCfgDlg.ModifyComponents"));
+ }
}
/**
@@ -265,26 +273,20 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
* @param document the document to configure.
* @param component the component to configure.
*/
- public static void showDialog(Window parent, OpenRocketDocument document,
- RocketComponent component) {
- ComponentConfigDialog.showDialog(parent, document, component, null, true);
+ public static void showDialog(Window parent, OpenRocketDocument document, RocketComponent component) {
+ ComponentConfigDialog.showDialog(parent, document, component, true);
}
- static void showDialog(RocketComponent component, List listeners, boolean rememberPreviousTab) {
- showDialog(dialog.parent, dialog.document, component, listeners, rememberPreviousTab);
- }
-
-
- /* package */
- static void showDialog(RocketComponent component, List listeners) {
- showDialog(dialog.parent, dialog.document, component, listeners, true);
+ static void showDialog(RocketComponent component, boolean rememberPreviousTab) {
+ showDialog(dialog.parent, dialog.document, component, rememberPreviousTab);
}
+
/* package */
static void showDialog(RocketComponent component) {
- ComponentConfigDialog.showDialog(component, null);
+ showDialog(dialog.parent, dialog.document, component, true);
}
-
+
/**
* Disposes the configuration dialog. May be used even if not currently visible.
*/
@@ -293,8 +295,8 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
dialog.dispose();
}
}
-
-
+
+
/**
* Returns whether the singleton configuration dialog is currently visible or not.
*/
@@ -302,6 +304,10 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
return (dialog != null) && (dialog.isVisible());
}
+ public int getSelectedTabIndex() {
+ return configurator.getSelectedTabIndex();
+ }
+
public String getSelectedTabName() {
if (configurator != null) {
return configurator.getSelectedTabName();
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java
index 06dee6dc5..e5470185e 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/FinSetConfig.java
@@ -82,17 +82,10 @@ public abstract class FinSetConfig extends RocketComponentConfig {
//// Convert fin set
document.addUndoPosition(trans.get("FinSetConfig.Convertfinset"));
- List listeners = new ArrayList<>();
- for (RocketComponent listener : component.getConfigListeners()) {
- if (listener instanceof FinSet) {
- listeners.add(FreeformFinSet.convertFinSet((FinSet) listener));
- }
- }
-
RocketComponent freeform =
FreeformFinSet.convertFinSet((FinSet) component);
- ComponentConfigDialog.showDialog(freeform, listeners);
+ ComponentConfigDialog.showDialog(freeform);
}
});
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
index f49741d82..283cdc52b 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
@@ -1,6 +1,7 @@
package net.sf.openrocket.gui.configdialog;
+import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.event.*;
@@ -39,7 +40,6 @@ import net.sf.openrocket.gui.widgets.SelectColorButton;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
-import net.sf.openrocket.rocketcomponent.ComponentAssembly;
import net.sf.openrocket.rocketcomponent.*;
import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
@@ -66,22 +66,42 @@ public class RocketComponentConfig extends JPanel {
private final TextFieldListener textFieldListener;
private JPanel buttonPanel;
+ private AppearancePanel appearancePanel = null;
private JLabel infoLabel;
-
-
+ private StyledLabel multiCompEditLabel;
+
+ private boolean allSameType; // Checks whether all listener components are of the same type as
+ private boolean allMassive; // Checks whether all listener components, and this component, are massive
+
public RocketComponentConfig(OpenRocketDocument document, RocketComponent component) {
setLayout(new MigLayout("fill, gap 4!, ins panel", "[]:5[]", "[growprio 5]5![fill, grow, growprio 500]5![growprio 5]"));
this.document = document;
this.component = component;
-
+
+ // Check the listeners for the same type and massive status
+ allSameType = true;
+ allMassive = component.isMassive();
+ List listeners = component.getConfigListeners();
+ if (listeners != null && listeners.size() > 0) {
+ allSameType = component.checkAllClassesEqual(listeners);
+ if (allMassive) { // Only check if is already massive
+ for (RocketComponent listener : listeners) {
+ if (!listener.isMassive()) {
+ allMassive = false;
+ break;
+ }
+ }
+ }
+ }
+
//// Component name:
JLabel label = new JLabel(trans.get("RocketCompCfg.lbl.Componentname"));
//// The component name.
label.setToolTipText(trans.get("RocketCompCfg.ttip.Thecomponentname"));
this.add(label, "spanx, height 32!, split");
-
+
componentNameField = new JTextField(15);
textFieldListener = new TextFieldListener();
componentNameField.addActionListener(textFieldListener);
@@ -89,34 +109,34 @@ public class RocketComponentConfig extends JPanel {
//// The component name.
componentNameField.setToolTipText(trans.get("RocketCompCfg.ttip.Thecomponentname"));
this.add(componentNameField, "growx");
-
- if (component.getPresetType() != null) {
+
+ if (allSameType && component.getPresetType() != null) {
// If the component supports a preset, show the preset selection box.
presetModel = new PresetModel(this, document, component);
presetComboBox = new JComboBox(presetModel);
presetComboBox.setEditable(false);
this.add(presetComboBox, "");
}
-
-
+
tabbedPane = new JTabbedPane();
this.add(tabbedPane, "newline, span, growx, growy 100, wrap");
-
+
//// Override and Mass and CG override options
tabbedPane.addTab(trans.get("RocketCompCfg.tab.Override"), null, overrideTab(),
trans.get("RocketCompCfg.tab.MassandCGoverride"));
- if (component.isMassive()) {
+ if (allMassive) {
//// Appearance options
- tabbedPane.addTab(trans.get("RocketCompCfg.tab.Appearance"), null, new AppearancePanel(document, component),
+ appearancePanel = new AppearancePanel(document, component);
+ tabbedPane.addTab(trans.get("RocketCompCfg.tab.Appearance"), null, appearancePanel,
"Appearance Tool Tip");
}
-
+
//// Comment and Specify a comment for the component
tabbedPane.addTab(trans.get("RocketCompCfg.tab.Comment"), null, commentTab(),
trans.get("RocketCompCfg.tab.Specifyacomment"));
-
+
addButtons();
-
+
updateFields();
}
@@ -128,6 +148,12 @@ public class RocketComponentConfig extends JPanel {
buttonPanel = new JPanel(new MigLayout("fillx, ins 5"));
+ //// Multi-comp edit label
+ multiCompEditLabel = new StyledLabel(" ", -1, Style.BOLD);
+ //multiCompEditLabel.setFontColor(new Color(0, 0, 239));
+ multiCompEditLabel.setFontColor(new Color(170, 0, 100));
+ buttonPanel.add(multiCompEditLabel, "split 2");
+
//// Mass:
infoLabel = new StyledLabel(" ", -1);
buttonPanel.add(infoLabel, "growx");
@@ -159,16 +185,17 @@ public class RocketComponentConfig extends JPanel {
public void updateFields() {
// Component name
componentNameField.setText(component.getName());
-
+
// Info label
StringBuilder sb = new StringBuilder();
-
- if (component.getPresetComponent() != null) {
+
+ if (allSameType && component.getPresetComponent() != null) {
ComponentPreset preset = component.getPresetComponent();
sb.append(preset.getManufacturer() + " " + preset.getPartNo() + " ");
}
-
- if (component.isMassive()) {
+
+ List listeners = component.getConfigListeners();
+ if (allMassive && (listeners == null || listeners.size() == 0)) { // TODO: support aggregate mass display for current component and listeners?
sb.append(trans.get("RocketCompCfg.lbl.Componentmass") + " ");
sb.append(UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(
component.getComponentMass()));
@@ -193,8 +220,31 @@ public class RocketComponentConfig extends JPanel {
} else {
infoLabel.setText("");
}
+
+ // Multi-comp edit label
+ if (listeners != null && listeners.size() > 0) {
+ multiCompEditLabel.setText(trans.get("ComponentCfgDlg.MultiComponentEdit"));
+
+ StringBuilder components = new StringBuilder(trans.get("ComponentCfgDlg.MultiComponentEdit.ttip"));
+ components.append(component.getName()).append(", ");
+ for (int i = 0; i < listeners.size(); i++) {
+ if (i < listeners.size() - 1) {
+ components.append(listeners.get(i).getName()).append(", ");
+ } else {
+ components.append(listeners.get(i).getName());
+ }
+ }
+ multiCompEditLabel.setToolTipText(components.toString());
+ } else {
+ multiCompEditLabel.setText("");
+ }
+ }
+
+ public void clearConfigListeners() {
+ if (appearancePanel != null) {
+ appearancePanel.clearConfigListeners();
+ }
}
-
protected JPanel materialPanel(Material.Type type) {
////Component material: and Component finish:
@@ -269,6 +319,10 @@ public class RocketComponentConfig extends JPanel {
return subPanel;
}
+ public int getSelectedTabIndex() {
+ return tabbedPane.getSelectedIndex();
+ }
+
public String getSelectedTabName() {
if (tabbedPane != null) {
return tabbedPane.getTitleAt(tabbedPane.getSelectedIndex());
@@ -277,6 +331,12 @@ public class RocketComponentConfig extends JPanel {
}
}
+ public void setSelectedTabIndex(int index) {
+ if (tabbedPane != null) {
+ tabbedPane.setSelectedIndex(index);
+ }
+ }
+
public void setSelectedTab(String tabName) {
if (tabbedPane != null) {
for (int i = 0; i < tabbedPane.getTabCount(); i++) {
diff --git a/swing/src/net/sf/openrocket/gui/main/BasicFrame.java b/swing/src/net/sf/openrocket/gui/main/BasicFrame.java
index 54ea0c45d..3a435b329 100644
--- a/swing/src/net/sf/openrocket/gui/main/BasicFrame.java
+++ b/swing/src/net/sf/openrocket/gui/main/BasicFrame.java
@@ -338,16 +338,16 @@ public class BasicFrame extends JFrame {
if (!ComponentConfigDialog.isDialogVisible())
return;
+ else
+ ComponentConfigDialog.disposeDialog();
+
RocketComponent c = (RocketComponent) paths[0].getLastPathComponent();
- List listeners = new ArrayList<>();
+ c.clearConfigListeners();
for (int i = 1; i < paths.length; i++) {
RocketComponent listener = (RocketComponent) paths[i].getLastPathComponent();
- if (listener.getClass().equals(c.getClass())) {
- listeners.add((RocketComponent) paths[i].getLastPathComponent());
- }
+ c.addConfigListener(listener);
}
- ComponentConfigDialog.showDialog(BasicFrame.this,
- BasicFrame.this.document, c, listeners);
+ ComponentConfigDialog.showDialog(BasicFrame.this, BasicFrame.this.document, c);
}
});
@@ -1332,7 +1332,6 @@ public class BasicFrame extends JFrame {
*
* @param worker the OpenFileWorker that loads the file.
* @param displayName the file name to display in dialogs.
- * @param file the File to set the document to (may be null).
* @param parent
* @param openRocketConfigDialog if true, will open the configuration dialog of the rocket. This is useful for examples.
* @return
diff --git a/swing/src/net/sf/openrocket/gui/main/RocketActions.java b/swing/src/net/sf/openrocket/gui/main/RocketActions.java
index e966061ec..3292af843 100644
--- a/swing/src/net/sf/openrocket/gui/main/RocketActions.java
+++ b/swing/src/net/sf/openrocket/gui/main/RocketActions.java
@@ -5,7 +5,6 @@ import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
@@ -879,16 +878,17 @@ public class RocketActions {
List components = selectionModel.getSelectedComponents();
Simulation[] sims = selectionModel.getSelectedSimulations();
- if ((components != null) && (components.size() > 0) && checkAllClassesEqual(components)) {
- // Do nothing if the config dialog is already visible
+ if ((components != null) && (components.size() > 0)) {
if (ComponentConfigDialog.isDialogVisible())
- return;
+ ComponentConfigDialog.disposeDialog();
- List listeners = null;
+ RocketComponent component = components.get(0);
if (components.size() > 1) {
- listeners = components.subList(1, components.size());
+ for (int i = 1; i < components.size(); i++) {
+ component.addConfigListener(components.get(i));
+ }
}
- ComponentConfigDialog.showDialog(parentFrame, document, components.get(0), listeners);
+ ComponentConfigDialog.showDialog(parentFrame, document, component);
} else if (sims != null && sims.length > 0 && (simulationPanel != null)) {
simulationPanel.editSimulation();
}
@@ -898,25 +898,7 @@ public class RocketActions {
public void clipboardChanged() {
List components = selectionModel.getSelectedComponents();
- this.setEnabled(checkAllClassesEqual(components) || isSimulationSelected());
- }
-
- /**
- * Checks whether all components in the list have the same class
- * @param components list to check
- * @return true if all components are of the same class, false if not
- */
- private boolean checkAllClassesEqual(List components) {
- if (components == null || components.size() == 0) {
- return false;
- }
- Class extends RocketComponent> myClass = components.get(0).getClass();
- for (int i = 1; i < components.size(); i++) {
- if (!components.get(i).getClass().equals(myClass)) {
- return false;
- }
- }
- return true;
+ this.setEnabled((components != null && components.size() > 0) || isSimulationSelected());
}
}