Merge pull request #1412 from SiboVG/issue-1411
[#1411] Show combined mass of multi-selection hover in component
This commit is contained in:
commit
213a9b9063
@ -1640,6 +1640,24 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
|||||||
|
|
||||||
return result;
|
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.
|
* Get the root component of the component tree.
|
||||||
|
@ -278,24 +278,6 @@ public class RocketActions {
|
|||||||
return result;
|
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
|
* 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.
|
* 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
|
// 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
|
// not selected, add it to the selection
|
||||||
RocketComponent temp = component;
|
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())) {
|
while (!selections.contains(temp.getParent())) {
|
||||||
selections.add(temp.getParent());
|
selections.add(temp.getParent());
|
||||||
temp = temp.getParent();
|
temp = temp.getParent();
|
||||||
@ -1038,7 +1020,7 @@ public class RocketActions {
|
|||||||
|
|
||||||
for (RocketComponent component : components) {
|
for (RocketComponent component : components) {
|
||||||
// Only move top components, don't move its children
|
// Only move top components, don't move its children
|
||||||
if (!listContainsParent(components, component)) {
|
if (!RocketComponent.listContainsParent(components, component)) {
|
||||||
moveUp(component);
|
moveUp(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1075,7 +1057,7 @@ public class RocketActions {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (RocketComponent component : components) {
|
for (RocketComponent component : components) {
|
||||||
if (!listContainsParent(components, component) && !canMove(component))
|
if (!RocketComponent.listContainsParent(components, component) && !canMove(component))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -1113,7 +1095,7 @@ public class RocketActions {
|
|||||||
|
|
||||||
for (RocketComponent component : components) {
|
for (RocketComponent component : components) {
|
||||||
// Only move top components, don't move its children
|
// Only move top components, don't move its children
|
||||||
if (!listContainsParent(components, component)) {
|
if (!RocketComponent.listContainsParent(components, component)) {
|
||||||
moveDown(component);
|
moveDown(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1150,7 +1132,7 @@ public class RocketActions {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (RocketComponent component : components) {
|
for (RocketComponent component : components) {
|
||||||
if (!listContainsParent(components, component) && !canMove(component))
|
if (!RocketComponent.listContainsParent(components, component) && !canMove(component))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -2,12 +2,14 @@ package net.sf.openrocket.gui.main.componenttree;
|
|||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.FlowLayout;
|
import java.awt.FlowLayout;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JTree;
|
import javax.swing.JTree;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||||
|
import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
import net.sf.openrocket.gui.main.ComponentIcons;
|
import net.sf.openrocket.gui.main.ComponentIcons;
|
||||||
import net.sf.openrocket.gui.util.Icons;
|
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.rocketcomponent.RocketComponent;
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.unit.UnitGroup;
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
|
import net.sf.openrocket.util.ArrayList;
|
||||||
import net.sf.openrocket.util.TextUtil;
|
import net.sf.openrocket.util.TextUtil;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
@ -31,11 +34,15 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
|
|||||||
|
|
||||||
Component comp = super.getTreeCellRendererComponent(tree, value, sel,
|
Component comp = super.getTreeCellRendererComponent(tree, value, sel,
|
||||||
expanded, leaf, row, hasFocus1);
|
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
|
// Set icon
|
||||||
|
|
||||||
RocketComponent c = (RocketComponent) value;
|
RocketComponent c = (RocketComponent) value;
|
||||||
|
|
||||||
if (c.getClass().isAssignableFrom(MassComponent.class)) {
|
if (c.getClass().isAssignableFrom(MassComponent.class)) {
|
||||||
MassComponentType t = ((MassComponent) c).getMassComponentType();
|
MassComponentType t = ((MassComponent) c).getMassComponentType();
|
||||||
setIcon(ComponentIcons.getSmallMassTypeIcon(t));
|
setIcon(ComponentIcons.getSmallMassTypeIcon(t));
|
||||||
@ -54,17 +61,26 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
|
|||||||
if (c.isCGOverridden()) {
|
if (c.isCGOverridden()) {
|
||||||
p.add(new JLabel(Icons.CG_OVERRIDE));
|
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;
|
comp = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set tooltip
|
if (components != null && components.size() > 1 && components.contains(c)) {
|
||||||
this.setToolTipText(getToolTip(c));
|
this.setToolTipText(getToolTipMultipleComponents(components));
|
||||||
|
} else {
|
||||||
|
this.setToolTipText(getToolTipSingleComponent(c));
|
||||||
|
}
|
||||||
|
|
||||||
return comp;
|
return comp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getToolTip(RocketComponent c) {
|
private static String getToolTipSingleComponent(RocketComponent c) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("<html>");
|
sb.append("<html>");
|
||||||
|
|
||||||
@ -104,4 +120,55 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
|
|||||||
return sb.toString();
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ import javax.swing.TransferHandler;
|
|||||||
import javax.swing.tree.TreeModel;
|
import javax.swing.tree.TreeModel;
|
||||||
import javax.swing.tree.TreePath;
|
import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
import net.sf.openrocket.gui.main.RocketActions;
|
|
||||||
import net.sf.openrocket.util.ArrayList;
|
import net.sf.openrocket.util.ArrayList;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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
|
// When the parent of a child is in the selection, don't include the child in components
|
||||||
for (RocketComponent component : new ArrayList<>(components)) {
|
for (RocketComponent component : new ArrayList<>(components)) {
|
||||||
if (RocketActions.listContainsParent(components, component)) {
|
if (RocketComponent.listContainsParent(components, component)) {
|
||||||
components.remove(component);
|
components.remove(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user