/**
* This file is part of VisiCut.
* Copyright (C) 2011 - 2013 Thomas Oster <thomas.oster@rwth-aachen.de>
* RWTH Aachen University - 52062 Aachen, Germany
*
* VisiCut is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VisiCut 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with VisiCut. If not, see <http://www.gnu.org/licenses/>.
**/
package com.t_oster.visicut.gui.mapping;
import com.t_oster.visicut.VisicutModel;
import com.t_oster.visicut.managers.MappingManager;
import com.t_oster.visicut.managers.ProfileManager;
import com.t_oster.visicut.model.PlfPart;
import com.t_oster.visicut.model.graphicelements.GraphicSet;
import com.t_oster.visicut.model.mapping.MappingSet;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Set;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
/**
* This implements a combo box, listing all predefined mappings.
* If the current selected part has one of those mappings, the
* combo box is updated. It shows "none" if the mapping is null
* and "Custom" if the mapping is none of the predefined ones.
* If the selection is changed by the user, the mapping will
* of the selected part will be set
* @author Thomas Oster <thomas.oster@rwth-aachen.de>
*/
public class PredefinedMappingBox extends javax.swing.JComboBox
{
/**
* This class is only for having entries like "Map by color"
*/
public class MapByPropertyEntry
{
public MapByPropertyEntry(String property)
{
this.property = property;
}
public String property;
}
private ResourceBundle bundle = ResourceBundle.getBundle("com/t_oster/visicut/gui/mapping/resources/PredefinedMappingBox");
public String NONE = "<html><b>"+bundle.getString("NONE")+"</b></html>";
public String ONE_PROFILE_FOR_EVERYTHING = "<html><b>"+bundle.getString("ONE_PROFILE_FOR_EVERYTHING")+"</b></html>";
public String PREDEFINED_MAPPINGS = "<html><b>"+bundle.getString("PREDEFINED_MAPPINGS")+"</b></html>";
public String BY_PROPERTY = "<html><b>"+bundle.getString("BY_PROPERTY")+"...</b></html>";
public String CUSTOM = "<html><b>"+bundle.getString("CUSTOM")+"...</b></html>";
private PlfPart lastSelectedPlfPart = null;
/**
* Creates new form MappingPanel
*/
public PredefinedMappingBox()
{
this.setRenderer(cbRenderer);
PropertyChangeListener pl = new PropertyChangeListener(){
public void propertyChange(PropertyChangeEvent pce)
{
propertyChanged(pce);
}
};
MappingManager.getInstance().addPropertyChangeListener(pl);
ProfileManager.getInstance().addPropertyChangeListener(pl);
VisicutModel.getInstance().addPropertyChangeListener(pl);
this.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae)
{
comboBoxActionPerformed(ae);
}
});
updateComboBoxContent();
updateUi();
}
private boolean ignoreUiUpdates = false;
//this renderer adds spaces before each mapping name
private ListCellRenderer cbRenderer = new DefaultListCellRenderer()
{
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
{
String mapBy = bundle.getString("MAP_BY");
Component result = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (result instanceof JLabel)
{
if (value instanceof MappingSet)
{
((JLabel) result).setText((isPopupVisible() ? " " : "" ) + ((MappingSet) value).toString());
}
else if (value instanceof MapByPropertyEntry)
{
((JLabel) result).setText(" "+mapBy.replace("$property", GraphicSet.translateAttVal(((MapByPropertyEntry) value).property)));
}
}
return result;
}
};
private void updateComboBoxContent()
{
ignoreUiUpdates = true;
Object selected = this.getSelectedItem();
this.removeAllItems();
this.addItem(NONE);
this.addItem(ONE_PROFILE_FOR_EVERYTHING);
for (MappingSet m : MappingManager.getInstance().generateDefaultMappings())
{
this.addItem(m);
}
List<MappingSet> all = MappingManager.getInstance().getAll();
if (all.size() > 0)
{
this.addItem(PREDEFINED_MAPPINGS);
for (MappingSet m : all)
{
this.addItem(m);
}
}
if (VisicutModel.getInstance().getSelectedPart() != null)
{
Iterable<String> props = VisicutModel.getInstance().getSelectedPart().getGraphicObjects().getInterestingAttributes();
if (props.iterator().hasNext())
{
this.addItem(BY_PROPERTY);
int count = 0;
for(String att: props)
{
if (++count > 4)
{
break;
}
this.addItem(new MapByPropertyEntry(att));
}
}
}
this.addItem(CUSTOM);
this.setSelectedItem(selected);
ignoreUiUpdates = false;
}
/**
* Updates the UI to represent the current this.mapping value
* WITHOUT generating propery change events.
*/
private void updateUi()
{
if (VisicutModel.getInstance().getSelectedPart() != null)
{
ignoreUiUpdates = true;
MappingSet ms = VisicutModel.getInstance().getSelectedPart().getMapping();
// guess the selected entry from the MappingSet
// we have no information about the name, so we need to see which entry matches
if ((lastSelectedPlfPart == VisicutModel.getInstance().getSelectedPart()) && (this.getSelectedItem() == CUSTOM || this.getSelectedItem() == BY_PROPERTY)) {
// special case:
// the selected PlfPart ("object") is still the same.
// CUSTOM/BY_PROPERTY was selected and the mapping was edited
// even if the mapping is now equal to a saved one, don't switch back to the entry of the saved mapping!
// otherwise the CustomMappingPanel would be hidden
// change nothing, selectedItem is still CUSTOM
} else {
// default case:
// show NONE if empty mapping
// show saved mapping if one is equal to the current mapping
// show "CUSTOM" otherwise
if (ms == null || ms.isEmpty())
{
Object selected = this.getSelectedItem();
//NONE, By_Property and Custom can represent a null mapping, so leave
//them alone if they are selected. Otherwise select NONE by default
if (!NONE.equals(selected) && !BY_PROPERTY.equals(selected) && !CUSTOM.equals(selected))
{
this.setSelectedItem(NONE);
}
}
else
{
this.setSelectedItem(PropertyMappingPanel.getPropertyMappingProperty(ms) != null ? BY_PROPERTY : CUSTOM);
this.setSelectedItem(ms); // only changes the selection if the mapping exists in the comboBox
}
}
ignoreUiUpdates = false;
}
lastSelectedPlfPart = VisicutModel.getInstance().getSelectedPart();
}
private void comboBoxActionPerformed(java.awt.event.ActionEvent evt)
{
if (!ignoreUiUpdates && VisicutModel.getInstance().getSelectedPart() != null)
{
Object selected = this.getSelectedItem();
if (selected == null || NONE.equals(selected))
{
VisicutModel.getInstance().getSelectedPart().setMapping(null);
VisicutModel.getInstance().firePartUpdated(VisicutModel.getInstance().getSelectedPart());
}
else if (selected instanceof MappingSet)
{
VisicutModel.getInstance().getSelectedPart().setMapping((MappingSet) selected);
VisicutModel.getInstance().firePartUpdated(VisicutModel.getInstance().getSelectedPart());
}
else if (selected instanceof MapByPropertyEntry)
{
//do nothing. MappingPanel will handle this
}
else //some string selected, which should not be selectable => revert state
{
updateUi();
}
}
}
private void propertyChanged(PropertyChangeEvent pce)
{
if (pce.getSource().equals(VisicutModel.getInstance()))
{
if (VisicutModel.PROP_SELECTEDPART.equals(pce.getPropertyName()))
{
updateComboBoxContent();
updateUi();
}
else if (VisicutModel.PROP_PLF_PART_UPDATED.equals(pce.getPropertyName()) && pce.getNewValue().equals(VisicutModel.getInstance().getSelectedPart()))
{
updateUi();
}
}
else if (pce.getSource().equals(MappingManager.getInstance()) || pce.getSource().equals(ProfileManager.getInstance()))
{
updateComboBoxContent();
}
}
}