/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2007 - 2008, Open Source Geospatial Foundation (OSGeo) * (C) 2008 - 2009, Johann Sorel * * 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.render2d; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JComponent; import javax.swing.JLayeredPane; import javax.swing.JPanel; import org.geotoolkit.display.canvas.control.NeverFailMonitor; import org.geotoolkit.display2d.canvas.J2DCanvas; import org.geotoolkit.display2d.canvas.J2DCanvasSwing; import org.geotoolkit.display2d.canvas.SwingVolatileGeoComponent; import org.geotoolkit.display2d.container.ContextContainer2D; import org.geotoolkit.gui.swing.util.BufferLayout; import org.geotoolkit.gui.swing.render2d.decoration.ColorDecoration; import org.geotoolkit.gui.swing.render2d.decoration.DefaultInformationDecoration; import org.geotoolkit.gui.swing.render2d.decoration.InformationDecoration; import org.geotoolkit.gui.swing.render2d.decoration.MapDecoration; import org.apache.sis.referencing.CommonCRS; import static org.apache.sis.util.ArgumentChecks.*; import org.apache.sis.util.logging.Logging; import org.geotoolkit.display.canvas.AbstractCanvas; import org.opengis.referencing.operation.TransformException; /** * * @author Johann Sorel (Geomatys) * @module */ public class JMap2D extends JPanel{ /** * The name of the {@linkplain PropertyChangeEvent property change event} fired when the * {@linkplain AWTCanvas2D#getHandler canvas handler} changed. */ public static final String HANDLER_PROPERTY = "handler"; private static final MapDecoration[] EMPTY_OVERLAYER_ARRAY = {}; private static final Logger LOGGER = Logging.getLogger("org.geotoolkit.gui.swing.render2d"); private CanvasHandler handler; private final J2DCanvas canvas; private final JComponent geoComponent; private boolean statefull = false; private final List<MapDecoration> userDecorations = new ArrayList<>(); private final JLayeredPane mapDecorationPane = new JLayeredPane(); private final JLayeredPane userDecorationPane = new JLayeredPane(); private final JLayeredPane mainDecorationPane = new JLayeredPane(); private int nextMapDecorationIndex = 1; private InformationDecoration informationDecoration = new DefaultInformationDecoration(); private MapDecoration backDecoration = new ColorDecoration(); public JMap2D(){ this(false); } public JMap2D(final boolean statefull){ setLayout(new BorderLayout()); setPreferredSize(new Dimension(150,150)); mapDecorationPane.setLayout(new BufferLayout()); userDecorationPane.setLayout(new BufferLayout()); mainDecorationPane.setLayout(new BufferLayout()); mainDecorationPane.add(informationDecoration.getComponent(), Integer.valueOf(3)); mainDecorationPane.add(userDecorationPane, Integer.valueOf(2)); mainDecorationPane.add(mapDecorationPane, Integer.valueOf(1)); informationDecoration.setMap2D(this); add(BorderLayout.CENTER, mainDecorationPane); setBackground(Color.WHITE); setOpaque(true); if(statefull){ canvas = new J2DCanvasSwing(CommonCRS.WGS84.normalizedGeographic()); geoComponent = ((J2DCanvasSwing)canvas).getComponent(); }else{ geoComponent = new SwingVolatileGeoComponent(CommonCRS.WGS84.normalizedGeographic()); canvas = ((SwingVolatileGeoComponent)geoComponent).getCanvas(); } canvas.setMonitor(new NeverFailMonitor()); mapDecorationPane.add(geoComponent, Integer.valueOf(0)); mapDecorationPane.revalidate(); canvas.setContainer(new ContextContainer2D(canvas, statefull)); canvas.setAutoRepaint(true); canvas.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if(canvas.isAutoRepaint()){ //dont show the painting icon if the cans is in auto render mode // since it may repaint dynamic graphic it would show up all the time return; } if(AbstractCanvas.RENDERSTATE_KEY.equals(evt.getPropertyName())){ final Object state = evt.getNewValue(); if(AbstractCanvas.ON_HOLD.equals(state)){ getInformationDecoration().setPaintingIconVisible(false); }else if(AbstractCanvas.RENDERING.equals(state)){ getInformationDecoration().setPaintingIconVisible(true); }else{ getInformationDecoration().setPaintingIconVisible(false); } } } }); try { canvas.setObjectiveCRS(CommonCRS.WGS84.normalizedGeographic()); } catch (TransformException ex) { LOGGER.log(Level.WARNING, null, ex); } } /** * @return the effective Go2 Canvas. */ public J2DCanvas getCanvas() { return canvas; } public ContextContainer2D getContainer(){ return (ContextContainer2D) canvas.getContainer(); } /** * Must be called when the map2d is not used anymore. * to avoid memory leak if it uses thread or other resources */ public void dispose() { canvas.dispose(); } public CanvasHandler getHandler(){ return handler; } public void setHandler(final CanvasHandler handler){ if(this.handler != handler) { //TODO : check for possible vetos final CanvasHandler old = this.handler; if (this.handler != null){ this.handler.uninstall(geoComponent); } this.handler = handler; if (this.handler != null) { this.handler.install(geoComponent); } firePropertyChange(HANDLER_PROPERTY, old, handler); } } //----------------------Use as extend for subclasses------------------------ protected void setRendering(final boolean render) { informationDecoration.setPaintingIconVisible(render); } //----------------------Over/Sub/information layers------------------------- /** * set the top InformationDecoration of the map2d widget * @param info , can't be null */ public void setInformationDecoration(final InformationDecoration info) { ensureNonNull("info decoration", info); mainDecorationPane.remove(informationDecoration.getComponent()); informationDecoration = info; mainDecorationPane.add(informationDecoration.getComponent(), Integer.valueOf(3)); mainDecorationPane.revalidate(); mainDecorationPane.repaint(); } /** * get the top InformationDecoration of the map2d widget * @return InformationDecoration */ public InformationDecoration getInformationDecoration() { return informationDecoration; } /** * set the decoration behind the map * @param back : MapDecoration, can't be null */ public void setBackgroundDecoration(final MapDecoration back) { ensureNonNull("background decoration", back); mainDecorationPane.remove(backDecoration.getComponent()); backDecoration = back; mainDecorationPane.add(backDecoration.getComponent(), Integer.valueOf(0)); mainDecorationPane.revalidate(); mainDecorationPane.repaint(); } /** * get the decoration behind the map * @return MapDecoration : or null if no back decoration */ public MapDecoration getBackgroundDecoration() { return backDecoration; } /** * add a Decoration between the map and the information top decoration * @param deco : MapDecoration to add */ public void addDecoration(final MapDecoration deco) { if (deco != null && !userDecorations.contains(deco)) { deco.setMap2D(this); userDecorations.add(deco); userDecorationPane.add(deco.getComponent(), Integer.valueOf(userDecorations.indexOf(deco))); userDecorationPane.revalidate(); userDecorationPane.repaint(); } } /** * insert a MapDecoration at a specific index * @param index : index where to isert the decoration * @param deco : MapDecoration to add */ public void addDecoration(final int index, final MapDecoration deco) { if (deco != null && !userDecorations.contains(deco)) { deco.setMap2D(this); userDecorations.add(index, deco); userDecorationPane.add(deco.getComponent(), Integer.valueOf(userDecorations.indexOf(deco))); userDecorationPane.revalidate(); userDecorationPane.repaint(); } } /** * get the index of a MapDecoration * @param deco : MapDecoration to find * @return index of the MapDecoration * @throw ClassCastException or NullPointerException */ public int getDecorationIndex(final MapDecoration deco) { return userDecorations.indexOf(deco); } /** * remove a MapDecoration * @param deco : MapDecoration to remove */ public void removeDecoration(final MapDecoration deco) { if (deco != null && userDecorations.contains(deco)) { deco.setMap2D(null); deco.dispose(); userDecorations.remove(deco); userDecorationPane.remove(deco.getComponent()); userDecorationPane.revalidate(); userDecorationPane.repaint(); } } /** * get an array of all MapDecoration * @return array of MapDecoration */ public MapDecoration[] getDecorations() { return userDecorations.toArray(EMPTY_OVERLAYER_ARRAY); } /** * add a MapDecoration between the map and the user MapDecoration * those MapDecoration can not be removed because they are important * for edition/selection/navigation. * @param deco : MapDecoration to add */ protected void addMapDecoration(final MapDecoration deco) { mapDecorationPane.add(deco.getComponent(), Integer.valueOf(nextMapDecorationIndex)); nextMapDecorationIndex++; } //-----------------------------MAP2D---------------------------------------- /** * get the visual component * @return Component */ public Component getComponent() { return geoComponent; } /** * Can be used to add more components on the side of the map * if needed. in any case, dont remove the central component. * @return JPanel the container in borderlayout mode */ public JPanel getUIContainer() { return this; } }