Merge pull request #1412 from SiboVG/issue-1411

[#1411] Show combined mass of multi-selection hover in component
This commit is contained in:
SiboVG 2022-06-07 23:14:49 +02:00 committed by GitHub
commit 213a9b9063
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 97 additions and 31 deletions

View File

@ -1640,6 +1640,24 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
return result;
}
/**
* Iteratively checks whether the list of components contains the parent or super-parent (parent of parent of parent of...)
* of component.
* @param components list of components that may contain the parent
* @param component component to check the parent for
* @return true if the list contains the parent, false if not
*/
public static boolean listContainsParent(List<RocketComponent> components, RocketComponent component) {
RocketComponent c = component;
while (c.getParent() != null) {
if (components.contains(c.getParent())) {
return true;
}
c = c.getParent();
}
return false;
}
/**
* Get the root component of the component tree.

View File

@ -278,24 +278,6 @@ public class RocketActions {
return result;
}
/**
* Iteratively checks whether the list of components contains the parent or super-parent (parent of parent of parent of...)
* of component.
* @param components list of components that may contain the parent
* @param component component to check the parent for
* @return true if the list contains the parent, false if not
*/
public static boolean listContainsParent(List<RocketComponent> components, RocketComponent component) {
RocketComponent c = component;
while (c.getParent() != null) {
if (components.contains(c.getParent())) {
return true;
}
c = c.getParent();
}
return false;
}
/**
* If the children of a parent are not selected, add them to the selection. Do this recursively for the children
* of the children as well.
@ -340,7 +322,7 @@ public class RocketActions {
// If there is a component in the selection, but its parent (or the parent of the parent) is still
// not selected, add it to the selection
RocketComponent temp = component;
if (listContainsParent(selections, temp) && !selections.contains(temp.getParent())) {
if (RocketComponent.listContainsParent(selections, temp) && !selections.contains(temp.getParent())) {
while (!selections.contains(temp.getParent())) {
selections.add(temp.getParent());
temp = temp.getParent();
@ -1038,7 +1020,7 @@ public class RocketActions {
for (RocketComponent component : components) {
// Only move top components, don't move its children
if (!listContainsParent(components, component)) {
if (!RocketComponent.listContainsParent(components, component)) {
moveUp(component);
}
}
@ -1075,7 +1057,7 @@ public class RocketActions {
return false;
for (RocketComponent component : components) {
if (!listContainsParent(components, component) && !canMove(component))
if (!RocketComponent.listContainsParent(components, component) && !canMove(component))
return false;
}
return true;
@ -1113,7 +1095,7 @@ public class RocketActions {
for (RocketComponent component : components) {
// Only move top components, don't move its children
if (!listContainsParent(components, component)) {
if (!RocketComponent.listContainsParent(components, component)) {
moveDown(component);
}
}
@ -1150,7 +1132,7 @@ public class RocketActions {
return false;
for (RocketComponent component : components) {
if (!listContainsParent(components, component) && !canMove(component))
if (!RocketComponent.listContainsParent(components, component) && !canMove(component))
return false;
}
return true;

View File

@ -2,12 +2,14 @@ package net.sf.openrocket.gui.main.componenttree;
import java.awt.Component;
import java.awt.FlowLayout;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreePath;
import net.sf.openrocket.gui.main.ComponentIcons;
import net.sf.openrocket.gui.util.Icons;
@ -17,6 +19,7 @@ import net.sf.openrocket.rocketcomponent.MassComponent.MassComponentType;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.ArrayList;
import net.sf.openrocket.util.TextUtil;
@SuppressWarnings("serial")
@ -31,11 +34,15 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
Component comp = super.getTreeCellRendererComponent(tree, value, sel,
expanded, leaf, row, hasFocus1);
if (tree == null) return comp;
TreePath[] paths = tree.getSelectionPaths();
List<RocketComponent> components = null;
if (paths != null && paths.length > 0) {
components = new ArrayList<>(ComponentTreeModel.componentsFromPaths(paths));
}
// Set icon
RocketComponent c = (RocketComponent) value;
if (c.getClass().isAssignableFrom(MassComponent.class)) {
MassComponentType t = ((MassComponent) c).getMassComponentType();
setIcon(ComponentIcons.getSmallMassTypeIcon(t));
@ -54,17 +61,26 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
if (c.isCGOverridden()) {
p.add(new JLabel(Icons.CG_OVERRIDE));
}
p.setToolTipText(getToolTip(c));
if (components != null && components.size() > 1 && components.contains(c)) {
p.setToolTipText(getToolTipMultipleComponents(components));
} else {
p.setToolTipText(getToolTipSingleComponent(c));
}
comp = p;
}
// Set tooltip
this.setToolTipText(getToolTip(c));
if (components != null && components.size() > 1 && components.contains(c)) {
this.setToolTipText(getToolTipMultipleComponents(components));
} else {
this.setToolTipText(getToolTipSingleComponent(c));
}
return comp;
}
private static String getToolTip(RocketComponent c) {
private static String getToolTipSingleComponent(RocketComponent c) {
StringBuilder sb = new StringBuilder();
sb.append("<html>");
@ -104,4 +120,55 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
return sb.toString();
}
private static String getToolTipMultipleComponents(List<RocketComponent> components) {
if (components == null || components.size() == 0) {
return null;
}
StringBuilder sb = new StringBuilder();
sb.append("<html>");
sb.append("<b>Components</b>");
double totalMass = 0;
double totalSectionMass = 0;
boolean containsSectionMass = false;
for (RocketComponent c : components) {
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
if (!RocketComponent.listContainsParent(components, c)) {
if (c.getChildCount() > 0 && c.getSectionMass() > 0) {
totalSectionMass += c.getSectionMass();
containsSectionMass = true;
} else {
totalSectionMass += c.getMass();
}
}
} else if ((c.getChildCount() > 0) && (c.getSectionMass() > 0)) {
totalMass = c.getSectionMass();
containsSectionMass = false;
break;
}
}
sb.append(" (").append(UnitGroup.UNITS_MASS.toStringUnit(totalMass));
if (containsSectionMass) {
sb.append(" of ").append(UnitGroup.UNITS_MASS.toStringUnit(totalSectionMass)).append(" total)");
} else {
sb.append(")");
}
// Set the component names as description
sb.append("<br>");
for (int i = 0; i < components.size(); i++) {
if (i < components.size() - 1) {
sb.append(components.get(i).getName()).append(", ");
} else {
sb.append(components.get(i).getName());
}
}
return sb.toString();
}
}

View File

@ -16,7 +16,6 @@ import javax.swing.TransferHandler;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import net.sf.openrocket.gui.main.RocketActions;
import net.sf.openrocket.util.ArrayList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -73,7 +72,7 @@ public class ComponentTreeTransferHandler extends TransferHandler {
// When the parent of a child is in the selection, don't include the child in components
for (RocketComponent component : new ArrayList<>(components)) {
if (RocketActions.listContainsParent(components, component)) {
if (RocketComponent.listContainsParent(components, component)) {
components.remove(component);
}
}