/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2011, 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.render2d.control.edition; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKTReader; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.sis.feature.FeatureExt; import org.geotoolkit.data.FeatureCollection; import org.geotoolkit.data.FeatureIterator; import org.geotoolkit.geometry.jts.JTSMapping; import org.geotoolkit.geometry.jts.JTS; import org.geotoolkit.gui.swing.resource.MessageBundle; import org.geotoolkit.process.ProcessDescriptor; import org.geotoolkit.process.ProcessException; import org.geotoolkit.process.ProcessFinder; import org.apache.sis.referencing.CRS; import org.geotoolkit.util.GeotkClipboard; import org.apache.sis.util.logging.Logging; import org.opengis.feature.Feature; import org.opengis.parameter.ParameterValueGroup; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; import org.opengis.util.FactoryException; import org.opengis.util.NoSuchIdentifierException; import org.apache.sis.util.Utilities; /** * Allow to copy geometry from clipboards * * @author Johann Sorel (Geomatys) * @module */ public class JClipboardPanel extends javax.swing.JPanel { private static final Logger LOGGER = Logging.getLogger("org.geotoolkit.gui.swing.render2d.control.edition"); public static final String GEOMETRY_PROPERTY = "geometry"; private final WKTReader reader = new WKTReader(); private Geometry original = null; private Geometry current = null; private CoordinateReferenceSystem crs = null; public JClipboardPanel() { initComponents(); } public void setGeometry(Geometry geom){ this.original = geom; this.current = null; } public Geometry getGeometry(){ if(current == null){ return original; }else{ return current; } } public void setCrs(CoordinateReferenceSystem crs) { this.crs = crs; } public CoordinateReferenceSystem getCrs() { return crs; } private boolean checkClipboard(boolean system){ Object candidate = null; if(system){ //extract geometry from system clipboard candidate = GeotkClipboard.getSystemClipboardValue(); candidate = adapt(candidate); }else{ //extract geometry from application clipboard final Transferable trs = GeotkClipboard.INSTANCE.getContents(this); for(DataFlavor df : trs.getTransferDataFlavors()){ try { candidate = trs.getTransferData(df); candidate = adapt(candidate); } catch (UnsupportedFlavorException ex) { LOGGER.log(Level.FINE, ex.getMessage(),ex); continue; } catch (IOException ex) { LOGGER.log(Level.FINE, ex.getMessage(),ex); continue; } if(candidate != null){ //we found something in the clipboard which can be matched as a geometry break; } } } if(candidate instanceof Geometry){ current = (Geometry) candidate; //reproject geometry if necessary if(crs != null){ try{ final CoordinateReferenceSystem currentCRS = JTS.findCoordinateReferenceSystem(current); if(currentCRS != null){ if(!Utilities.equalsIgnoreMetadata(currentCRS, crs)){ final MathTransform trs = CRS.findOperation(currentCRS, crs, null).getMathTransform(); current = JTS.transform(current, trs); } } }catch(FactoryException ex){ LOGGER.log(Level.FINE, ex.getMessage(),ex); }catch(TransformException ex){ LOGGER.log(Level.FINE, ex.getMessage(),ex); } } return true; } //ensure the geometry type match if(current != null && original != null){ current = JTSMapping.convertType(current,original.getClass()); } return false; } /** * Try to convert extract a geometry from the given object * @return Geometry or null if failed to adapt candidate to a geometry */ private Geometry adapt(Object candidate){ if(candidate == null){ return null; } if(candidate instanceof Geometry){ //already a geometry return (Geometry) candidate; } Geometry result = null; if(candidate instanceof String){ try { //try to parse it from WKT result = reader.read((String)candidate); } catch (ParseException ex) { LOGGER.log(Level.FINE, ex.getMessage(),ex); } }else if(candidate instanceof FeatureCollection){ final FeatureCollection col = (FeatureCollection) candidate; //we must merge all geometries //we use the regroup process without any attribute define FeatureIterator ite = null; try{ final ProcessDescriptor desc = ProcessFinder.getProcessDescriptor("vector", "regroup"); final ParameterValueGroup in = desc.getInputDescriptor().createValue(); in.parameter("feature_in").setValue(col); org.geotoolkit.process.Process proc = desc.createProcess(in); final FeatureCollection featureListOut = (FeatureCollection) proc.call().parameter("feature_out").getValue(); ite = featureListOut.iterator(); //we should have only one feature in this collection while(ite.hasNext()){ candidate = FeatureExt.deepCopy(ite.next()); } }catch(NoSuchIdentifierException ex){ LOGGER.log(Level.FINE, ex.getMessage(),ex); }catch(ProcessException ex){ LOGGER.log(Level.FINE, ex.getMessage(),ex); }finally{ if(ite != null){ ite.close(); } } }else if(candidate instanceof Collection){ final List<Geometry> geometries = new ArrayList<Geometry>(); //try to extract a single geometry from each element for(Object o : (Collection)candidate){ Geometry g = adapt(o); if(g != null){ geometries.add(g); } } //then merge the geometries if(!geometries.isEmpty()){ result = geometries.get(0); while(geometries.size()>1){ Geometry second = geometries.remove(1); final CoordinateReferenceSystem crs1 = getCRS(result); final CoordinateReferenceSystem crs2 = getCRS(second); if(crs1 != null && crs2 != null){ if(!Utilities.equalsIgnoreMetadata(crs1, crs2)){ //reproject second geometry try { final MathTransform trs = CRS.findOperation(crs2, crs1, null).getMathTransform(); second = JTS.transform(second, trs); } catch (FactoryException ex) { LOGGER.log(Level.FINE, ex.getMessage(),ex); } catch (TransformException ex) { LOGGER.log(Level.FINE, ex.getMessage(),ex); } } result = result.union(second); JTS.setCRS(result, crs1); }else{ result = result.union(second); if(crs1 != null){ JTS.setCRS(result, crs1); }else if(crs2 != null){ JTS.setCRS(result, crs2); } } } } } if(candidate instanceof Feature){ final Feature f = (Feature) candidate; if(FeatureExt.hasAGeometry(f.getType())){ result = (Geometry) FeatureExt.getDefaultGeometryAttributeValue(f); //make a copy and ensure the crs is set result = (Geometry) result.clone(); JTS.setCRS(result, FeatureExt.getCRS(f.getType())); } } return result; } private static CoordinateReferenceSystem getCRS(final Geometry geom){ try { return JTS.findCoordinateReferenceSystem(geom); } catch (NoSuchAuthorityCodeException ex) { LOGGER.log(Level.FINE, ex.getMessage(),ex); } catch (FactoryException ex) { LOGGER.log(Level.FINE, ex.getMessage(),ex); } return null; } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { guiApply = new javax.swing.JButton(); jLabel1 = new javax.swing.JLabel(); guiApply.setText(MessageBundle.format("paste")); // NOI18N guiApply.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { pasteFromApp(evt); } }); jLabel1.setText(MessageBundle.format("clipboard")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 122, Short.MAX_VALUE) .addComponent(guiApply)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(guiApply) .addComponent(jLabel1)) ); }// </editor-fold>//GEN-END:initComponents private void pasteFromApp(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pasteFromApp final Geometry old = getGeometry(); if(checkClipboard(false)){ firePropertyChange(GEOMETRY_PROPERTY, old, getGeometry()); } }//GEN-LAST:event_pasteFromApp // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton guiApply; private javax.swing.JLabel jLabel1; // End of variables declaration//GEN-END:variables }