[fixes #358] Implement multi-component selection in ScaleDialog
This commit is contained in:
		
							parent
							
								
									6157ce04b6
								
							
						
					
					
						commit
						04b9332920
					
				@ -1757,7 +1757,7 @@ Warning.ZERO_RADIUS_BODY = Zero length bodies may not result in accurate simulat
 | 
				
			|||||||
! Scale dialog
 | 
					! Scale dialog
 | 
				
			||||||
ScaleDialog.lbl.scaleRocket = Entire rocket
 | 
					ScaleDialog.lbl.scaleRocket = Entire rocket
 | 
				
			||||||
ScaleDialog.lbl.scaleSubselection = Selection and all subcomponents
 | 
					ScaleDialog.lbl.scaleSubselection = Selection and all subcomponents
 | 
				
			||||||
ScaleDialog.lbl.scaleSelection = Only selected component
 | 
					ScaleDialog.lbl.scaleSelection = Only selected component(s)
 | 
				
			||||||
ScaleDialog.title = Scale design
 | 
					ScaleDialog.title = Scale design
 | 
				
			||||||
ScaleDialog.lbl.scale = Scale:
 | 
					ScaleDialog.lbl.scale = Scale:
 | 
				
			||||||
ScaleDialog.lbl.scale.ttip = Select whether to scale the entire design or only the selected component
 | 
					ScaleDialog.lbl.scale.ttip = Select whether to scale the entire design or only the selected component
 | 
				
			||||||
@ -1769,6 +1769,8 @@ ScaleDialog.lbl.scaleTo = to
 | 
				
			|||||||
ScaleDialog.lbl.scaleFromTo.ttip = Define the scaling based on an original and resulting length.
 | 
					ScaleDialog.lbl.scaleFromTo.ttip = Define the scaling based on an original and resulting length.
 | 
				
			||||||
ScaleDialog.checkbox.scaleMass = Update explicit mass values
 | 
					ScaleDialog.checkbox.scaleMass = Update explicit mass values
 | 
				
			||||||
ScaleDialog.checkbox.scaleMass.ttip = Scale mass component and override mass values by the cube of the scaling factor
 | 
					ScaleDialog.checkbox.scaleMass.ttip = Scale mass component and override mass values by the cube of the scaling factor
 | 
				
			||||||
 | 
					ScaleDialog.checkbox.scaleOffsets = Scale component offsets
 | 
				
			||||||
 | 
					ScaleDialog.checkbox.scaleOffsets.ttip = Also scale offsets between components
 | 
				
			||||||
ScaleDialog.button.scale = Scale
 | 
					ScaleDialog.button.scale = Scale
 | 
				
			||||||
ScaleDialog.undo.scaleRocket = Scale rocket
 | 
					ScaleDialog.undo.scaleRocket = Scale rocket
 | 
				
			||||||
ScaleDialog.undo.scaleComponent = Scale component
 | 
					ScaleDialog.undo.scaleComponent = Scale component
 | 
				
			||||||
 | 
				
			|||||||
@ -17,6 +17,7 @@ import java.io.OutputStreamWriter;
 | 
				
			|||||||
import java.io.Writer;
 | 
					import java.io.Writer;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.EventObject;
 | 
					import java.util.EventObject;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.swing.JButton;
 | 
					import javax.swing.JButton;
 | 
				
			||||||
import javax.swing.JComboBox;
 | 
					import javax.swing.JComboBox;
 | 
				
			||||||
@ -241,7 +242,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
 | 
				
			|||||||
			@Override
 | 
								@Override
 | 
				
			||||||
			public void actionPerformed(ActionEvent e) {
 | 
								public void actionPerformed(ActionEvent e) {
 | 
				
			||||||
				log.info(Markers.USER_MARKER, "Scaling free-form fin");
 | 
									log.info(Markers.USER_MARKER, "Scaling free-form fin");
 | 
				
			||||||
				ScaleDialog dialog = new ScaleDialog(document, finset, SwingUtilities.getWindowAncestor(FreeformFinSetConfig.this), true);
 | 
									ScaleDialog dialog = new ScaleDialog(document, new ArrayList<>(List.of(finset)), SwingUtilities.getWindowAncestor(FreeformFinSetConfig.this), true);
 | 
				
			||||||
				dialog.setVisible(true);
 | 
									dialog.setVisible(true);
 | 
				
			||||||
				dialog.dispose();
 | 
									dialog.dispose();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,10 @@ package net.sf.openrocket.gui.dialogs;
 | 
				
			|||||||
import java.awt.Window;
 | 
					import java.awt.Window;
 | 
				
			||||||
import java.awt.event.ActionEvent;
 | 
					import java.awt.event.ActionEvent;
 | 
				
			||||||
import java.awt.event.ActionListener;
 | 
					import java.awt.event.ActionListener;
 | 
				
			||||||
 | 
					import java.awt.event.ItemEvent;
 | 
				
			||||||
 | 
					import java.awt.event.ItemListener;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
@ -194,22 +197,23 @@ public class ScaleDialog extends JDialog {
 | 
				
			|||||||
	private final DoubleModel toField = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
 | 
						private final DoubleModel toField = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	private final OpenRocketDocument document;
 | 
						private final OpenRocketDocument document;
 | 
				
			||||||
	private final RocketComponent selection;
 | 
						private final List<RocketComponent> selection;
 | 
				
			||||||
	private final boolean onlySelection;
 | 
						private final boolean onlySelection;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	private JComboBox<String> selectionOption;
 | 
						private JComboBox<String> selectionOption;
 | 
				
			||||||
	private JCheckBox scaleMassValues;
 | 
						private JCheckBox scaleMassValues;
 | 
				
			||||||
 | 
						private JCheckBox scaleOffsets;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	private boolean changing = false;
 | 
						private boolean changing = false;
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Sole constructor.
 | 
						 * Sole constructor.
 | 
				
			||||||
	 * 
 | 
						 * 
 | 
				
			||||||
	 * @param document		the document to modify.
 | 
						 * @param document		the document to modify.
 | 
				
			||||||
	 * @param selection		the currently selected component (or <code>null</code> if none selected).
 | 
						 * @param selection		the currently selected componentents (or <code>null</code> if none selected).
 | 
				
			||||||
	 * @param parent		the parent window.
 | 
						 * @param parent		the parent window.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public ScaleDialog(OpenRocketDocument document, RocketComponent selection, Window parent) {
 | 
						public ScaleDialog(OpenRocketDocument document, List<RocketComponent> selection, Window parent) {
 | 
				
			||||||
		this(document, selection, parent, false);
 | 
							this(document, selection, parent, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@ -221,7 +225,7 @@ public class ScaleDialog extends JDialog {
 | 
				
			|||||||
	 * @param parent		the parent window.
 | 
						 * @param parent		the parent window.
 | 
				
			||||||
	 * @param onlySelection	true to only allow scaling on the selected component (not the whole rocket)
 | 
						 * @param onlySelection	true to only allow scaling on the selected component (not the whole rocket)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public ScaleDialog(OpenRocketDocument document, RocketComponent selection, Window parent, Boolean onlySelection) {
 | 
						public ScaleDialog(OpenRocketDocument document, List<RocketComponent> selection, Window parent, Boolean onlySelection) {
 | 
				
			||||||
		super(parent, trans.get("title"), ModalityType.APPLICATION_MODAL);
 | 
							super(parent, trans.get("title"), ModalityType.APPLICATION_MODAL);
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		this.document = document;
 | 
							this.document = document;
 | 
				
			||||||
@ -236,10 +240,21 @@ public class ScaleDialog extends JDialog {
 | 
				
			|||||||
		List<String> options = new ArrayList<String>();
 | 
							List<String> options = new ArrayList<String>();
 | 
				
			||||||
		if (!onlySelection)
 | 
							if (!onlySelection)
 | 
				
			||||||
			options.add(SCALE_ROCKET);
 | 
								options.add(SCALE_ROCKET);
 | 
				
			||||||
		if (selection != null && selection.getChildCount() > 0) {
 | 
					
 | 
				
			||||||
 | 
							boolean subPartsPresent = false;
 | 
				
			||||||
 | 
							if (selection != null) {
 | 
				
			||||||
 | 
								for (RocketComponent component : selection) {
 | 
				
			||||||
 | 
									if (component.getChildCount() > 0) {
 | 
				
			||||||
 | 
										subPartsPresent = true;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (selection != null && subPartsPresent) {
 | 
				
			||||||
			options.add(SCALE_SUBSELECTION);
 | 
								options.add(SCALE_SUBSELECTION);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (selection != null) {
 | 
					
 | 
				
			||||||
 | 
							if (selection != null && selection.size() > 0) {
 | 
				
			||||||
			options.add(SCALE_SELECTION);
 | 
								options.add(SCALE_SELECTION);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
@ -251,15 +266,16 @@ public class ScaleDialog extends JDialog {
 | 
				
			|||||||
		 * Otherwise the maximum body diameter is selected.  As a fallback DEFAULT_INITIAL_SIZE is used.
 | 
							 * Otherwise the maximum body diameter is selected.  As a fallback DEFAULT_INITIAL_SIZE is used.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		double initialSize = 0;
 | 
							double initialSize = 0;
 | 
				
			||||||
		if (selection != null) {
 | 
							if (selection != null && selection.size() == 1) {
 | 
				
			||||||
			if (selection instanceof SymmetricComponent) {
 | 
								RocketComponent component = selection.get(0);
 | 
				
			||||||
				SymmetricComponent s = (SymmetricComponent) selection;
 | 
								if (component instanceof SymmetricComponent) {
 | 
				
			||||||
 | 
									SymmetricComponent s = (SymmetricComponent) component;
 | 
				
			||||||
				initialSize = s.getForeRadius() * 2;
 | 
									initialSize = s.getForeRadius() * 2;
 | 
				
			||||||
				initialSize = MathUtil.max(initialSize, s.getAftRadius() * 2);
 | 
									initialSize = MathUtil.max(initialSize, s.getAftRadius() * 2);
 | 
				
			||||||
			}else if ((selection instanceof ParallelStage) || (selection instanceof PodSet )) {
 | 
								}else if ((component instanceof ParallelStage) || (component instanceof PodSet )) {
 | 
				
			||||||
				initialSize = selection.getRadiusOffset();
 | 
									initialSize = component.getRadiusOffset();
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				initialSize = selection.getLength();
 | 
									initialSize = component.getLength();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			for (RocketComponent c : document.getRocket()) {
 | 
								for (RocketComponent c : document.getRocket()) {
 | 
				
			||||||
@ -267,8 +283,6 @@ public class ScaleDialog extends JDialog {
 | 
				
			|||||||
					SymmetricComponent s = (SymmetricComponent) c;
 | 
										SymmetricComponent s = (SymmetricComponent) c;
 | 
				
			||||||
					initialSize = s.getForeRadius() * 2;
 | 
										initialSize = s.getForeRadius() * 2;
 | 
				
			||||||
					initialSize = MathUtil.max(initialSize, s.getAftRadius() * 2);
 | 
										initialSize = MathUtil.max(initialSize, s.getAftRadius() * 2);
 | 
				
			||||||
				} else if ((selection instanceof ParallelStage) || (selection instanceof PodSet )) {
 | 
					 | 
				
			||||||
					initialSize = selection.getRadiusOffset();
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -330,6 +344,18 @@ public class ScaleDialog extends JDialog {
 | 
				
			|||||||
		selectionOption.setEditable(false);
 | 
							selectionOption.setEditable(false);
 | 
				
			||||||
		selectionOption.setToolTipText(tip);
 | 
							selectionOption.setToolTipText(tip);
 | 
				
			||||||
		panel.add(selectionOption, "growx, wrap para*2");
 | 
							panel.add(selectionOption, "growx, wrap para*2");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Change the offset checkbox to false when 'Scale selection' is selection and only one component is selected,
 | 
				
			||||||
 | 
							// since this is a common action.
 | 
				
			||||||
 | 
							selectionOption.addItemListener(new ItemListener() {
 | 
				
			||||||
 | 
								@Override
 | 
				
			||||||
 | 
								public void itemStateChanged(ItemEvent e) {
 | 
				
			||||||
 | 
									if (SCALE_SELECTION.equals(selectionOption.getSelectedItem()) && (selection != null) &&
 | 
				
			||||||
 | 
											(selection.size() == 1) && (scaleOffsets != null)) {
 | 
				
			||||||
 | 
										scaleOffsets.setSelected(false);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		// Scale multiplier
 | 
							// Scale multiplier
 | 
				
			||||||
@ -393,7 +419,13 @@ public class ScaleDialog extends JDialog {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		scaleMassValues.setEnabled(overridden);
 | 
							scaleMassValues.setEnabled(overridden);
 | 
				
			||||||
		panel.add(scaleMassValues, "span, wrap para*3");
 | 
							panel.add(scaleMassValues, "span, wrap");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Scale offsets
 | 
				
			||||||
 | 
							scaleOffsets = new JCheckBox(trans.get("checkbox.scaleOffsets"));
 | 
				
			||||||
 | 
							scaleOffsets.setToolTipText(trans.get("checkbox.scaleOffsets.ttip"));
 | 
				
			||||||
 | 
							scaleOffsets.setSelected(true);
 | 
				
			||||||
 | 
							panel.add(scaleOffsets, "span, wrap para*3");
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		// Scale / Accept Buttons
 | 
							// Scale / Accept Buttons
 | 
				
			||||||
@ -455,7 +487,7 @@ public class ScaleDialog extends JDialog {
 | 
				
			|||||||
			try {
 | 
								try {
 | 
				
			||||||
				document.startUndo(trans.get("undo.scaleRocket"));
 | 
									document.startUndo(trans.get("undo.scaleRocket"));
 | 
				
			||||||
				for (RocketComponent c : document.getRocket()) {
 | 
									for (RocketComponent c : document.getRocket()) {
 | 
				
			||||||
					scale(c, mul, scaleMass, true);
 | 
										scale(c, mul, scaleMass, scaleOffsets.isSelected());
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} finally {
 | 
								} finally {
 | 
				
			||||||
				document.stopUndo();
 | 
									document.stopUndo();
 | 
				
			||||||
@ -466,9 +498,17 @@ public class ScaleDialog extends JDialog {
 | 
				
			|||||||
			// Scale component and subcomponents
 | 
								// Scale component and subcomponents
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
				document.startUndo(trans.get("undo.scaleComponents"));
 | 
									document.startUndo(trans.get("undo.scaleComponents"));
 | 
				
			||||||
				scale(selection, mul, scaleMass, false);
 | 
					
 | 
				
			||||||
				for (RocketComponent c : selection.getChildren()) {
 | 
									// Keep track of which components are already scaled so that we don't scale children multiple times (if
 | 
				
			||||||
					scale(c, mul, scaleMass, true);
 | 
									// they were also part of selection)
 | 
				
			||||||
 | 
									List<RocketComponent> scaledComponents = new ArrayList<>();
 | 
				
			||||||
 | 
									for (RocketComponent component : selection) {
 | 
				
			||||||
 | 
										scale(component, mul, scaleMass, scaleOffsets.isSelected());
 | 
				
			||||||
 | 
										scaledComponents.add(component);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (component.getChildCount() > 0) {
 | 
				
			||||||
 | 
											scaleChildren(component, scaledComponents, mul, scaleMass);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} finally {
 | 
								} finally {
 | 
				
			||||||
				document.stopUndo();
 | 
									document.stopUndo();
 | 
				
			||||||
@ -476,10 +516,13 @@ public class ScaleDialog extends JDialog {
 | 
				
			|||||||
			
 | 
								
 | 
				
			||||||
		} else if (SCALE_SELECTION.equals(item)) {
 | 
							} else if (SCALE_SELECTION.equals(item)) {
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			// Scale only the selected component
 | 
								// Scale only the selected components
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
				document.startUndo(trans.get("undo.scaleComponent"));
 | 
									document.startUndo(trans.get("undo.scaleComponent"));
 | 
				
			||||||
				scale(selection, mul, scaleMass, false);
 | 
					
 | 
				
			||||||
 | 
									for (RocketComponent component : selection) {
 | 
				
			||||||
 | 
										scale(component, mul, scaleMass, scaleOffsets.isSelected());
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			} finally {
 | 
								} finally {
 | 
				
			||||||
				document.stopUndo();
 | 
									document.stopUndo();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -519,6 +562,22 @@ public class ScaleDialog extends JDialog {
 | 
				
			|||||||
			clazz = clazz.getSuperclass();
 | 
								clazz = clazz.getSuperclass();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Iteratively scale the children of component. If one of the children was already present in scaledComponents,
 | 
				
			||||||
 | 
						 * don't scale it.
 | 
				
			||||||
 | 
						 * @param component component whose children need to be scaled
 | 
				
			||||||
 | 
						 * @param scaledComponents list of components that were already scaled
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private void scaleChildren(RocketComponent component, List<RocketComponent> scaledComponents, double mul, boolean scaleMass) {
 | 
				
			||||||
 | 
							for (RocketComponent child : component.getChildren()) {
 | 
				
			||||||
 | 
								if (!scaledComponents.contains(component)) {
 | 
				
			||||||
 | 
									scale(child, mul, scaleMass, scaleOffsets.isSelected());
 | 
				
			||||||
 | 
									scaledComponents.add(child);
 | 
				
			||||||
 | 
									scaleChildren(child, scaledComponents, mul, scaleMass);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	private void updateToField() {
 | 
						private void updateToField() {
 | 
				
			||||||
 | 
				
			|||||||
@ -407,6 +407,24 @@ public class BasicFrame extends JFrame {
 | 
				
			|||||||
		return (RocketComponent) path.getLastPathComponent();
 | 
							return (RocketComponent) path.getLastPathComponent();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Return the currently selected rocket component, or <code>null</code> if none selected.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private List<RocketComponent> getSelectedComponents() {
 | 
				
			||||||
 | 
							TreePath[] paths = componentSelectionModel.getSelectionPaths();
 | 
				
			||||||
 | 
							if (paths == null || paths.length == 0)
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							List<RocketComponent> result = new LinkedList<>();
 | 
				
			||||||
 | 
							for (TreePath path : paths) {
 | 
				
			||||||
 | 
								tree.scrollPathToVisible(path);
 | 
				
			||||||
 | 
								RocketComponent component = (RocketComponent) path.getLastPathComponent();
 | 
				
			||||||
 | 
								result.add(component);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return result;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Creates the menu for the window.
 | 
						 * Creates the menu for the window.
 | 
				
			||||||
@ -651,7 +669,7 @@ public class BasicFrame extends JFrame {
 | 
				
			|||||||
			@Override
 | 
								@Override
 | 
				
			||||||
			public void actionPerformed(ActionEvent e) {
 | 
								public void actionPerformed(ActionEvent e) {
 | 
				
			||||||
				log.info(Markers.USER_MARKER, "Scale... selected");
 | 
									log.info(Markers.USER_MARKER, "Scale... selected");
 | 
				
			||||||
				ScaleDialog dialog = new ScaleDialog(document, getSelectedComponent(), BasicFrame.this);
 | 
									ScaleDialog dialog = new ScaleDialog(document, getSelectedComponents(), BasicFrame.this);
 | 
				
			||||||
				dialog.setVisible(true);
 | 
									dialog.setVisible(true);
 | 
				
			||||||
				dialog.dispose();
 | 
									dialog.dispose();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user