eu.limetri.client.mapviewer.nb.jxmap.map.RootMapPanelController Maven / Gradle / Ivy
/**
* Copyright (C) 2008-2012 AgroSense Foundation.
*
* AgroSense 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.
*
* There are special exceptions to the terms and conditions of the GPLv3 as it is applied to
* this software, see the FLOSS License Exception
* .
*
* AgroSense 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 AgroSense. If not, see .
*/
package eu.limetri.client.mapviewer.nb.jxmap.map;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import nl.cloudfarming.eventbus.GuiEvent;
import nl.cloudfarming.eventbus.GuiEventBus;
import nl.cloudfarming.eventbus.GuiEventKey;
import nl.cloudfarming.eventbus.GuiEventListener;
import org.openide.nodes.Node;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import eu.limetri.api.geo.Geographical;
import eu.limetri.client.mapviewer.api.Layer;
import eu.limetri.client.mapviewer.api.LayerDropTarget;
import eu.limetri.client.mapviewer.api.LayerInfo;
import eu.limetri.client.mapviewer.api.ObjectLayer;
import eu.limetri.client.mapviewer.api.SingleObjectLayer;
import eu.limetri.client.mapviewer.api.event.GeoEvent;
import eu.limetri.client.mapviewer.data.GeoPosition;
import eu.limetri.client.mapviewer.nb.jxmap.LayerPanel;
import eu.limetri.client.mapviewer.nb.jxmap.MapViewerTopComponent;
import eu.limetri.client.mapviewer.nb.jxmap.Module;
import eu.limetri.client.mapviewer.nb.jxmap.RootMapPanel;
import eu.limetri.client.mapviewer.nb.jxmap.layerlist.LayerListController;
import eu.limetri.client.mapviewer.swing.jxmap.layerlist.AbstractLayerListNode;
import eu.limetri.client.mapviewer.swing.jxmap.map.LayerDropTargetListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
/**
* Controller of the rootmap panel.
*
* The RootMapPanelController is the
* MapController
implementation for the JXMap geoviewer
* implementation. It exposes methods to control this map implementation.
*
* Swing hierarchy
The top swing component for the
* RootMapController
is the {@link MapViewerTopComponent}. This
* TopComponent only contains the hook to the netbeans window management system,
* like {@link #setActive(boolean)} on componentActivated and
* componentDeactivated. The controller delivers the root panel to TopComponent
* which is a {@link RootMapPanel}. The Controller controls the state and
* content of this root panel.
The {@link RootMapPanel} is a
* JXPanel
which contains a JLayerPane. The layered pane contains
* several layers starting with the JXMap layer as background.
Layer
* containing object ({@link ObjectLayer)} implementations) are represented as
* an {@link ObjectLayerPanel} and added to the layered panel on the
* {@link RootMapPanel.LayerGroup#LAYER_ACTIVE} position.
* ObjectLayerPanel
s are ObjectScenes and contain
* LayerObjectWidget
s representing geographical components on the
* map.
*
* MapViewerTopComponent->RootMapPanel->ObjectLayerPanel->LayerObjectWidget
*
* @author Timon Veenstra
*/
public class RootMapPanelController {
private final RootMapPanel mapPanel;
private final Map layerPanelMap = new HashMap<>();
private static int lastId = 0;
private final LayerDropTargetListener dropTargetListener = new LayerDropTargetListener();
private final RequestFocusEventListener requestFocusEventListener = new RequestFocusEventListener();
private static final Logger LOGGER = Logger.getLogger(RootMapPanelController.class.getName());
private static final int DEFAULT_ZOOM_LEVEL = 3;
private PropertyChangeListener orderChangeListener;
private PropertyChangeListener selectionChangeListener;
public RootMapPanelController(LayerListController layerListController) {
mapPanel = new RootMapPanel(layerListController.getLayerList());
//
// register a drop target listener for the layerlist component
//
DropTarget dt = new DropTarget(layerListController.getLayerList(), dropTargetListener);
dt.setDefaultActions(DnDConstants.ACTION_COPY);
dt.setActive(true);
layerListController.getLayerList().setDropTarget(dt);
//
// register a drop target listener for the top panel of the map component
//
DropTarget dt2 = new DropTarget(mapPanel.getTopPanel(), dropTargetListener);
dt.setDefaultActions(DnDConstants.ACTION_COPY);
dt.setActive(true);
mapPanel.getTopPanel().setDropTarget(dt2);
//
// add the request focus listener
//
GuiEventBus.addListener(requestFocusEventListener);
orderChangeListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
mapPanel.repaintReorder(layerPanelMap.values());
}
};
selectionChangeListener = new PropertyChangeListener() {
boolean selecting = false;
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!selecting) {
selecting = true;
Boolean selected = (Boolean) evt.getNewValue();
LayerInfo info = (LayerInfo) evt.getSource();
//deselect other layers
if (selected) {
for (LayerPanel lp : layerPanelMap.values()) {
if (!lp.getInfo().equals(info)) {
lp.getInfo().setSelected(false);
}
}
}
selecting = false;
mapPanel.refreshSelectedLayer();
}
}
};
}
public void addLayerDropTarget(LayerDropTarget dropTarget) {
dropTargetListener.addDropTarget(dropTarget);
}
public RootMapPanel getPanel() {
return mapPanel;
}
public void addLayerNode(Node layerNode, LayerInfo layerInfo) {
Layer layer = Layer.Finder.findLayer(layerNode);
//FIXME set propert ID, should depend on layer order since its used for event dispatching
if (layerInfo != null) {
layerInfo.setOrder(lastId);
}
if (layer instanceof SingleObjectLayer) {
SingleObjectLayer singleObjectLayer = (SingleObjectLayer) layer;
if (!singleObjectLayer.hasGeometry() && layerInfo != null) {
layerInfo.setOrder(-1); //-1 to be at the beginning of list and on the top of the map
}
}
LayerPanel layerPanel = new LayerPanel(layerNode, mapPanel.getMapViewer(), lastId++, layerInfo);
//
// let layerpanel listen to selection changes in layelist em.
//
layer.addPropertyChangeListener(layerPanel);
//
// save reference to the layerpanel and add it to the map panel
//
layerPanelMap.put(layer, layerPanel);
mapPanel.addLayerPanel(layerPanel);
if (layerInfo != null) {
layerInfo.addPropertyChangeListener(LayerInfo.PROPERTY_ORDER, orderChangeListener);
layerInfo.addPropertyChangeListener(LayerInfo.PROPERTY_SELECTED, selectionChangeListener);
}
}
public void removeLayerNode(Node layerNode) {
final Layer layer = Layer.Finder.findLayer(layerNode);
if (layer == null) {
LOGGER.warning("removeLayerNode called with a node without a layer in its hierarchy");
return;
}
LayerPanel layerPanel = layerPanelMap.get(layer);
//
// remove reference to the layerpanel and remove it from the map panel
//
mapPanel.removeLayerPanel(layerPanel);
layerPanelMap.remove(layer);
if (layerNode instanceof AbstractLayerListNode) {
AbstractLayerListNode abstractLayerListNode = (AbstractLayerListNode) layerNode;
LayerInfo layerInfo = abstractLayerListNode.getInfo();
layerInfo.removePropertyChangeListener(LayerInfo.PROPERTY_ORDER, orderChangeListener);
layerInfo.removePropertyChangeListener(LayerInfo.PROPERTY_SELECTED, selectionChangeListener);
}
}
public void refreshLayerNode(Node layerNode) {
final Layer layer = Layer.Finder.findLayer(layerNode);
if (layer == null) {
LOGGER.warning("refreshLayerNode called with a node without a layer in its hierarchy");
return;
}
LayerPanel layerPanel = layerPanelMap.get(layer);
if (layerPanel != null) {
layerPanel.repaint();
} else {
LOGGER.log(Level.WARNING, "refresh requested for unmanaged layer {0} in node {1}", new Object[]{layer, layerNode});
}
}
private class RequestFocusEventListener implements GuiEventListener {
@Override
public void onEvent(GuiEvent event) {
Geographical geographical = event.getContent();
Point centroid = geographical.getCentroid();
if (centroid != null) {
GeoPosition geoPosition = new GeoPosition(centroid.getY(), centroid.getX());
mapPanel.getMapViewer().setCenterPosition(geoPosition);
Geometry boundingBox = geographical.getBoundingBox();
if (boundingBox instanceof Polygon) {
Polygon polygon = (Polygon) boundingBox;
LineString exteriorRing = polygon.getExteriorRing();
Coordinate leftTopCorner = exteriorRing.getCoordinateN(0);
Coordinate rightBottomCorner = exteriorRing.getCoordinateN(2);
mapPanel.getMapViewer().setZoomFromGeoPosition(new GeoPosition(leftTopCorner.y, leftTopCorner.x), new GeoPosition(rightBottomCorner.y, rightBottomCorner.x));
} else {
//Default zoom level
mapPanel.getMapViewer().setZoom(DEFAULT_ZOOM_LEVEL);
}
}
}
@Override
public boolean listensTo(GuiEventKey guiEventKey) {
return GeoEvent.REQUEST_FOCUS.equals(guiEventKey);
}
@Override
public String getModuleName() {
return Module.MODULE_NAME;
}
}
}