diff --git a/core/src/main/resources/l10n/messages.properties b/core/src/main/resources/l10n/messages.properties
index d51d999e0..5ed6d7b46 100644
--- a/core/src/main/resources/l10n/messages.properties
+++ b/core/src/main/resources/l10n/messages.properties
@@ -278,6 +278,10 @@ matedtpan.but.ttip.revertall = Delete all user-defined materials
matedtpan.title.Deletealluser-defined = Delete all user-defined materials?
matedtpan.title.Revertall = Revert all?
matedtpan.lbl.edtmaterials = Editing materials will not affect existing rocket designs.
+matedtpan.dlg.RemoveUsedMaterial.Application.title = Material used by component(s)
+matedtpan.dlg.RemoveUsedMaterial.Application.msg = The material is currently used in the following designs and components:
%s
The material will be converted from an Application material to a Document material.
+matedtpan.dlg.RemoveUsedMaterial.Document.title = Cannot remove material
+matedtpan.dlg.RemoveUsedMaterial.Document.msg = The material cannot be removed because it is used in the following designs and components:
%s
!MaterialModel
MaterialModel.title.Material = Material
diff --git a/swing/src/main/java/info/openrocket/swing/gui/dialogs/preferences/MaterialEditPanel.java b/swing/src/main/java/info/openrocket/swing/gui/dialogs/preferences/MaterialEditPanel.java
index eb8a695e2..c9863f1f0 100644
--- a/swing/src/main/java/info/openrocket/swing/gui/dialogs/preferences/MaterialEditPanel.java
+++ b/swing/src/main/java/info/openrocket/swing/gui/dialogs/preferences/MaterialEditPanel.java
@@ -6,7 +6,12 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import javax.swing.JButton;
import javax.swing.JLabel;
@@ -20,6 +25,8 @@ import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import info.openrocket.core.document.OpenRocketDocument;
+import info.openrocket.core.rocketcomponent.RocketComponent;
+import info.openrocket.swing.gui.main.BasicFrame;
import net.miginfocom.swing.MigLayout;
import info.openrocket.core.database.Databases;
@@ -200,7 +207,7 @@ public class MaterialEditPanel extends JPanel {
return;
}
// Remove the original material
- removeMaterial(m);
+ removeMaterial(m, false);
// Add the edited material
Material mat = dialog.getMaterial();
@@ -227,7 +234,7 @@ public class MaterialEditPanel extends JPanel {
Material m = getMaterial(sel);
if (!m.isUserDefined())
return;
- removeMaterial(m);
+ removeMaterial(m, true);
model.fireTableDataChanged();
setButtonStates();
}
@@ -324,14 +331,82 @@ public class MaterialEditPanel extends JPanel {
}
}
- private void removeMaterial(Material m) {
- // TODO: what if a component is currently using the material?
+ private void removeMaterial(Material m, boolean checkForComponentsInUse) {
+ Map> components = getComponentsThatUseMaterial(m);
+
if (m.isDocumentMaterial()) {
+ if (checkForComponentsInUse && !components.isEmpty()) {
+ String componentsTxt = formatDocumentComponentsMap(components);
+ JOptionPane.showMessageDialog(MaterialEditPanel.this,
+ String.format(trans.get("matedtpan.dlg.RemoveUsedMaterial.Document.msg"), componentsTxt),
+ trans.get("matedtpan.dlg.RemoveUsedMaterial.Document.title"), JOptionPane.WARNING_MESSAGE);
+ return;
+ }
document.getDocumentPreferences().removeMaterial(m);
} else {
+ if (checkForComponentsInUse && !components.isEmpty()) {
+ String componentsTxt = formatDocumentComponentsMap(components);
+ JOptionPane.showMessageDialog(MaterialEditPanel.this,
+ String.format(trans.get("matedtpan.dlg.RemoveUsedMaterial.Application.msg"), componentsTxt),
+ trans.get("matedtpan.dlg.RemoveUsedMaterial.Application.title"), JOptionPane.WARNING_MESSAGE);
+ Databases.removeMaterial(m);
+ m.setDocumentMaterial(true);
+ document.getDocumentPreferences().addMaterial(m);
+ return;
+ }
Databases.removeMaterial(m);
}
}
+
+ private String formatDocumentComponentsMap(Map> components) {
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry> entry: components.entrySet()) {
+ OpenRocketDocument doc = entry.getKey();
+ List comps = entry.getValue();
+ File file = doc.getFile();
+ String fileName = file == null ? "<" + "Unsaved" + ">" : file.getName();
+ sb.append(fileName);
+ sb.append(": ");
+ for (RocketComponent comp: comps) {
+ sb.append(comp.getName());
+ sb.append(", ");
+ }
+ sb.delete(sb.length() - 2, sb.length());
+ sb.append("
");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Parse all open documents and return a map of documents and components that use the material.
+ * @param m The material to search for
+ * @return A map of documents and components that use the material.
+ */
+ private Map> getComponentsThatUseMaterial(Material m) {
+ Map> result = new HashMap<>();
+ for (BasicFrame frame: BasicFrame.getAllFrames()) {
+ OpenRocketDocument doc = frame.getRocketPanel().getDocument();
+ List components = new ArrayList<>();
+ for (RocketComponent component: doc.getRocket()) {
+ // Parse the materials of the component
+ List materials = component.getAllMaterials();
+ if (materials == null) {
+ continue;
+ }
+ for (Material componentMaterial: materials) {
+ if (m.equals(componentMaterial)) {
+ components.add(component);
+ break;
+ }
+ }
+ }
+
+ if (!components.isEmpty()) {
+ result.put(doc, components);
+ }
+ }
+ return result;
+ }
private void setButtonStates() {