diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties
index b8969fd8b..135ad0ed8 100644
--- a/core/resources/l10n/messages.properties
+++ b/core/resources/l10n/messages.properties
@@ -932,7 +932,7 @@ RocketCompCfg.checkbox.OverrideSubcomponents.CG.ttip = Overrides the cente
RocketCompCfg.checkbox.OverrideSubcomponents.CD.ttip = Overrides the coefficient of drag (CD) of this component
and its subcomponents with the CD of this component.
RocketCompCfg.lbl.MassOverriddenBy = Mass overridden by %s
RocketCompCfg.lbl.CGOverriddenBy = CG overridden by %s
-RocketCompCfg.lbl.CDOverriddenBy = CD overridden by %s
+RocketCompCfg.lbl.CDOverriddenBy = CD overridden by %s
RocketCompCfg.lbl.MassOverriddenBy.ttip = The mass of this component is determined by the mass override value of %s
RocketCompCfg.lbl.CGOverriddenBy.ttip = The CG of this component is determined by the CG override value of %s
RocketCompCfg.lbl.CDOverriddenBy.ttip = The CD of this component is determined by the CD override value of %s
@@ -1360,10 +1360,13 @@ PlotDialog.CheckBox.Showdatapoints = Show data points
PlotDialog.lbl.Chart = left click drag to zoom area. mouse wheel to zoom. ctrl-mouse wheel to zoom x axis only. ctrl-left click drag to pan. right click drag to zoom dynamically.
PlotDialog.btn.exportImage = Export Image
-ComponentTree.ttip.massoverride = mass override
-ComponentTree.ttip.cgoverride = cg override
+ComponentTree.ttip.massoverride = mass overriden
+ComponentTree.ttip.cgoverride = CG overriden
+ComponentTree.ttip.cdoverride = CD overriden
! "main" prefix is used for the main application dialog
+ComponentTreeRenderer.total = total
+
# FIXME: Rename the description keys
main.menu.file = File
diff --git a/core/resources/l10n/messages_de.properties b/core/resources/l10n/messages_de.properties
index e2cda7b33..11418eb82 100644
--- a/core/resources/l10n/messages_de.properties
+++ b/core/resources/l10n/messages_de.properties
@@ -1024,6 +1024,7 @@ PlotDialog.Chart.Simulatedflight = Simulierter Flug
PlotDialog.CheckBox.Showdatapoints = Datenpunkte anzeigen
PlotDialog.lbl.Chart = Klicken+ziehen: runter+rechts um hinein zu zoomen, hoch+links um heraus zu zoomen
+ComponentTreeRenderer.total = gesamt
! "main" prefix is used for the main application dialog
diff --git a/core/resources/l10n/messages_es.properties b/core/resources/l10n/messages_es.properties
index aec98d9c5..48a1df482 100644
--- a/core/resources/l10n/messages_es.properties
+++ b/core/resources/l10n/messages_es.properties
@@ -732,6 +732,8 @@ PlotDialog.CheckBox.Showdatapoints = Mostrar los datos de los puntos
PlotDialog.lbl.Chart = Arastrar con bot\u00f3n-izq rat\u00f3n para zoom del \u00e1rea. Rueda rat\u00f3n para zoom. Ctrl+rueda rat\u00f3n para zoom eje x. Ctrl+arrastrar con bot\u00f3n-izq rat\u00f3n para desplazar. Arrastrar con bot\u00f3n-der para zoom din\u00e1mico
PlotDialog.title.Flightdataplot = Representaci\u00f3n de los datos de vuelo
+ComponentTreeRenderer.total = total
+
PreferencesDialog.languages.default = Idioma por defecto
PreferencesDialog.lbl.language = Idioma de la interfaz:
PreferencesDialog.lbl.languageEffect = El idioma cambiar\u00e1 la pr\u00f3xima vez que abra OpenRocket.
diff --git a/core/resources/l10n/messages_fr.properties b/core/resources/l10n/messages_fr.properties
index 0e9ea5cdb..8eed74a8f 100644
--- a/core/resources/l10n/messages_fr.properties
+++ b/core/resources/l10n/messages_fr.properties
@@ -724,6 +724,8 @@ PlotDialog.lbl.Chart = Cliquer+d\u00E9placer en bas +droite pour a
! PlotDialog
PlotDialog.title.Flightdataplot = Trac\u00E9 du vol
+ComponentTreeRenderer.total = total
+
PreferencesDialog.languages.default = Valeur syst\u00E8me par d\u00E9faut
PreferencesDialog.lbl.language = Langue du programme:
PreferencesDialog.lbl.languageEffect = La langue sera chang\u00E9e apr\u00E8s avoir red\u00E9marr\u00E9 OpenRocket.
diff --git a/core/resources/l10n/messages_it.properties b/core/resources/l10n/messages_it.properties
index f8b4cb3f0..897a2f29b 100644
--- a/core/resources/l10n/messages_it.properties
+++ b/core/resources/l10n/messages_it.properties
@@ -1025,6 +1025,7 @@ PlotDialog.Chart.Simulatedflight = Volo simulato
PlotDialog.CheckBox.Showdatapoints = Mostra i punti
PlotDialog.lbl.Chart = Clicca e trascina giu'-dx per ingrandire, su-sx per rimpicciolire
+ComponentTreeRenderer.total = totali
! "main" prefix is used for the main application dialog
diff --git a/core/resources/l10n/messages_nl.properties b/core/resources/l10n/messages_nl.properties
index 08dccf2ca..f30d5c91e 100644
--- a/core/resources/l10n/messages_nl.properties
+++ b/core/resources/l10n/messages_nl.properties
@@ -1224,10 +1224,12 @@ TCMotorSelPan.btn.close = Sluit
PlotDialog.CheckBox.Showdatapoints = Toon datapunten
PlotDialog.lbl.Chart = Linksklik+sleep om in te zoomen op omgeving. Muiswiel om te zoomen. Ctrl-muiswiel om enkel x-as te zoomen. Ctrl-linksklik om te bewegen. Rechtsklik+sleep om dynamisch te zoomen.
-ComponentTree.ttip.massoverride = Massa overschrijven
+ComponentTree.ttip.massoverride = Massa overschreven
ComponentTree.ttip.cgoverride = ZP overschrijven
! "main" prefix is used for the main application dialog
+ComponentTreeRenderer.total = totaal
+
# FIXME: Rename the description keys
main.menu.file = Bestand
diff --git a/swing/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java b/swing/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java
index 0f66f24e2..2dad7795d 100644
--- a/swing/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java
+++ b/swing/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java
@@ -96,32 +96,60 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
StringBuilder sb = new StringBuilder();
sb.append("");
+ // Component name title
sb.append("").append(c.getName()).append("");
- if (c.isMassive() || c.isMassOverridden()) {
+
+ // Only add mass information if mass is not overridden by a parent component
+ RocketComponent overriddenBy = c.getMassOverriddenBy();
+ if (overriddenBy == null) {
+ if (c.isMassive() || c.isMassOverridden()) {
+ sb.append(" (").append(
+ UnitGroup.UNITS_MASS.toStringUnit(c.getMass()));
+ if (c.getChildCount() > 0) {
+ sb.append(" of ")
+ .append(UnitGroup.UNITS_MASS.toStringUnit(c
+ .getSectionMass())).append(" ").append(trans.get("ComponentTreeRenderer.total"));
+ }
+ sb.append(")");
+ } else {
+ if ((c.getChildCount() > 0) && (c.getSectionMass() > 0)) {
+ sb.append(" (")
+ .append(UnitGroup.UNITS_MASS.toStringUnit(c
+ .getSectionMass())).append(" ").append(trans.get("ComponentTreeRenderer.total")).append(")");
+ }
+ }
+ }
+
+ // Add component override information in title
+ if (c.isMassOverridden() && c.getMassOverriddenBy() == null) {
+ sb.append(", ").append(trans.get("ComponentTree.ttip.massoverride"));
+ }
+ if (c.isCGOverridden() && c.getCGOverriddenBy() == null) {
+ sb.append(", ").append(trans.get("ComponentTree.ttip.cgoverride"));
+ }
+ if (c.isCDOverridden() && c.getCDOverriddenBy() == null) {
+ sb.append(", ").append(trans.get("ComponentTree.ttip.cdoverride"));
+ }
+
+ // Add parent component override information on new lines
+ if (overriddenBy != null) {
+ sb.append("
").append(String.format(trans.get("RocketCompCfg.lbl.MassOverriddenBy"), overriddenBy.getName()));
sb.append(" (").append(
- UnitGroup.UNITS_MASS.toStringUnit(c.getMass()));
- if (c.getChildCount() > 0) {
- sb.append(" of ")
- .append(UnitGroup.UNITS_MASS.toStringUnit(c
- .getSectionMass())).append(" total");
- }
- sb.append(")");
- } else {
- if ((c.getChildCount() > 0) && (c.getSectionMass() > 0)) {
- sb.append(" (")
- .append(UnitGroup.UNITS_MASS.toStringUnit(c
- .getSectionMass())).append(" total)");
- }
- }
-
- if (c.isMassOverridden()) {
- sb.append(" ").append(trans.get("ComponentTree.ttip.massoverride"));
- }
-
- if (c.isCGOverridden()) {
- sb.append(" ").append(trans.get("ComponentTree.ttip.cgoverride"));
+ UnitGroup.UNITS_MASS.toStringUnit(overriddenBy.getMass())).append(")");
+ }
+ overriddenBy = c.getCGOverriddenBy();
+ if (overriddenBy != null) {
+ sb.append("
").append(String.format(trans.get("RocketCompCfg.lbl.CGOverriddenBy"), overriddenBy.getName()));
+ sb.append(" (").append(
+ UnitGroup.UNITS_LENGTH.toStringUnit(overriddenBy.getOverrideCGX())).append(")");
+ }
+ overriddenBy = c.getCDOverriddenBy();
+ if (overriddenBy != null) {
+ sb.append("
").append(String.format(trans.get("RocketCompCfg.lbl.CDOverriddenBy"), overriddenBy.getName()));
+ sb.append(" (").append(overriddenBy.getOverrideCD()).append(")");
}
+ // Add component comment on new line
String comment = c.getComment().trim();
if (comment.length() > 0) {
comment = TextUtil.escapeXML(comment);
@@ -140,11 +168,24 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
StringBuilder sb = new StringBuilder();
sb.append("");
+ // Components title
sb.append("Components");
+
+ // Calculate the total mass of the selected components
double totalMass = 0;
double totalSectionMass = 0;
boolean containsSectionMass = false;
+ List overriddenByComponents = new java.util.ArrayList<>(); // Components that override the mass of the selected components
for (RocketComponent c : components) {
+ RocketComponent overriddenBy = c.getMassOverriddenBy();
+ if (overriddenBy != null) {
+ if (!components.contains(overriddenBy) && !overriddenByComponents.contains(overriddenBy)) {
+ totalMass += overriddenBy.getMass();
+ overriddenByComponents.add(overriddenBy);
+ }
+ continue;
+ }
+
if (c.isMassive() || c.isMassOverridden()) {
totalMass += c.getMass();
// Don't add this component's mass to the section mass if its parent is in the list, otherwise you add up duplicate mass
@@ -163,9 +204,11 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
}
}
+ // Add total mass of the selected components in the title
sb.append(" (").append(UnitGroup.UNITS_MASS.toStringUnit(totalMass));
if (containsSectionMass) {
- sb.append(" of ").append(UnitGroup.UNITS_MASS.toStringUnit(totalSectionMass)).append(" total)");
+ sb.append(" of ").append(UnitGroup.UNITS_MASS.toStringUnit(totalSectionMass))
+ .append(" ").append(trans.get("ComponentTreeRenderer.total")).append(")");
} else {
sb.append(")");
}