/* * Copyright (C) 2014 Alec Dhuse * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package co.foldingmap.actions; import co.foldingmap.Logger; import co.foldingmap.dataStructures.SmartTokenizer; import co.foldingmap.map.DigitalMap; import co.foldingmap.map.Layer; import co.foldingmap.map.MapObject; import co.foldingmap.map.vector.Coordinate; import co.foldingmap.map.vector.CoordinateMath; import co.foldingmap.map.vector.MapPoint; import co.foldingmap.map.vector.VectorLayer; import co.foldingmap.map.vector.VectorObject; import java.awt.Toolkit; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.util.ArrayList; import java.util.StringTokenizer; /** * Attempts to create objects from Plain text clipboard data. * * @author Alec */ public class PasteText extends Action { private ArrayList<MapObject> newObjects; private DigitalMap mapData; public PasteText(DigitalMap mapData) { this.mapData = mapData; this.newObjects = new ArrayList<MapObject>(); } /** * Returns if this Action can be undone. * * @return */ @Override public boolean canUndo() { return true; } @Override public void execute() { String clipboardText; Transferable clipboardTransferable; VectorLayer vectorLayer; VectorObject vObject; try { clipboardTransferable = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null); clipboardText = (String) clipboardTransferable.getTransferData(DataFlavor.stringFlavor); vectorLayer = null; StringTokenizer st = new StringTokenizer(clipboardText, "\n"); while (st.hasMoreElements()) { String token = st.nextToken(); vObject = parsePoint(token); if (vObject != null) { newObjects.add(vObject); //Find a VectorLayer to add the new MapPoint to. if (mapData.getSelectedLayer() instanceof VectorLayer) { vectorLayer = (VectorLayer) mapData.getSelectedLayer(); } else { for (Layer l: mapData.getLayers()) { if (l instanceof VectorLayer) vectorLayer = (VectorLayer) l; } } mapData.getCoordinateSet().put(vObject.getCoordinateList().get(0)); vectorLayer.addObject(vObject); } } } catch (Exception e) { Logger.log(Logger.ERR, "Error in PasteText.execute() - " + e); } } /** * Tries to parse a coordinate from plain text. * Returns null if it fails. * * @param text * @return */ public static MapPoint parsePoint(String text) { Coordinate returnVal; float alt, f1, f2; double lat, lon; String l1, l2, name, token; StringTokenizer tokenizer; //init returnVal = null; lat = 0; lon = 0; alt = 0; name = "Pasted Point"; if (text.contains("N") || text.contains("S") || text.contains("E") || text.contains("W") ) { //Try for format like: E: 121° 57.7" N: 24° 46' 27.9" SmartTokenizer st = new SmartTokenizer(text); String deg = "0°"; String min = "0'"; String sec = "0\""; if (text.contains("E")) { st.jumpAfterChar('E'); } else if (text.contains("e")) { st.jumpAfterChar('e'); } else if (text.contains("W")) { st.jumpAfterChar('W'); } else if (text.contains("w")) { st.jumpAfterChar('w'); } token = st.nextToken(); while (!token.contains("N") && !token.contains("n") && !token.contains("S") && !token.contains("s")) { if (token.endsWith("°")) { deg = token; } else if (token.endsWith("'")) { min = token; } else if (token.endsWith("\"")) { sec = token; } token = st.nextToken(); } lon = CoordinateMath.convertHourToDecimal(deg + " " + min + " " + sec); lat = CoordinateMath.convertHourToDecimal(st.toString()); if (Coordinate.isLongitudeValid(lon) && Coordinate.isLatitudeValid(lat)) { returnVal = new Coordinate(0, lat, lon); if (returnVal != null) return new MapPoint(name, "(Unspecified Point)", "", returnVal); } } else if (text.matches("[0-9a-z\\-, ]*lat\\:[0-9\\. ]*, lng\\:[0-9\\.\\- ]*")) { if (text.contains(",")) { StringTokenizer st = new StringTokenizer(text, ","); String s; String latStr = "0"; String lonStr = "0"; try { while (st.hasMoreElements()) { s = st.nextToken().trim(); if (s.contains("lat")) { latStr = s.substring(s.indexOf(" ")); lat = Double.parseDouble(latStr); } else if (s.contains("lng")) { lonStr = s.substring(s.indexOf(" ")); lon = Double.parseDouble(lonStr); } else { name = s; } } } catch (Exception e) { } returnVal = new Coordinate(0, lat, lon); if (returnVal != null) return new MapPoint(name, "(Unspecified Point)", "", returnVal); } } else { if (text.contains(",")) { //possibly comma delimited tokenizer = new StringTokenizer("text", ","); } else { //Try white space delimited tokenizer = new StringTokenizer(text); } //Try to extract Lat and Lon if (tokenizer.countTokens() >= 2) { l1 = tokenizer.nextToken(); l2 = tokenizer.nextToken(); try { f1 = Float.parseFloat(l1); f2 = Float.parseFloat(l2); //Try to decide which is lat and lon if (f1 > 90f) { // try to use f1 as lon lat = f2; lon = f1; } else { lat = f1; lon = f2; } } catch (Exception e) { Logger.log(Logger.INFO, "Error in PasteText.parseCoordinate(String) - Cound Not Parse Coordinate"); } } //Check if they are valid if (Coordinate.isLongitudeValid(lon) && Coordinate.isLatitudeValid(lat)) returnVal = new Coordinate(0, lat, lon); //try to extract altitude as third token if (tokenizer.hasMoreTokens()) { alt = Float.parseFloat(tokenizer.nextToken()); returnVal.setAltitude(alt); } } if (returnVal != null) return new MapPoint(name, "(Unspecified Point)", "", returnVal); return null; } @Override public void undo() { for (MapObject object: this.newObjects) { if (object instanceof VectorObject) { ((VectorLayer) object.getParentLayer()).removeObject((VectorObject) object); } else { Logger.log(Logger.ERR, "Error in PasteText.undo() - Can't Remove Object From Layer"); } } } }