/*
* ModelMaterialsComponent.java 26 oct. 2012
*
* Sweet Home 3D, Copyright (c) 2012 Emmanuel PUYBARET / eTeks <info@eteks.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.eteks.sweethome3d.swing;
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Locale;
import javax.media.j3d.BranchGroup;
import javax.swing.AbstractButton;
import javax.swing.AbstractListModel;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.KeyStroke;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import com.eteks.sweethome3d.j3d.ModelManager;
import com.eteks.sweethome3d.model.HomeMaterial;
import com.eteks.sweethome3d.model.HomeTexture;
import com.eteks.sweethome3d.model.UserPreferences;
import com.eteks.sweethome3d.tools.OperatingSystem;
import com.eteks.sweethome3d.viewcontroller.ModelMaterialsController;
import com.eteks.sweethome3d.viewcontroller.TextureChoiceController;
import com.eteks.sweethome3d.viewcontroller.View;
/**
* Button giving access to materials editor. When the user clicks
* on this button a dialog appears to let him choose materials.
*/
public class ModelMaterialsComponent extends JButton implements View {
/**
* Creates a texture button.
*/
public ModelMaterialsComponent(final UserPreferences preferences,
final ModelMaterialsController controller) {
setText(SwingTools.getLocalizedLabelText(preferences, ModelMaterialsComponent.class, "modifyButton.text"));
if (!OperatingSystem.isMacOSX()) {
setMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString(
ModelMaterialsComponent.class, "modifyButton.mnemonic")).getKeyCode());
}
// Add a listener to update materials
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
final ModelMaterialsPanel texturePanel = new ModelMaterialsPanel(preferences, controller);
texturePanel.displayView(ModelMaterialsComponent.this);
}
});
}
/**
* A panel that displays available textures in a list to let user make choose one.
*/
private static class ModelMaterialsPanel extends JPanel {
private final ModelMaterialsController controller;
private JLabel previewLabel;
private ModelPreviewComponent previewComponent;
private JLabel materialsLabel;
private JList materialsList;
private JLabel colorAndTextureLabel;
private JRadioButton defaultColorAndTextureRadioButton;
private JRadioButton colorRadioButton;
private ColorButton colorButton;
private JRadioButton textureRadioButton;
private JComponent textureComponent;
private JLabel shininessLabel;
private JSlider shininessSlider;
private PropertyChangeListener textureChangeListener;
public ModelMaterialsPanel(UserPreferences preferences,
ModelMaterialsController controller) {
super(new GridBagLayout());
this.controller = controller;
createComponents(preferences, controller);
setMnemonics(preferences);
layoutComponents();
}
/**
* Creates and initializes components.
*/
private void createComponents(final UserPreferences preferences,
final ModelMaterialsController controller) {
this.materialsLabel = new JLabel(SwingTools.getLocalizedLabelText(preferences,
ModelMaterialsComponent.class, "materialsLabel.text"));
this.materialsList = new JList(new MaterialsListModel(controller));
this.materialsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
this.materialsList.setCellRenderer(new MaterialListCellRenderer());
this.previewLabel = new JLabel(SwingTools.getLocalizedLabelText(preferences,
ModelMaterialsComponent.class, "previewLabel.text"));
this.previewComponent = new ModelPreviewComponent(true);
this.previewComponent.setFocusable(false);
ModelManager.getInstance().loadModel(controller.getModel(), new ModelManager.ModelObserver() {
public void modelUpdated(BranchGroup modelRoot) {
final MaterialsListModel materialsListModel = (MaterialsListModel)materialsList.getModel();
previewComponent.setModel(controller.getModel());
previewComponent.setModelRotationAndSize(controller.getModelRotation(),
controller.getModelWidth(), controller.getModelDepth(), controller.getModelHeight());
previewComponent.setBackFaceShown(controller.isBackFaceShown());
previewComponent.setModelMaterials(materialsListModel.getMaterials());
materialsListModel.addListDataListener(new ListDataListener() {
public void contentsChanged(ListDataEvent ev) {
previewComponent.setModelMaterials(materialsListModel.getMaterials());
}
public void intervalRemoved(ListDataEvent ev) {
}
public void intervalAdded(ListDataEvent ev) {
}
});
}
public void modelError(Exception ex) {
// Should happen only if model is missing
previewLabel.setVisible(false);
previewComponent.setVisible(false);
}
});
this.colorAndTextureLabel = new JLabel(SwingTools.getLocalizedLabelText(preferences,
ModelMaterialsComponent.class, "colorAndTextureLabel.text"));
// Create color and texture image radio buttons properties
this.defaultColorAndTextureRadioButton = new JRadioButton(SwingTools.getLocalizedLabelText(preferences,
ModelMaterialsComponent.class, "defaultColorAndTextureRadioButton.text"));
final ChangeListener defaultChoiceChangeListener = new ChangeListener() {
public void stateChanged(ChangeEvent ev) {
if (defaultColorAndTextureRadioButton.isEnabled() && defaultColorAndTextureRadioButton.isSelected()) {
HomeMaterial material = (HomeMaterial)materialsList.getSelectedValue();
((MaterialsListModel)materialsList.getModel()).setMaterialAt(
new HomeMaterial(material.getName(), null, null, material.getShininess()),
materialsList.getSelectedIndex());
}
}
};
this.defaultColorAndTextureRadioButton.addChangeListener(defaultChoiceChangeListener);
this.colorRadioButton = new JRadioButton(SwingTools.getLocalizedLabelText(preferences,
ModelMaterialsComponent.class, "colorRadioButton.text"));
final ChangeListener colorChoiceChangeListener = new ChangeListener() {
public void stateChanged(ChangeEvent ev) {
if (colorRadioButton.isEnabled() && colorRadioButton.isSelected()) {
HomeMaterial material = (HomeMaterial)materialsList.getSelectedValue();
((MaterialsListModel)materialsList.getModel()).setMaterialAt(
new HomeMaterial(material.getName(), colorButton.getColor(), null, material.getShininess()),
materialsList.getSelectedIndex());
}
}
};
this.colorRadioButton.addChangeListener(colorChoiceChangeListener);
this.colorButton = new ColorButton(preferences);
this.colorButton.setColorDialogTitle(preferences.getLocalizedString(ModelMaterialsComponent.class, "colorDialog.title"));
final PropertyChangeListener colorChangeListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent ev) {
if (!colorRadioButton.isSelected()) {
colorRadioButton.setSelected(true);
} else {
colorChoiceChangeListener.stateChanged(null);
}
}
};
this.colorButton.addPropertyChangeListener(ColorButton.COLOR_PROPERTY, colorChangeListener);
final TextureChoiceController textureController = controller.getTextureController();
this.textureRadioButton = new JRadioButton(SwingTools.getLocalizedLabelText(preferences,
ModelMaterialsComponent.class, "textureRadioButton.text"));
final ChangeListener textureChoiceChangeListener = new ChangeListener() {
public void stateChanged(ChangeEvent ev) {
if (textureRadioButton.isEnabled() && textureRadioButton.isSelected()) {
HomeMaterial material = (HomeMaterial)materialsList.getSelectedValue();
((MaterialsListModel)materialsList.getModel()).setMaterialAt(
new HomeMaterial(material.getName(), null, textureController.getTexture(), material.getShininess()),
materialsList.getSelectedIndex());
}
}
};
this.textureRadioButton.addChangeListener(textureChoiceChangeListener);
this.textureComponent = (JComponent)textureController.getView();
this.textureChangeListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent ev) {
if (!textureRadioButton.isSelected()) {
textureRadioButton.setSelected(true);
} else {
textureChoiceChangeListener.stateChanged(null);
}
}
};
// Listener added and removed in displayView()
ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(this.defaultColorAndTextureRadioButton);
buttonGroup.add(this.colorRadioButton);
buttonGroup.add(this.textureRadioButton);
this.shininessLabel = new JLabel(SwingTools.getLocalizedLabelText(preferences,
ModelMaterialsComponent.class, "shininessLabel.text"));
this.shininessSlider = new JSlider(0, 128);
JLabel mattLabel = new JLabel(preferences.getLocalizedString(
ModelMaterialsComponent.class, "mattLabel.text"));
JLabel shinyLabel = new JLabel(preferences.getLocalizedString(
ModelMaterialsComponent.class, "shinyLabel.text"));
Dictionary<Integer,JComponent> shininessSliderLabelTable = new Hashtable<Integer,JComponent>();
shininessSliderLabelTable.put(0, mattLabel);
shininessSliderLabelTable.put(128, shinyLabel);
this.shininessSlider.setLabelTable(shininessSliderLabelTable);
this.shininessSlider.setPaintLabels(true);
this.shininessSlider.setPaintTicks(true);
this.shininessSlider.setMajorTickSpacing(16);
final ChangeListener shininessChangeListener = new ChangeListener() {
public void stateChanged(ChangeEvent ev) {
HomeMaterial material = (HomeMaterial)materialsList.getSelectedValue();
int shininess = shininessSlider.getValue();
((MaterialsListModel)materialsList.getModel()).setMaterialAt(
new HomeMaterial(material.getName(), material.getColor(), material.getTexture(), shininess / 128f),
materialsList.getSelectedIndex());
}
};
this.shininessSlider.addChangeListener(shininessChangeListener);
this.materialsList.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent ev) {
if (!materialsList.isSelectionEmpty()) {
defaultColorAndTextureRadioButton.removeChangeListener(defaultChoiceChangeListener);
colorRadioButton.removeChangeListener(colorChoiceChangeListener);
textureRadioButton.removeChangeListener(textureChoiceChangeListener);
colorButton.removePropertyChangeListener(ColorButton.COLOR_PROPERTY, colorChangeListener);
if (((JComponent)textureController.getView()).isShowing()) {
// Remove listener only if its texture component is shown because its listener is added later
textureController.removePropertyChangeListener(TextureChoiceController.Property.TEXTURE, textureChangeListener);
}
shininessSlider.removeChangeListener(shininessChangeListener);
HomeMaterial material = (HomeMaterial)materialsList.getSelectedValue();
HomeTexture texture = material.getTexture();
Integer color = material.getColor();
Float shininess = material.getShininess();
HomeMaterial defaultMaterial = ((MaterialsListModel)materialsList.getModel()).getDefaultMaterialAt(materialsList.getSelectedIndex());
if (color == null && texture == null) {
defaultColorAndTextureRadioButton.setSelected(true);
// Display default color or texture in buttons
texture = defaultMaterial.getTexture();
if (texture != null) {
colorButton.setColor(null);
controller.getTextureController().setTexture(texture);
} else {
color = defaultMaterial.getColor();
if (color != null) {
textureController.setTexture(null);
colorButton.setColor(color);
}
}
} else if (texture != null) {
textureRadioButton.setSelected(true);
colorButton.setColor(null);
textureController.setTexture(texture);
} else {
colorRadioButton.setSelected(true);
textureController.setTexture(null);
colorButton.setColor(color);
}
if (shininess != null) {
shininessSlider.setValue((int)(shininess * 128));
} else {
shininessSlider.setValue((int)(defaultMaterial.getShininess() * 128));
}
defaultColorAndTextureRadioButton.addChangeListener(defaultChoiceChangeListener);
colorRadioButton.addChangeListener(colorChoiceChangeListener);
textureRadioButton.addChangeListener(textureChoiceChangeListener);
colorButton.addPropertyChangeListener(ColorButton.COLOR_PROPERTY, colorChangeListener);
if (((JComponent)textureController.getView()).isShowing()) {
textureController.addPropertyChangeListener(TextureChoiceController.Property.TEXTURE, textureChangeListener);
}
shininessSlider.addChangeListener(shininessChangeListener);
}
enableComponents();
}
});
this.materialsList.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent ev) {
// Open color or texture choice dialogs on double clicks
if (ev.getClickCount() == 2 && !materialsList.isSelectionEmpty()) {
if (colorButton.getColor() != null) {
colorButton.doClick(200);
} else if (controller.getTextureController().getTexture() != null
&& textureComponent instanceof AbstractButton) {
((AbstractButton)textureComponent).doClick(200);
}
}
}
});
if (this.materialsList.getModel().getSize() > 0) {
this.materialsList.setSelectedIndex(0);
} else {
// Add a listener that will select first row as soon as the list contains some data
this.materialsList.getModel().addListDataListener(new ListDataListener() {
public void intervalAdded(ListDataEvent ev) {
materialsList.setSelectedIndex(0);
((ListModel)ev.getSource()).removeListDataListener(this);
}
public void contentsChanged(ListDataEvent ev) {
intervalAdded(ev);
}
public void intervalRemoved(ListDataEvent ev) {
}
});
}
enableComponents();
}
/**
* Renderer used to display the materials in list.
*/
private class MaterialListCellRenderer extends DefaultListCellRenderer {
private Font defaultFont;
private Icon emptyIcon = new Icon() {
public void paintIcon(Component c, Graphics g, int x, int y) {
}
public int getIconHeight() {
return defaultFont.getSize();
}
public int getIconWidth() {
return getIconHeight();
}
};
@Override
public Component getListCellRendererComponent(final JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
// Initialize fonts if not done
if (this.defaultFont == null) {
this.defaultFont = getFont();
}
HomeMaterial material = (HomeMaterial)value;
super.getListCellRendererComponent(list, material.getName(), index, isSelected, cellHasFocus);
HomeTexture materialTexture = material.getTexture();
Integer materialColor = material.getColor();
HomeMaterial defaultMaterial = ((MaterialsListModel)materialsList.getModel()).getDefaultMaterialAt(index);
if (materialTexture == null && materialColor == null) {
materialTexture = defaultMaterial.getTexture();
if (materialTexture == null) {
materialColor = defaultMaterial.getColor();
}
}
if (materialTexture != null) {
// Display material texture image with an icon
final HomeTexture texture = materialTexture;
setIcon(new Icon() {
public int getIconHeight() {
return defaultFont.getSize();
}
public int getIconWidth() {
return getIconHeight();
}
public void paintIcon(Component c, Graphics g, int x, int y) {
Icon icon = IconManager.getInstance().getIcon(texture.getImage(), getIconHeight(), list);
if (icon.getIconWidth() != icon.getIconHeight()) {
Graphics2D g2D = (Graphics2D)g;
AffineTransform previousTransform = g2D.getTransform();
g2D.translate(x, y);
g2D.scale((float)icon.getIconHeight() / icon.getIconWidth(), 1);
icon.paintIcon(c, g2D, 0, 0);
g2D.setTransform(previousTransform);
} else {
icon.paintIcon(c, g, x, y);
}
}
});
} else if (materialColor != null) {
// Display material color with an icon
final Color color = new Color(materialColor);
setIcon(new Icon () {
public int getIconHeight() {
return getFont().getSize();
}
public int getIconWidth() {
return getIconHeight();
}
public void paintIcon(Component c, Graphics g, int x, int y) {
int squareSize = getIconHeight();
g.setColor(color);
g.fillRect(x + 2, y + 2, squareSize - 3, squareSize - 3);
g.setColor(c.getParent().getParent().getForeground());
g.drawRect(x + 1, y + 1, squareSize - 2, squareSize - 2);
}
});
} else {
setIcon(this.emptyIcon);
}
return this;
}
}
/**
* Enables editing components according to current selection in materials list.
*/
private void enableComponents() {
boolean selectionEmpty = this.materialsList.isSelectionEmpty();
defaultColorAndTextureRadioButton.setEnabled(!selectionEmpty);
textureRadioButton.setEnabled(!selectionEmpty);
textureComponent.setEnabled(!selectionEmpty);
colorRadioButton.setEnabled(!selectionEmpty);
colorButton.setEnabled(!selectionEmpty);
shininessSlider.setEnabled(!selectionEmpty);
}
/**
* Sets components mnemonics and label / component associations.
*/
private void setMnemonics(UserPreferences preferences) {
if (!OperatingSystem.isMacOSX()) {
this.materialsLabel.setDisplayedMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString(
ModelMaterialsComponent.class, "materialsLabel.mnemonic")).getKeyCode());
this.materialsLabel.setLabelFor(this.materialsList);
this.defaultColorAndTextureRadioButton.setMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString(
ModelMaterialsComponent.class, "defaultColorAndTextureRadioButton.mnemonic")).getKeyCode());
this.colorRadioButton.setMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString(
ModelMaterialsComponent.class, "colorRadioButton.mnemonic")).getKeyCode());
this.textureRadioButton.setMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString(
ModelMaterialsComponent.class, "textureRadioButton.mnemonic")).getKeyCode());
this.shininessLabel.setDisplayedMnemonic(KeyStroke.getKeyStroke(preferences.getLocalizedString(
ModelMaterialsComponent.class, "shininessLabel.mnemonic")).getKeyCode());
this.shininessLabel.setLabelFor(this.shininessSlider);
}
}
/**
* Layouts components in panel with their labels.
*/
private void layoutComponents() {
// Preview
add(this.previewLabel, new GridBagConstraints(
0, 0, 1, 1, 0, 0, GridBagConstraints.LINE_START,
GridBagConstraints.NONE, new Insets(0, 0, 5, 10), 0, 0));
this.previewComponent.setPreferredSize(new Dimension(150, 150));
add(this.previewComponent, new GridBagConstraints(
0, 1, 1, 5, 0, 0, GridBagConstraints.NORTH,
GridBagConstraints.NONE, new Insets(2, 0, 0, 15), 0, 0));
// Materials list
add(this.materialsLabel, new GridBagConstraints(
1, 0, 1, 1, 0, 0, GridBagConstraints.LINE_START,
GridBagConstraints.NONE, new Insets(0, 0, 5, 15), 0, 0));
JScrollPane scrollPane = new JScrollPane(this.materialsList);
Dimension preferredSize = scrollPane.getPreferredSize();
scrollPane.setPreferredSize(new Dimension(Math.min(150, preferredSize.width), preferredSize.height));
add(scrollPane, new GridBagConstraints(
1, 1, 1, 5, 1, 1, GridBagConstraints.CENTER,
GridBagConstraints.BOTH, new Insets(0, 0, 0, 15), 0, 0));
SwingTools.installFocusBorder(this.materialsList);
// Color and Texture
add(this.colorAndTextureLabel, new GridBagConstraints(
2, 0, 2, 1, 0, 0, GridBagConstraints.LINE_START,
GridBagConstraints.NONE, new Insets(0, 0, 5, 0), 0, 0));
add(this.defaultColorAndTextureRadioButton, new GridBagConstraints(
2, 1, 2, 1, 0, 0, GridBagConstraints.LINE_START,
GridBagConstraints.NONE, new Insets(0, 0, 5, 0), 0, 0));
add(this.colorRadioButton, new GridBagConstraints(
2, 2, 1, 1, 0, 0, GridBagConstraints.LINE_START,
GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0));
add(this.colorButton, new GridBagConstraints(
3, 2, 1, 1, 0, 0, GridBagConstraints.CENTER,
GridBagConstraints.NONE, new Insets(0, 0, 5, 0), 0, 0));
add(this.textureRadioButton, new GridBagConstraints(
2, 3, 1, 1, 0, 0, GridBagConstraints.LINE_START,
GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0));
add(this.textureComponent, new GridBagConstraints(
3, 3, 1, 1, 0, 0, GridBagConstraints.CENTER,
GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
this.textureComponent.setPreferredSize(this.colorButton.getPreferredSize());
// Shininess
add(this.shininessLabel, new GridBagConstraints(
2, 4, 2, 1, 0, 0, GridBagConstraints.LINE_START,
GridBagConstraints.NONE, new Insets(15, 0, 5, 0), 0, 0));
add(this.shininessSlider, new GridBagConstraints(
2, 5, 2, 1, 0, 0, GridBagConstraints.LINE_START,
GridBagConstraints.NONE, new Insets(0, 0, 5, 0), -20, 0));
}
public void displayView(View parent) {
// Show panel in a resizable modal dialog
final JOptionPane optionPane = new JOptionPane(this, JOptionPane.PLAIN_MESSAGE,
JOptionPane.OK_CANCEL_OPTION);
JComponent parentComponent = SwingUtilities.getRootPane((JComponent)parent);
if (parentComponent != null) {
optionPane.setComponentOrientation(parentComponent.getComponentOrientation());
}
final JDialog dialog = optionPane.createDialog(parentComponent, controller.getDialogTitle());
dialog.applyComponentOrientation(ComponentOrientation.getOrientation(Locale.getDefault()));
dialog.setResizable(true);
// Pack again because resize decorations may have changed dialog preferred size
dialog.pack();
dialog.setMinimumSize(getPreferredSize());
this.controller.getTextureController().addPropertyChangeListener(
TextureChoiceController.Property.TEXTURE, this.textureChangeListener);
// Add a listener that transfer focus to focusable field of texture panel when dialog is shown
dialog.addComponentListener(new ComponentAdapter() {
@Override
public void componentShown(ComponentEvent ev) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(ModelMaterialsPanel.this);
dialog.removeComponentListener(this);
}
});
dialog.setVisible(true);
dialog.dispose();
this.controller.getTextureController().removePropertyChangeListener(
TextureChoiceController.Property.TEXTURE, this.textureChangeListener);
if (Integer.valueOf(JOptionPane.OK_OPTION).equals(optionPane.getValue())) {
this.controller.setMaterials(((MaterialsListModel)this.materialsList.getModel()).getMaterials());
}
}
/**
* Model for materials list.
*/
private static class MaterialsListModel extends AbstractListModel {
private HomeMaterial [] defaultMaterials;
private HomeMaterial [] materials;
public MaterialsListModel(ModelMaterialsController controller) {
this.materials = controller.getMaterials();
ModelManager.getInstance().loadModel(controller.getModel(),
new ModelManager.ModelObserver() {
public void modelUpdated(BranchGroup modelRoot) {
defaultMaterials = ModelManager.getInstance().getMaterials(modelRoot);
fireContentsChanged(MaterialsListModel.this, 0, defaultMaterials.length);
}
public void modelError(Exception ex) {
// Let the list be empty
}
});
}
public Object getElementAt(int index) {
if (this.materials != null
&& this.materials [index] != null) {
return this.materials [index];
} else {
return new HomeMaterial(this.defaultMaterials [index].getName(), null, null, null);
}
}
public int getSize() {
if (this.defaultMaterials != null) {
return this.defaultMaterials.length;
} else {
return 0;
}
}
public HomeMaterial getDefaultMaterialAt(int index) {
return this.defaultMaterials [index];
}
/**
* Sets the material at the given <code>index</code>.
*/
public void setMaterialAt(HomeMaterial material, int index) {
if (this.materials != null
&& material.getColor() == null
&& material.getTexture() == null
&& material.getShininess() == null) {
this.materials [index] = null;
boolean containsOnlyNull = true;
for (HomeMaterial m : this.materials) {
if (m != null) {
containsOnlyNull = false;
break;
}
}
if (containsOnlyNull) {
this.materials = null;
}
} else {
if (this.materials == null || this.materials.length != this.defaultMaterials.length) {
this.materials = new HomeMaterial [this.defaultMaterials.length];
}
this.materials [index] = material;
}
fireContentsChanged(this, index, index);
}
/**
* Returns the edited materials.
*/
public HomeMaterial [] getMaterials() {
return this.materials;
}
}
}
}