Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
nl.cloudfarming.client.geoviewer.edit.GeoEditorController Maven / Gradle / Ivy
/**
* Copyright (C) 2010-2012 Agrosense [email protected]
*
* Licensed under the Eclipse Public License - v 1.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package nl.cloudfarming.client.geoviewer.edit;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
import java.awt.Color;
import java.beans.IntrospectionException;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import nl.cloudfarming.client.geoviewer.Geometrical;
import nl.cloudfarming.client.geoviewer.Palette;
import nl.cloudfarming.client.geoviewer.render.GeoTranslator;
import nl.cloudfarming.client.geoviewer.render.GeometricalWidget;
import nl.cloudfarming.client.geoviewer.render.SimpleGeoTranslator;
import nl.cloudfarming.client.util.ExplorerManagerUtil;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.netbeans.api.visual.action.ActionFactory;
import org.netbeans.api.visual.model.ObjectSceneEvent;
import org.netbeans.api.visual.model.ObjectSceneEventType;
import org.netbeans.api.visual.model.ObjectSceneListener;
import org.netbeans.api.visual.model.ObjectState;
import org.netbeans.api.visual.widget.Widget;
import org.openide.explorer.ExplorerManager;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.NbBundle.Messages;
/**
* controller for the surface editor view
*
* @author Timon Veenstra
*/
@Messages("geo_editor.action_add_point=Add point")
public class GeoEditorController implements ExplorerManager.Provider, ObjectSceneListener {
private static final Logger LOGGER = Logger.getLogger("nl.cloudfarming.client.geoviewer.edit.GeoEditorController");
private static final double FORM_FACTOR = 100000.0;
private static final int MARGIN_X = 100;
private static final int MARGIN_Y = 100;
private final GeoEditorScene scene = new GeoEditorScene();
private JComponent view = scene.createView();
private List context;
private final GeoTranslator geoTranslator;
private Geometry sceneBoundingBox;
private ExplorerManager em = new ExplorerManager();
private Palette palette = new Palette(Color.red);
private ExplorerSelectionListener esl = new ExplorerSelectionListener();
public GeoEditorController(List context) {
geoTranslator = new SimpleGeoTranslator();
setContext(context);
em.setRootContext(new RootNode());
em.addPropertyChangeListener(esl);
scene.getActions().addAction(ActionFactory.createZoomAction());
scene.getActions().addAction(ActionFactory.createPanAction());
scene.getActions().addAction(scene.createObjectHoverAction());
scene.getActions().addAction(scene.createSelectAction());
scene.addObjectSceneListener(this, ObjectSceneEventType.OBJECT_STATE_CHANGED, ObjectSceneEventType.OBJECT_SELECTION_CHANGED);
// scene.getActions().addAction(ActionFactory.createPopupMenuAction(new EditPopupProvider()));
}
final void setContext(List context) {
assert context.size() >= 1 : "context should always at least contain one Geometrical";
this.context = context;
applyContext();
}
/**
* Calculates a square bounding box around a list of geometricals containing
* geometries. The biggest of height and width will be applied to the other
* variable, creating a square box respecting aspect ratio's when drawn.
*
* When there is only one geometrical in the list, and it does not contain a
* geometry, //TODO figure out what to take as default bounding box
*
* @param context List with geometricals
* @return square bounding box
*/
public Geometry calculateSquareBoundingBox(List context) {
Geometry boundingBox = null;
for (Geometrical geometrical : context) {
Geometry addedBoundingBox = geometrical.getBoundingBox() != null ? geometrical.getBoundingBox() : geometrical.getGeometry().getEnvelope();
boundingBox = sceneBoundingBox == null ? addedBoundingBox : sceneBoundingBox.union(addedBoundingBox);
}
boundingBox = boundingBox.getEnvelope();
// gather min and max coordinates
double minx = 0.0, maxx = 0.0, miny = 0.0, maxy = 0.0;
for (Coordinate c : boundingBox.getCoordinates()) {
minx = (c.x < minx) ? c.x : minx;
miny = (c.y < miny) ? c.y : miny;
maxx = (c.x > maxx) ? c.x : maxx;
maxy = (c.y > maxy) ? c.y : maxy;
}
// transform to square
// x axis smaller then y axis, enlarge x
if (maxx - minx < maxy - miny) {
maxx = minx + (maxy - miny);
// y axis smaller then x axis, enlarge y
} else if (maxx - minx > maxy - miny) {
maxy = miny + (maxx - minx);
}
// create new geometry
GeometryFactory factory = JTSFactoryFinder.getGeometryFactory(null);
Coordinate[] coordinates = new Coordinate[5];
coordinates[0] = new Coordinate(minx, miny);
coordinates[1] = new Coordinate(minx, maxy);
coordinates[2] = new Coordinate(maxx, maxy);
coordinates[3] = new Coordinate(maxx, miny);
coordinates[4] = new Coordinate(minx, miny);
CoordinateSequence coordinateSequence = new CoordinateArraySequence(coordinates);
LinearRing ring = new LinearRing(coordinateSequence, factory);
Geometry square = factory.createPolygon(ring, null);
return square;
}
private void applyContext() {
LOGGER.log(Level.FINEST, "applyContext with {0} geometricals", context.size());
sceneBoundingBox = calculateSquareBoundingBox(context);
LOGGER.log(Level.FINEST, "Final bounding box {0}", sceneBoundingBox.toText());
}
public void activateEditor() {
GeoEditorModalWindow dialog = new GeoEditorModalWindow(em);
dialog.setView(view);
dialog.setVisible(true);
int returnStatus = dialog.getReturnStatus();
//TODO process return status
}
private void addGeometry(Node geometricalNode) {
if (!scene.getObjects().contains(geometricalNode)) {
GeometricalWidget gw = new GeometricalWidget(scene, geoTranslator, geometricalNode.getLookup().lookup(Geometrical.class), palette, sceneBoundingBox);
gw.getActions().addAction(scene.createSelectAction());
gw.getActions().addAction(scene.createObjectHoverAction());
scene.addChild(gw);
scene.addObject(geometricalNode, gw);
}
}
protected GeoEditorScene getScene() {
return scene;
}
// private void addGeometry(Geometry geometry) {
// GeoNode prev = null;
// GeoNode first = null;
//
// for (int i = 0; i < geometry.getCoordinates().length - 1; i++) {
// Coordinate c = geometry.getCoordinates()[i];
// GeoNode geoNode = new GeoNode(new Coordinate(c.x, c.y));
// if (!scene.getNodes().contains(geoNode)) {
// Widget w = scene.addNode(geoNode);
//
// //translate to coordinate to a point
//
// Point2D location = geoTranslator.geoToPixel(scene.getClientArea(), sceneBoundingBox, geoNode.getCoordinate());//coordinateToPoint(geoNode.getCoordinate());
// LOGGER.log(Level.FINEST, "Determined local location for the point to be {0}", location.toString());
// // replace the point based on the widget size
// int x = (int) (location.getX() - ((double) w.getPreferredSize().width / 2));
// int y = (int) (location.getY() - ((double) w.getPreferredSize().height / 2));
// w.setPreferredLocation(new Point(x, y));
//
// if (first == null) {
// first = geoNode;
// } else {
// scene.connectNodes(geoNode, prev);
//
// }
// prev = geoNode;
// }
//
// }
// scene.connectNodes(prev, first);
// }
// /**
// * Provides a popup menu for the edit component
// *
// */
// private class EditPopupProvider implements PopupMenuProvider {
//
// @Override
// public JPopupMenu getPopupMenu(Widget widget, final Point localLocation) {
// JPopupMenu menu = new JPopupMenu();
// menu.add(new AbstractAction(NbBundle.getMessage(this.getClass(), "geo_editor.action_add_point")) {
//
// @Override
// public void actionPerformed(ActionEvent e) {
// assert SwingUtilities.isEventDispatchThread();
// Point p = localLocation;
// p.x = p.x - MARGIN_X;
// p.y = p.y - MARGIN_Y;
//
// GeoNode geoNode = new GeoNode(geoTranslator.pixelToGeo(scene.getClientArea(), sceneBoundingBox, p));
// scene.addNode(geoNode).setPreferredLocation((Point) geoTranslator.geoToPixel(scene.getClientArea(), sceneBoundingBox, geoNode.getCoordinate()));
// scene.validate();
// }
// });
// return menu;
// }
// }
@Override
public ExplorerManager getExplorerManager() {
return em;
}
@Override
public void objectAdded(ObjectSceneEvent event, Object addedObject) {
}
@Override
public void objectRemoved(ObjectSceneEvent event, Object removedObject) {
}
//
// state control variables to prevent update cycles
private boolean removingObjects = false;
private boolean incomingSelectionChange = false;
private boolean outgoingSelectionChange = false;
@Override
public void objectStateChanged(ObjectSceneEvent event, Object changedObject, ObjectState previousState, ObjectState newState) {
LOGGER.finest("objectStateChanged");
Widget widget = event.getObjectScene().findWidget(changedObject);
if (widget != null) {
if (!removingObjects
&& !incomingSelectionChange) {
outgoingSelectionChange = true;
if (changedObject instanceof Node) {
//
// add node to the selection
//
if (!previousState.isSelected() && newState.isSelected()) {
ExplorerManagerUtil.addNodeToSelection((Node) changedObject, em);
}
//
// remove node from the selection
//
if (previousState.isSelected() && !newState.isSelected()) {
ExplorerManagerUtil.removeNodeFromSelection((Node) changedObject, em);
}
}
outgoingSelectionChange = false;
}
}
}
@Override
public void selectionChanged(ObjectSceneEvent event, Set previousSelection, Set newSelection) {
}
@Override
public void highlightingChanged(ObjectSceneEvent event, Set previousHighlighting, Set newHighlighting) {
}
@Override
public void hoverChanged(ObjectSceneEvent event, Object previousHoveredObject, Object newHoveredObject) {
}
@Override
public void focusChanged(ObjectSceneEvent event, Object previousFocusedObject, Object newFocusedObject) {
}
private class RootNode extends AbstractNode {
public RootNode() {
super(Children.create(new GeometricalChildFactory(), false));
}
}
private class GeometricalChildFactory extends ChildFactory {
@Override
protected boolean createKeys(List toPopulate) {
toPopulate.addAll(context);
return true;
}
@Override
protected Node createNodeForKey(Geometrical key) {
try {
// create a new geometrical node
GeometricalNode node = new GeometricalNode(key);
// add the geometry to the editor window
addGeometry(node);
return node;
} catch (IntrospectionException ex) {
LOGGER.log(Level.SEVERE, "Error occured while creating a node for {0} : {0}", new Object[]{key, ex});
return null;
}
}
}
/**
* Listener for changes in the node selection of the explorer. Will change
* the selection state of the corresponding widgets
*/
private class ExplorerSelectionListener implements PropertyChangeListener {
public ExplorerSelectionListener() {
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
//
// synchronize selection changes in the explorer manager to the editor
//
if (!outgoingSelectionChange && ExplorerManager.PROP_SELECTED_NODES.equals(evt.getPropertyName())) {
Node[] newSelection = (Node[]) evt.getNewValue();
Set selection = new HashSet<>();
for (Node selected : newSelection) {
// only add to selection if the object is part of this scene
if (scene.findStoredObject(selected) != null) {
selection.add(selected);
}
}
incomingSelectionChange = true;
scene.setSelectedObjects(selection);
incomingSelectionChange = false;
view.repaint();
}
}
}
}