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() {