001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * JUMP is Copyright (C) 2003 Vivid Solutions
006: *
007: * This program implements extensions to JUMP and is
008: * Copyright (C) 2004 Integrated Systems Analysts, Inc.
009: *
010: * This program is free software; you can redistribute it and/or
011: * modify it under the terms of the GNU General Public License
012: * as published by the Free Software Foundation; either version 2
013: * of the License, or (at your option) any later version.
014: *
015: * This program is distributed in the hope that it will be useful,
016: * but WITHOUT ANY WARRANTY; without even the implied warranty of
017: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
018: * GNU General Public License for more details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with this program; if not, write to the Free Software
022: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
023: *
024: * For more information, contact:
025: *
026: * Integrated Systems Analysts, Inc.
027: * 630C Anchors St., Suite 101
028: * Fort Walton Beach, Florida
029: * USA
030: *
031: * (850)862-7321
032: * www.ashs.isa.com
033: */
034:
035: package org.openjump.core.ui.plugin.view;
036:
037: import java.awt.Component;
038: import java.awt.event.ContainerEvent;
039: import java.awt.event.ContainerListener;
040: import java.awt.event.MouseEvent;
041: import java.awt.event.MouseMotionAdapter;
042: import java.awt.geom.NoninvertibleTransformException;
043: import java.awt.geom.Point2D;
044: import java.text.DecimalFormat;
045: import java.util.Iterator;
046: import java.util.List;
047:
048: import org.openjump.core.geomutils.GeoUtils;
049:
050: import com.vividsolutions.jts.geom.Coordinate;
051: import com.vividsolutions.jts.geom.CoordinateList;
052: import com.vividsolutions.jts.geom.Geometry;
053: import com.vividsolutions.jts.geom.GeometryCollection;
054: import com.vividsolutions.jts.geom.LinearRing;
055: import com.vividsolutions.jts.geom.Polygon;
056: import com.vividsolutions.jts.util.UniqueCoordinateArrayFilter;
057: import com.vividsolutions.jump.I18N;
058: import com.vividsolutions.jump.feature.AttributeType;
059: import com.vividsolutions.jump.feature.Feature;
060: import com.vividsolutions.jump.feature.FeatureCollectionWrapper;
061: import com.vividsolutions.jump.feature.FeatureSchema;
062: import com.vividsolutions.jump.workbench.model.Layer;
063: import com.vividsolutions.jump.workbench.model.LayerManager;
064: import com.vividsolutions.jump.workbench.plugin.AbstractPlugIn;
065: import com.vividsolutions.jump.workbench.plugin.PlugInContext;
066: import com.vividsolutions.jump.workbench.ui.LayerViewPanel;
067: import com.vividsolutions.jump.workbench.ui.TaskFrame;
068: import com.vividsolutions.jump.workbench.ui.ToolTipWriter;
069:
070: public class MapToolTipPlugIn extends AbstractPlugIn {
071: private class GeoData {
072: public String type;
073: public double distance;
074: public int side;
075: public double length;
076: public double angle;
077: public double area;
078:
079: public void set(GeoData geoData) {
080: this .type = geoData.type;
081: this .distance = geoData.distance;
082: this .side = geoData.side;
083: this .length = geoData.length;
084: this .angle = geoData.angle;
085: this .area = geoData.area;
086: }
087: }
088:
089: PlugInContext gContext;
090: final static String sErrorSeeOutputWindow = I18N
091: .get("org.openjump.core.ui.plugin.view.MapToolTipPlugIn.Error-See-Output-Window");
092: final static String sPoint = I18N
093: .get("org.openjump.core.ui.plugin.view.MapToolTipPlugIn.Point");
094: final static String sSide = I18N
095: .get("org.openjump.core.ui.plugin.view.MapToolTipPlugIn.Side");
096: final static String sLength = I18N
097: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.length");
098: final static String sAngle = I18N
099: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.angle");
100: final static String sDegrees = I18N
101: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.degrees");
102: final static String sNoData = I18N
103: .get("org.openjump.core.ui.plugin.view.MapToolTipPlugIn.No-Data");
104: final static String sArea = I18N
105: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.area");
106:
107: private MouseMotionAdapter mouseMotionAdapter = new MouseMotionAdapter() {
108: public void mouseMoved(MouseEvent e) {
109: if (gContext.getWorkbenchContext().getLayerViewPanel() == null) {
110: return;
111: } //[Jon Aquino 2005-08-04]
112: ToolTipWriter toolTipWriter = new ToolTipWriter(gContext
113: .getWorkbenchContext().getLayerViewPanel());
114: toolTipWriter
115: .setEnabled(gContext.getWorkbenchContext()
116: .getLayerViewPanel().getToolTipWriter()
117: .isEnabled());
118: String fid = toolTipWriter.write("{FID}", e.getPoint());
119:
120: if (fid != null) {
121: String toolTipText = getData(Integer.parseInt(fid), e
122: .getPoint());
123: gContext.getWorkbenchContext().getLayerViewPanel()
124: .setToolTipText(toolTipText);
125: }
126: }
127: };
128:
129: public void initialize(final PlugInContext context)
130: throws Exception {
131: gContext = context;
132: context.getWorkbenchFrame().getDesktopPane()
133: .addContainerListener(new ContainerListener() {
134: public void componentAdded(ContainerEvent e) {
135: Component child = e.getChild();
136: if (child
137: .getClass()
138: .getName()
139: .equals(
140: "com.vividsolutions.jump.workbench.ui.TaskFrame")) {
141: ((TaskFrame) child).getLayerViewPanel()
142: .addMouseMotionListener(
143: mouseMotionAdapter);
144: }
145: }
146:
147: public void componentRemoved(ContainerEvent e) {
148: Component child = e.getChild();
149: if (child
150: .getClass()
151: .getName()
152: .equals(
153: "com.vividsolutions.jump.workbench.ui.TaskFrame")) {
154: ((TaskFrame) child).getLayerViewPanel()
155: .removeMouseMotionListener(
156: mouseMotionAdapter);
157: }
158: }
159: });
160: }
161:
162: public boolean execute(PlugInContext context) throws Exception {
163: try {
164: return true;
165: } catch (Exception e) {
166: context.getWorkbenchFrame().warnUser(sErrorSeeOutputWindow);
167: context.getWorkbenchFrame().getOutputFrame()
168: .createNewDocument();
169: context.getWorkbenchFrame().getOutputFrame().addText(
170: "MapToolTipPlugIn Exception:" + e.toString());
171: return false;
172: }
173: }
174:
175: private String getData(int fID, Point2D mouseLocation) {
176: int maxLinesOfData = 10;
177: String dataText = "<html>";
178: LayerViewPanel panel = gContext.getWorkbenchContext()
179: .getLayerViewPanel();
180: if (panel == null) {
181: return "";
182: }
183: LayerManager layerManager = panel.getLayerManager();
184: List layerList = layerManager.getVisibleLayers(false);
185: for (Iterator i = layerList.iterator(); i.hasNext();) {
186: Layer layer = (Layer) i.next();
187: FeatureSchema featureSchema = layer
188: .getFeatureCollectionWrapper().getFeatureSchema();
189: int numAttribs = featureSchema.getAttributeCount();
190: FeatureCollectionWrapper featureCollection = layer
191: .getFeatureCollectionWrapper();
192: List featureList = featureCollection.getFeatures();
193:
194: //for each layer iterate thru featureList
195: for (Iterator j = featureList.iterator(); j.hasNext();) {
196: Feature feature = (Feature) j.next();
197: int fid = feature.getID();
198:
199: if (fid == fID) {
200: Geometry geo = feature.getGeometry();
201: try {
202: Coordinate coord = panel.getViewport()
203: .toModelCoordinate(mouseLocation);
204: dataText += getGeoData(geo, coord);
205: } catch (NoninvertibleTransformException e) {
206: //let it go
207: }
208:
209: int NumLinesOfData = 1;
210:
211: for (int num = 0; num < numAttribs; num++) {
212: AttributeType type = featureSchema
213: .getAttributeType(num);
214:
215: if (type == AttributeType.STRING) {
216: String name = featureSchema
217: .getAttributeName(num);
218: String data = feature.getString(name)
219: .trim();
220: if ((!data.equals(""))
221: && (NumLinesOfData < maxLinesOfData)) {
222: dataText += "<br>" + name + ": " + data;
223: NumLinesOfData++;
224: }
225: }
226: }
227: return dataText + "</html>";
228: }
229: }
230: }
231: dataText += sNoData + "</html>";
232: return dataText;
233: }
234:
235: private String getGeoData(Geometry geo, Coordinate mousePt) {
236: GeoData geoData = getClosest(geo, mousePt);
237: DecimalFormat df2 = new DecimalFormat("##0.0#");
238: DecimalFormat df3 = new DecimalFormat("###,###,##0.0##");
239: String geoText = "";
240: if (geoData.area > 0)
241: geoText = geoData.type + ": " + sSide + ": " + geoData.side
242: + ", " + sLength + ": "
243: + df3.format(geoData.length) + ", " + sAngle + ": "
244: + df2.format(geoData.angle) + " " + sDegrees + ", "
245: + sArea + ": " + df2.format(geoData.area);
246: else
247: geoText = geoData.type + ": " + sSide + ": " + geoData.side
248: + ", " + sLength + ": "
249: + df3.format(geoData.length) + ", " + sAngle + ": "
250: + df2.format(geoData.angle) + " " + sDegrees;
251: if (geoData.type.equals("Point"))
252: geoText = "Point";
253: return geoText;
254: }
255:
256: private GeoData getClosest(Geometry geo, Coordinate mousePt) {
257: GeoData geoData;
258:
259: if ((geo.getGeometryType().equals("GeometryCollection"))
260: || (geo.getGeometryType().equals("MultiPoint"))
261: || (geo.getGeometryType().equals("MultiLineString"))
262: || (geo.getGeometryType().equals("MultiPolygon"))) {
263: geoData = getClosest(((GeometryCollection) geo)
264: .getGeometryN(0), mousePt);
265: for (int i = 1; i < ((GeometryCollection) geo)
266: .getNumGeometries(); i++) {
267: GeoData geoData2 = getClosest(
268: ((GeometryCollection) geo).getGeometryN(i),
269: mousePt);
270: if (geoData2.distance < geoData.distance) {
271: geoData.set(geoData2);
272: }
273: }
274: } else {
275: geo.getCoordinates();
276: CoordinateList coords = new CoordinateList();
277: UniqueCoordinateArrayFilter filter = new UniqueCoordinateArrayFilter();
278: geo.apply(filter);
279: coords.add(filter.getCoordinates(), false);
280:
281: //need to do this since UniqueCoordinateArrayFilter keeps the poly from being closed
282: if ((geo instanceof Polygon) || (geo instanceof LinearRing)) {
283: coords.add(coords.getCoordinate(0));
284: }
285:
286: int maxIndex = coords.size() - 1;
287: int side = 1;
288: double length = 0;
289: double angle = 0;
290: Coordinate p0;
291: Coordinate p1;
292: double distToClosestSide = mousePt.distance(coords
293: .getCoordinate(0));
294:
295: if (coords.size() > 1) {
296: p0 = coords.getCoordinate(0);
297: p1 = coords.getCoordinate(1);
298: length = p0.distance(p1);
299: angle = GeoUtils.getBearing180(p0, p1);
300: distToClosestSide = GeoUtils.getDistance(mousePt, p0,
301: p1);
302: }
303:
304: for (int i = 1; i < maxIndex; i++) {
305: p0 = coords.getCoordinate(i);
306: p1 = coords.getCoordinate(i + 1);
307: double distToSide = GeoUtils.getDistance(mousePt, p0,
308: p1);
309:
310: if (distToSide < distToClosestSide) {
311: side = i + 1;
312: length = p0.distance(p1);
313: angle = GeoUtils.getBearing180(p0, p1);
314: distToClosestSide = distToSide;
315: }
316: }
317: geoData = new GeoData();
318: geoData.type = geo.getGeometryType();
319: geoData.side = side;
320: geoData.length = length;
321: geoData.angle = angle;
322: geoData.distance = distToClosestSide;
323: geoData.area = geo.getArea();
324: }
325: return geoData;
326: }
327: }
328:
329: // this code shows how to add an ItemListener to a menu item
330: // so that you know when a menu item changes
331: // private ItemListener itemListener =
332: // new ItemListener()
333: // {
334: // public void itemStateChanged(ItemEvent e)
335: // {
336: //// String chk = context.getFeatureInstaller().menuBar().getMenu(2).getItem(13).getText();
337: // java.awt.Toolkit.getDefaultToolkit().beep();
338: // }
339: // };
340:
341: // add this to the initializer
342: // context.getFeatureInstaller().menuBar().getMenu(2).getItem(13).addItemListener(itemListener);
|