/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2012 -2014 Geomatys
*
* This library 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;
* version 2.1 of the License.
*
* This library 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.
*/
package org.geotoolkit.gui.swing.style;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.measure.Unit;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
import org.geotoolkit.display2d.GO2Utilities;
import org.geotoolkit.display2d.service.DefaultGlyphService;
import org.geotoolkit.style.StyleConstants;
import org.opengis.filter.expression.Expression;
import org.opengis.style.AnchorPoint;
import org.opengis.style.Description;
import org.opengis.style.Displacement;
import org.opengis.style.ExternalGraphic;
import org.opengis.style.Fill;
import org.opengis.style.Graphic;
import org.opengis.style.GraphicalSymbol;
import org.opengis.style.LineSymbolizer;
import org.opengis.style.Mark;
import org.opengis.style.PointPlacement;
import org.opengis.style.PointSymbolizer;
import org.opengis.style.PolygonSymbolizer;
import org.opengis.style.RasterSymbolizer;
import org.opengis.style.Stroke;
import org.opengis.style.TextSymbolizer;
import org.apache.sis.measure.Units;
/**
* This component ables to display preview of SLD norm object (PointSymbolizer,
* Fill, Stroke...)
*
* @author Fabien Rétif (Geomatys)
* @author Johann Sorel (Geomatys)
*/
public class JPreview extends JPanel implements ComponentListener {
private BufferedImage image = null;
private final double[] disp = new double[] {0d,0d};
/**
* Display or not mir
*/
private boolean mir = false;
private Object targetObj = null;
public JPreview() {
this.addComponentListener(this);
setBorder(new LineBorder(Color.DARK_GRAY, 1));
setBackground(Color.WHITE);
setOpaque(true);
}
public void setMir(boolean mir) {
this.mir = mir;
}
public boolean isMir() {
return mir;
}
public Object getTarget() {
return targetObj;
}
/**
* This methods parses settled object and tries to create a preview of it
*
* @param obj Parsing object
*/
public void parse(final Object obj) {
if(this.targetObj != null && this.targetObj.equals(obj)){
//same object
return;
}else if(this.targetObj == null && obj == null){
//both null
return;
}
this.targetObj = obj;
image = null;
repaint();
}
public BufferedImage getImage() {
if(image==null) updateImage();
return image;
}
private void updateImage() {
//There is already an image or there is no object to draw => exit
if (image != null || this.targetObj == null) {
return;
}
int glyphSize = Math.min(getWidth(), getHeight());
glyphSize = Math.max(24, glyphSize);
final Dimension dim = new Dimension(glyphSize, glyphSize);
image = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
final Rectangle rect = new Rectangle(dim);
final Graphics2D g = image.createGraphics();
this.disp[0] = 0d;
this.disp[1] = 0d;
try {
// Main type
if (this.targetObj instanceof PointSymbolizer) {
DefaultGlyphService.render((PointSymbolizer) targetObj, rect, g, null);
this.disp[0] = ((PointSymbolizer) targetObj).getGraphic().getDisplacement().getDisplacementX().evaluate(null, Double.class);
this.disp[1] = ((PointSymbolizer) targetObj).getGraphic().getDisplacement().getDisplacementY().evaluate(null, Double.class);
} else if (targetObj instanceof LineSymbolizer) {
DefaultGlyphService.render((LineSymbolizer) targetObj, rect, g, null);
this.disp[0] = ((LineSymbolizer) targetObj).getPerpendicularOffset().evaluate(null, Double.class);
} else if (targetObj instanceof PolygonSymbolizer) {
DefaultGlyphService.render((PolygonSymbolizer) targetObj, rect, g, null);
this.disp[0] = ((PolygonSymbolizer) targetObj).getDisplacement().getDisplacementX().evaluate(null, Double.class);
this.disp[1] = ((PolygonSymbolizer) targetObj).getDisplacement().getDisplacementY().evaluate(null, Double.class);
} else if (targetObj instanceof TextSymbolizer) {
DefaultGlyphService.render((TextSymbolizer) targetObj, rect, g, null);
if(((TextSymbolizer) targetObj).getLabelPlacement() instanceof PointPlacement) {
PointPlacement pp = (PointPlacement) ((TextSymbolizer) targetObj).getLabelPlacement();
this.disp[0] = pp.getDisplacement().getDisplacementX().evaluate(null, Double.class);
this.disp[1] = pp.getDisplacement().getDisplacementY().evaluate(null, Double.class);
}
} else if (targetObj instanceof RasterSymbolizer) {
DefaultGlyphService.render((RasterSymbolizer) targetObj, rect, g, null);
}
// Sub-type
else if (targetObj instanceof GraphicalSymbol) {
final String name = "mySymbol";
final Description desc = StyleConstants.DEFAULT_DESCRIPTION;
final String geometry = null; //use the default geometry of the feature
final Unit unit = Units.POINT;
final Expression offset = StyleConstants.LITERAL_ONE_FLOAT;
//the visual element
final Expression size = GO2Utilities.FILTER_FACTORY.literal(12);
final Expression opacity = StyleConstants.LITERAL_ONE_FLOAT;
final Expression rotation = StyleConstants.LITERAL_ONE_FLOAT;
final AnchorPoint anchor = StyleConstants.DEFAULT_ANCHOR_POINT;
final Displacement disp = StyleConstants.DEFAULT_DISPLACEMENT;
final List<GraphicalSymbol> symbols = new ArrayList<GraphicalSymbol>();
symbols.add((GraphicalSymbol) targetObj);
final Graphic graphic = GO2Utilities.STYLE_FACTORY.graphic(symbols, opacity, size, rotation, anchor, disp);
final PointSymbolizer symbolizer = GO2Utilities.STYLE_FACTORY.pointSymbolizer(name, geometry, desc, unit, graphic);
DefaultGlyphService.render(symbolizer, rect, g, null);
} else if (targetObj instanceof Stroke) {
final String name = "mySymbol";
final Description desc = StyleConstants.DEFAULT_DESCRIPTION;
final String geometry = null; //use the default geometry of the feature
final Unit unit = Units.POINT;
final Expression offset = StyleConstants.LITERAL_ONE_FLOAT;
final LineSymbolizer symbolizer = GO2Utilities.STYLE_FACTORY.lineSymbolizer(name, geometry, desc, unit, (Stroke) targetObj, offset);
DefaultGlyphService.render(symbolizer, rect, g, null);
} else if (targetObj instanceof Fill) {
final String name = "mySymbol";
final Description desc = StyleConstants.DEFAULT_DESCRIPTION;
final String geometry = null; //use the default geometry of the feature
final Unit unit = Units.POINT;
final Expression offset = StyleConstants.LITERAL_ONE_FLOAT;
//the visual element
final Expression size = GO2Utilities.FILTER_FACTORY.literal(32);
final Expression opacity = StyleConstants.LITERAL_ONE_FLOAT;
final Expression rotation = StyleConstants.LITERAL_ONE_FLOAT;
final AnchorPoint anchor = StyleConstants.DEFAULT_ANCHOR_POINT;
final Displacement disp = StyleConstants.DEFAULT_DISPLACEMENT;
//the visual element
final Expression color = GO2Utilities.STYLE_FACTORY.literal(Color.BLACK);
final Expression width = GO2Utilities.FILTER_FACTORY.literal(2);
final Expression linecap = StyleConstants.STROKE_CAP_BUTT;
final Expression linejoin = StyleConstants.STROKE_JOIN_ROUND;
final Expression dashOffset = StyleConstants.LITERAL_ZERO_FLOAT;
final Stroke stroke = GO2Utilities.STYLE_FACTORY.stroke(color, opacity, width, linejoin, linecap, new float[]{1.f, 1.f, 1.f}, dashOffset);
final List<GraphicalSymbol> symbols = new ArrayList<GraphicalSymbol>();
final Mark mark = GO2Utilities.STYLE_FACTORY.mark(StyleConstants.MARK_SQUARE, (Fill) targetObj, stroke);
symbols.add(mark);
final Graphic graphic = GO2Utilities.STYLE_FACTORY.graphic(symbols, opacity, size, rotation, anchor, disp);
final PointSymbolizer symbolizer = GO2Utilities.STYLE_FACTORY.pointSymbolizer(name, geometry, desc, unit, graphic);
DefaultGlyphService.render(symbolizer, rect, g, null);
} else if (targetObj instanceof ExternalGraphic) {
final String name = "mySymbol";
final Description desc = StyleConstants.DEFAULT_DESCRIPTION;
final String geometry = null; //use the default geometry of the feature
final Unit unit = Units.POINT;
final Expression offset = StyleConstants.LITERAL_ONE_FLOAT;
//the visual element
final Expression size = GO2Utilities.FILTER_FACTORY.literal(32);
final Expression opacity = StyleConstants.LITERAL_ONE_FLOAT;
final Expression rotation = StyleConstants.LITERAL_ONE_FLOAT;
final AnchorPoint anchor = StyleConstants.DEFAULT_ANCHOR_POINT;
final Displacement disp = StyleConstants.DEFAULT_DISPLACEMENT;
final List<GraphicalSymbol> symbols = new ArrayList<GraphicalSymbol>();
symbols.add((ExternalGraphic) targetObj);
final Graphic graphic = GO2Utilities.STYLE_FACTORY.graphic(symbols, opacity, size, rotation, anchor, disp);
final PointSymbolizer symbolizer = GO2Utilities.STYLE_FACTORY.pointSymbolizer(name, geometry, desc, unit, graphic);
DefaultGlyphService.render(symbolizer, rect, g, null);
}
setPreferredSize(dim);
revalidate();
} catch (NullPointerException ex) {
//Do nothing because we probably try to draw a symbolizer to size 0
}
}
@Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
final Graphics2D g = (Graphics2D) grphcs;
if (this.mir) {
g.setColor(Color.LIGHT_GRAY);
g.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
g.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
}
updateImage();
if (this.image != null) {
final AffineTransform trs = new AffineTransform();
trs.translate(disp[0] + (getWidth() - image.getWidth()) / 2, disp[1] + (getHeight() - image.getHeight()) / 2);
g.drawImage(image, trs, null);
}
}
/**
* When component is resized, we repaint the image
* @param ce : ComponentEvent
*/
public void componentResized(ComponentEvent ce) {
image = null;
updateImage();
}
public void componentMoved(ComponentEvent ce) {
}
public void componentShown(ComponentEvent ce) {
}
public void componentHidden(ComponentEvent ce) {
}
}