package rescuecore2.view;
import java.util.List;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Collection;
import java.util.Collections;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.awt.event.ActionEvent;
import javax.swing.JPopupMenu;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.Action;
import javax.swing.AbstractAction;
import rescuecore2.misc.gui.ScreenTransform;
import rescuecore2.config.Config;
/**
A ViewComponent that uses layers.
*/
public class LayerViewComponent extends ViewComponent {
private Config config;
private List<ViewLayer> layers;
private Map<ViewLayer, Action> layerActions;
private Object[] data;
private Rectangle2D bounds;
/**
Construct a new LayerViewComponent.
*/
public LayerViewComponent() {
layers = new ArrayList<ViewLayer>();
layerActions = new HashMap<ViewLayer, Action>();
addMouseListener(new MouseListener() {
@Override
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()) {
showPopupMenu(e.getX(), e.getY());
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
showPopupMenu(e.getX(), e.getY());
}
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
});
}
@Override
public void initialise(Config c) {
this.config = c;
for (ViewLayer next : layers) {
next.initialise(config);
}
}
/**
Add a view layer.
@param layer The layer to add.
*/
public void addLayer(ViewLayer layer) {
layers.add(layer);
layer.setLayerViewComponent(this);
layerActions.put(layer, new LayerAction(layer));
if (config != null) {
layer.initialise(config);
}
computeBounds();
}
/**
Remove a view layer.
@param layer The layer to remove.
*/
public void removeLayer(ViewLayer layer) {
int index = layers.indexOf(layer);
if (index != -1) {
layers.remove(index);
layerActions.remove(layer);
layer.setLayerViewComponent(null);
computeBounds();
}
}
/**
Remove all view layers.
*/
public void removeAllLayers() {
for (ViewLayer next : layers) {
next.setLayerViewComponent(null);
}
layers.clear();
layerActions.clear();
computeBounds();
}
@Override
public void view(Object... objects) {
data = objects;
computeBounds();
super.view(objects);
}
@Override
protected Collection<RenderedObject> render(Graphics2D g, ScreenTransform transform, int width, int height) {
Collection<RenderedObject> result = new HashSet<RenderedObject>();
prepaint();
for (ViewLayer next : layers) {
if (next.isVisible()) {
Graphics2D copy = (Graphics2D)g.create();
result.addAll(next.render(copy, transform, width, height));
}
}
postpaint();
return result;
}
/**
Get all installed layers.
@return All installed layers.
*/
protected List<ViewLayer> getLayers() {
return Collections.unmodifiableList(layers);
}
/**
Do whatever needs doing before the layers are painted. The default implementation does nothing.
*/
protected void prepaint() {
}
/**
Do whatever needs doing after the layers are painted. The default implementation does nothing.
*/
protected void postpaint() {
}
private void computeBounds() {
Rectangle2D oldBounds = bounds;
bounds = null;
for (ViewLayer next : layers) {
expandBounds(next.view(data));
}
if (bounds == null) {
updateBounds(0, 0, 1, 1);
}
else if (oldBounds == null
|| oldBounds.getMinX() != bounds.getMinX()
|| oldBounds.getMinY() != bounds.getMinY()
|| oldBounds.getMaxX() != bounds.getMaxX()
|| oldBounds.getMaxY() != bounds.getMaxY()) {
updateBounds(bounds.getMinX(), bounds.getMinY(), bounds.getMaxX(), bounds.getMaxY());
}
}
private void expandBounds(Rectangle2D next) {
if (next == null) {
return;
}
if (bounds == null) {
bounds = next;
}
else {
Rectangle2D.union(bounds, next, bounds);
}
}
private void showPopupMenu(int x, int y) {
JPopupMenu menu = new JPopupMenu();
for (ViewLayer next : layers) {
Action action = layerActions.get(next);
JMenu layerMenu = new JMenu(next.getName());
layerMenu.add(new JMenuItem(action));
if (next.isVisible()) {
List<JMenuItem> items = next.getPopupMenuItems();
if (items != null && !items.isEmpty()) {
layerMenu.addSeparator();
for (JMenuItem item : items) {
layerMenu.add(item);
}
}
}
menu.add(layerMenu);
}
menu.show(this, x, y);
}
private class LayerAction extends AbstractAction {
private ViewLayer layer;
public LayerAction(ViewLayer layer) {
super("Visible");
this.layer = layer;
putValue(Action.SELECTED_KEY, Boolean.valueOf(layer.isVisible()));
putValue(Action.SMALL_ICON, layer.isVisible() ? Icons.TICK : Icons.CROSS);
}
@Override
public void actionPerformed(ActionEvent e) {
boolean selected = ((Boolean)getValue(Action.SELECTED_KEY)).booleanValue();
putValue(Action.SELECTED_KEY, Boolean.valueOf(!selected));
putValue(Action.SMALL_ICON, !selected ? Icons.TICK : Icons.CROSS);
layer.setVisible(!selected);
LayerViewComponent.this.repaint();
}
}
}