/* * GeoTools - The Open Source Java GIS Tookit * http://geotools.org * * (C) 2006-2008, Open Source Geospatial Foundation (OSGeo) * * This file is hereby placed into the Public Domain. This means anyone is * free to do whatever they wish with this file. Use it well and enjoy! */ package org.geotools.demo.swing; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import org.geotools.data.DataStore; import org.geotools.data.DefaultRepository; import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.factory.CommonFactoryFinder; import org.geotools.map.DefaultMapContext; import org.geotools.map.DefaultMapLayer; import org.geotools.map.MapContext; import org.geotools.map.MapLayer; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.renderer.lite.StreamingRenderer; import org.geotools.styling.SLDParser; import org.geotools.styling.Style; import org.geotools.styling.StyleFactory; import org.geotools.swing.JMapFrame; import org.geotools.swing.JMapPane; import org.geotools.swing.data.JFileDataStoreChooser; import org.geotools.swing.styling.JSimpleStyleDialog; import org.opengis.referencing.crs.CoordinateReferenceSystem; /** * This class demonstrates extending JMapFrame to add a menu bar and shapefile handling * methods. It also shows the use of {@code DefaultRepository} to manage data stores, and * the {@code JFileDataStoreChooser} and {@code JSimpleStyleDialog} classes. * * @author Michael Bedward * @since 2.6 * @source $URL$ * @version $Id$ */ public class ShapefileViewer extends JMapFrame { private DefaultRepository repository = new DefaultRepository(); private MapContext context; private String title; private File cwd; /** * Main function. Creates and displays a ShapefileViewer object. * * @param args ignored presently */ public static void main(String[] args) { final ShapefileViewer viewer = new ShapefileViewer("Shapefile viewer"); File dataDir = new File(ShapefileViewer.class.getResource("/data").getPath()); viewer.setWorkingDir(dataDir); viewer.setSize(800, 600); viewer.setVisible(true); } /** * Constructor * @param title text to be displayed in the frame's title bar */ public ShapefileViewer(String title) { this.title = title; enableLayerTable(true); enableStatusBar(true); enableToolBar(true); initComponents(); JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); JMenu menu = new JMenu("File"); JMenuItem item = new JMenuItem("Open..."); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { loadShapefile(); } catch (IOException ex) { ex.printStackTrace(); } } }); menu.add(item); item = new JMenuItem("Get scale"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JMapPane mapPane = getMapPane(); if (mapPane != null) { AffineTransform tr = mapPane.getScreenToWorldTransform(); if (tr != null) { System.out.println("x scale: " + tr.getScaleX()); System.out.println("Y scale: " + tr.getScaleY()); System.out.println("pane area: " + mapPane.getVisibleRect()); } } } }); menu.add(item); menuBar.add(menu); } /** * Set the current working directory * * @param cwd a File object representing the directory; if NULL the user's default * directory will be set */ public void setWorkingDir(File cwd) { if (!cwd.isDirectory()) { throw new IllegalArgumentException("The argument is not a directory: " + cwd.getAbsolutePath()); } this.cwd = cwd; } /** * Add the contents of a shapefile as a new layer. This method * simply calls {@linkplain #showOpenShapefileDialog} followed by * {@linkplain #addShapefile} with the {@code defaultStyle} * argument of the latter method set to {@code true}. */ public void loadShapefile() throws IOException { File file = JFileDataStoreChooser.showOpenFile("shp", cwd, null); if (file != null) { addShapefile(file.toURL(), true); setWorkingDir(file.getParentFile()); } } /** * Open a shapefile and add it to the map layers displayed * by the widget, styling the layer as specified by the * associated SLD file (same root name as shapefile with .sld * extension) if it exists. * <p> * To add a shapefile with a Style from elsewhere, e.g. one * constructed programmitcally, use the * {@linkplain #addShapefile(java.net.URL, org.geotools.styling.Style)} method. * Alternatively, create a MapLayer object and use the * {@linkplain #addLayer} method. * * @param shapefile URL for the shapefile to add * @param defaultStyle specifies what action to take if there is no * associated SLD file: fallback to a minimal style (if true) or * abort adding the layer (if false) * * @return true if the layer was added successfully; false otherwise * * @throws IllegalArgumentException if shapefileURL is null */ public boolean addShapefile(URL shapefileURL, boolean defaultStyle) throws IOException { if (shapefileURL == null) { throw new IllegalArgumentException("shapefileURL must not me null"); } ShapefileDataStore dstore = null; DataStore found = repository.dataStore( shapefileURL.toString()); if( found != null && found instanceof ShapefileDataStore){ dstore = (ShapefileDataStore) found; } else { try { dstore = new ShapefileDataStore(shapefileURL); } catch (MalformedURLException urlEx) { throw new RuntimeException(urlEx); } repository.register( shapefileURL.toString(), dstore ); } /* * Before doing anything else we attempt to connect to the * shapefile to check that it exists and is reachable. An * IOException will be thrown if this fails. */ dstore.getSchema(); /* * We assume from this point that the shapefile exists and * is accessible */ String typeName = dstore.getTypeNames()[0]; Style style = null; URL sldURL = getShapefileSLD(shapefileURL); if (sldURL != null) { /* * The shapefile has an associated SLD file. We read this and * use the (first) style for the new layer */ StyleFactory factory = CommonFactoryFinder.getStyleFactory(null); SLDParser stylereader = new SLDParser(factory, sldURL); style = stylereader.readXML()[0]; } else if (defaultStyle) { /* * There was no associated SLD file so we attempt to create * a minimal style to display the layer */ style = JSimpleStyleDialog.showDialog(this, dstore); if (style == null) { return false; } } else { /* * We are not having a good day... */ return false; } MapLayer layer = new DefaultMapLayer(dstore.getFeatureSource(typeName), style); addLayer(layer); return true; } /** * Open a shapefile and add it to the map layers displayed * by the widget, rendering the layer with the provided style. * <p> * * @param shapefile URL for the shapefile to add * @param style the Syle object to use in rendering this layer * * @return true if the layer was added successfully; false otherwise * * @throws IOException if the shapefile could not be accessed * @throws IllegalArgumentException if either of the arguments is null */ public boolean addShapefile(URL shapefileURL, Style style) throws IOException { if (shapefileURL == null || style == null) { throw new IllegalArgumentException("shapefileURL must not be null"); } ShapefileDataStore dstore = null; DataStore found = repository.dataStore( shapefileURL.toString()); if( found != null && found instanceof ShapefileDataStore){ dstore = (ShapefileDataStore) found; } else { try { dstore = new ShapefileDataStore(shapefileURL); } catch (MalformedURLException urlEx) { throw new RuntimeException(urlEx); } repository.register( shapefileURL.toString(), dstore ); } /* * Before doing anything else we attempt to connect to the * shapefile to check that it exists and is reachable. An * IOException will be thrown if this fails. */ dstore.getSchema(); /* * We assume from this point that the shapefile exists and * is accessible */ String typeName = dstore.getTypeNames()[0]; MapLayer layer = new DefaultMapLayer(dstore.getFeatureSource(typeName), style); addLayer(layer); return true; } /** * Search for a Styled Layer Descriptor (SLD) file associated with the * specified shapefile. If the SLD file exists it will be in the same * directory as the shapefile, have the same root name, and have * .sld as its extension. * * @param shapefileURL the shapefile for which an SLD file is being sought * * @return the URL of the SLD file; or null if not found or not accessible */ public URL getShapefileSLD(URL shapefileURL) { URL sldURL = null; File shapefile; try { shapefile = new File( shapefileURL.toURI() ); } catch (URISyntaxException e) { shapefile = new File( shapefileURL.getPath() ); } String fileName = shapefile.getName(); int lastDot = fileName.lastIndexOf('.'); if (lastDot > 0) { File directory = shapefile.getParentFile(); String sldname1 = fileName.substring(0, lastDot) + ".sld"; String sldname2 = fileName.substring(0, lastDot) + ".SLD"; InputStream input=null; try { File sldFile1 = new File( directory, sldname1 ); File sldFile2 = new File( directory, sldname2 ); if( sldFile1.exists() && sldFile1.canRead() ){ sldURL = sldFile1.toURL(); } else if( sldFile1.exists() && sldFile1.canRead() ){ sldURL = sldFile2.toURL(); } else { /* * The SLD file can't be opened so we return null */ return null; } /* * Now we check to see if the url that we have created * corresponds to an existing and accessible SLD file. * If it doesn't, this call to openStream() will provoke * an IOException */ input = sldURL.openStream(); } catch (MalformedURLException urlEx) { throw new RuntimeException(urlEx); } catch (IOException ioEx) { /* * The SLD file can't be opened so we return null */ return null; } finally { if( input != null) { try { input.close(); } catch (IOException e) { } } } } return sldURL; } /** * Add a map layer to those displayed. If no {@linkplain org.geotools.map.MapContext} * has been set explicitly, a new instance of {@linkplain org.geotools.map.DefaultMapContext} * will be created. */ public void addLayer(MapLayer layer) { if (context == null) { CoordinateReferenceSystem crs = layer.getBounds().getCoordinateReferenceSystem(); if (crs == null) { crs = DefaultGeographicCRS.WGS84; } context = new DefaultMapContext(crs); context.setTitle(title); setMapContext(context); setRenderer(new StreamingRenderer()); } context.addLayer(layer); } }