package net.sf.openrocket.gui.dialogs.preferences;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Iterator;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.database.Database;
import net.sf.openrocket.database.Databases;
import net.sf.openrocket.gui.adaptors.Column;
import net.sf.openrocket.gui.adaptors.ColumnTable;
import net.sf.openrocket.gui.adaptors.ColumnTableModel;
import net.sf.openrocket.gui.components.StyledLabel;
import net.sf.openrocket.gui.components.StyledLabel.Style;
import net.sf.openrocket.gui.dialogs.CustomMaterialDialog;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.unit.Value;
public class MaterialEditPanel extends JPanel {
private final JTable table;
private final JButton addButton;
private final JButton editButton;
private final JButton deleteButton;
private final JButton revertButton;
private static final Translator trans = Application.getTranslator();
public MaterialEditPanel() {
super(new MigLayout("fill"));
// TODO: LOW: Create sorter that keeps material types always in order
final ColumnTableModel model = new ColumnTableModel(
//// Material
new Column(trans.get("matedtpan.col.Material")) {
@Override
public Object getValueAt(int row) {
return getMaterial(row).getName();
}
},
//// Type
new Column(trans.get("matedtpan.col.Type")) {
@Override
public Object getValueAt(int row) {
return getMaterial(row).getType().toString();
}
@Override
public int getDefaultWidth() {
return 15;
}
},
//// Density
new Column(trans.get("matedtpan.col.Density")) {
@Override
public Object getValueAt(int row) {
Material m = getMaterial(row);
double d = m.getDensity();
switch (m.getType()) {
case LINE:
return UnitGroup.UNITS_DENSITY_LINE.toValue(d);
case SURFACE:
return UnitGroup.UNITS_DENSITY_SURFACE.toValue(d);
case BULK:
return UnitGroup.UNITS_DENSITY_BULK.toValue(d);
default:
throw new IllegalStateException("Material type " + m.getType());
}
}
@Override
public int getDefaultWidth() {
return 15;
}
@Override
public Class<?> getColumnClass() {
return Value.class;
}
}
) {
@Override
public int getRowCount() {
return Databases.BULK_MATERIAL.size() + Databases.SURFACE_MATERIAL.size() +
Databases.LINE_MATERIAL.size();
}
};
table = new ColumnTable(model);
model.setColumnWidths(table.getColumnModel());
table.setAutoCreateRowSorter(true);
table.setDefaultRenderer(Object.class, new MaterialCellRenderer());
this.add(new JScrollPane(table), "w 200px, h 100px, grow 100");
//// New button
addButton = new JButton(trans.get("matedtpan.but.new"));
//// Add a new material
addButton.setToolTipText(trans.get("matedtpan.col.but.ttip.New"));
addButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
CustomMaterialDialog dialog = new CustomMaterialDialog(
SwingUtilities.getWindowAncestor(MaterialEditPanel.this),
//// Add a custom material
null, false, trans.get("matedtpan.title.Addcustmaterial"));
dialog.setVisible(true);
if (dialog.getOkClicked()) {
Material mat = dialog.getMaterial();
getDatabase(mat).add(mat);
model.fireTableDataChanged();
setButtonStates();
}
}
});
this.add(addButton, "gap rel rel para para, w 70lp, split 5, flowy, growx 1, top");
//// Edit button
editButton = new JButton(trans.get("matedtpan.but.edit"));
//// Edit an existing material
editButton.setToolTipText(trans.get("matedtpan.but.ttip.edit"));
editButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int sel = table.getSelectedRow();
if (sel < 0)
return;
sel = table.convertRowIndexToModel(sel);
Material m = getMaterial(sel);
CustomMaterialDialog dialog;
if (m.isUserDefined()) {
dialog = new CustomMaterialDialog(
SwingUtilities.getWindowAncestor(MaterialEditPanel.this),
//// Edit material
m, false, trans.get("matedtpan.title.Editmaterial"));
} else {
dialog = new CustomMaterialDialog(
SwingUtilities.getWindowAncestor(MaterialEditPanel.this),
//// Add a custom material
m, false, trans.get("matedtpan.title.Addcustmaterial"),
//// The built-in materials cannot be modified.
trans.get("matedtpan.title2.Editmaterial"));
}
dialog.setVisible(true);
if (dialog.getOkClicked()) {
if (m.isUserDefined()) {
getDatabase(m).remove(m);
}
Material mat = dialog.getMaterial();
getDatabase(mat).add(mat);
model.fireTableDataChanged();
setButtonStates();
}
}
});
this.add(editButton, "gap rel rel para para, growx 1, top");
//// Delete button
deleteButton = new JButton(trans.get("matedtpan.but.delete"));
//// Delete a user-defined material
deleteButton.setToolTipText(trans.get("matedtpan.but.ttip.delete"));
deleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int sel = table.getSelectedRow();
if (sel < 0)
return;
sel = table.convertRowIndexToModel(sel);
Material m = getMaterial(sel);
if (!m.isUserDefined())
return;
getDatabase(m).remove(m);
model.fireTableDataChanged();
setButtonStates();
}
});
this.add(deleteButton, "gap rel rel para para, growx 1, top");
this.add(new JPanel(), "grow 1");
//// Revert all button
revertButton = new JButton(trans.get("matedtpan.but.revertall"));
//// Delete all user-defined materials
revertButton.setToolTipText(trans.get("matedtpan.but.ttip.revertall"));
revertButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int sel = JOptionPane.showConfirmDialog(MaterialEditPanel.this,
//// Delete all user-defined materials?
trans.get("matedtpan.title.Deletealluser-defined"),
//// Revert all?
trans.get("matedtpan.title.Revertall"),
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
if (sel == JOptionPane.YES_OPTION) {
Iterator<Material> iterator;
iterator = Databases.LINE_MATERIAL.iterator();
while (iterator.hasNext()) {
if (iterator.next().isUserDefined())
iterator.remove();
}
iterator = Databases.SURFACE_MATERIAL.iterator();
while (iterator.hasNext()) {
if (iterator.next().isUserDefined())
iterator.remove();
}
iterator = Databases.BULK_MATERIAL.iterator();
while (iterator.hasNext()) {
if (iterator.next().isUserDefined())
iterator.remove();
}
model.fireTableDataChanged();
setButtonStates();
}
}
});
this.add(revertButton, "gap rel rel para para, growx 1, bottom, wrap unrel");
setButtonStates();
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
setButtonStates();
}
});
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
editButton.doClick();
}
}
});
//// <html><i>Editing materials will not affect existing
//// rocket designs.</i>
this.add(new StyledLabel(trans.get("matedtpan.lbl.edtmaterials"), -2, Style.ITALIC), "span");
}
private Database<Material> getDatabase(Material m) {
switch (m.getType()) {
case BULK:
return Databases.BULK_MATERIAL;
case SURFACE:
return Databases.SURFACE_MATERIAL;
case LINE:
return Databases.LINE_MATERIAL;
default:
throw new IllegalArgumentException("Material type invalid, m=" + m);
}
}
private void setButtonStates() {
int sel = table.getSelectedRow();
// Add button always enabled
addButton.setEnabled(true);
// Edit button enabled if a material is selected
editButton.setEnabled(sel >= 0);
// Delete button enabled if a user-defined material is selected
if (sel >= 0) {
int modelRow = table.convertRowIndexToModel(sel);
deleteButton.setEnabled(getMaterial(modelRow).isUserDefined());
} else {
deleteButton.setEnabled(false);
}
// Revert button enabled if any user-defined material exists
boolean found = false;
for (Material m : Databases.BULK_MATERIAL) {
if (m.isUserDefined()) {
found = true;
break;
}
}
if (!found) {
for (Material m : Databases.SURFACE_MATERIAL) {
if (m.isUserDefined()) {
found = true;
break;
}
}
}
if (!found) {
for (Material m : Databases.LINE_MATERIAL) {
if (m.isUserDefined()) {
found = true;
break;
}
}
}
revertButton.setEnabled(found);
}
private Material getMaterial(int origRow) {
int row = origRow;
int n;
n = Databases.BULK_MATERIAL.size();
if (row < n) {
return Databases.BULK_MATERIAL.get(row);
}
row -= n;
n = Databases.SURFACE_MATERIAL.size();
if (row < n) {
return Databases.SURFACE_MATERIAL.get(row);
}
row -= n;
n = Databases.LINE_MATERIAL.size();
if (row < n) {
return Databases.LINE_MATERIAL.get(row);
}
throw new IndexOutOfBoundsException("row=" + origRow + " while material count" +
" bulk:" + Databases.BULK_MATERIAL.size() +
" surface:" + Databases.SURFACE_MATERIAL.size() +
" line:" + Databases.LINE_MATERIAL.size());
}
private class MaterialCellRenderer extends DefaultTableCellRenderer {
/* (non-Javadoc)
* @see javax.swing.table.DefaultTableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int)
*/
@Override
public Component getTableCellRendererComponent(JTable myTable, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
Component c = super.getTableCellRendererComponent(myTable, value, isSelected,
hasFocus, row, column);
if (c instanceof JLabel) {
JLabel label = (JLabel) c;
Material m = getMaterial(row);
if (isSelected) {
if (m.isUserDefined())
label.setForeground(myTable.getSelectionForeground());
else
label.setForeground(Color.GRAY);
} else {
if (m.isUserDefined())
label.setForeground(myTable.getForeground());
else
label.setForeground(Color.GRAY);
}
}
return c;
}
}
}