/*
* Copyright 2013 Serdar.
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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 de.fub.maps.project.plugins.tasks.eval;
import de.fub.agg2graph.roadgen.Road;
import de.fub.agg2graph.roadgen.RoadNetwork;
import de.fub.agg2graph.structs.DoubleRect;
import de.fub.agg2graph.structs.ILocation;
import de.fub.agg2graphui.controller.AbstractLayer;
import de.fub.maps.project.openstreetmap.service.MapProvider;
import de.fub.maps.project.plugins.mapmatcher.MapMatcher;
import de.fub.maps.project.utils.LayerTableCellRender;
import de.fub.mapviewer.ui.MapViewerTileFactory;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JPopupMenu;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.MenuElement;
import org.jdesktop.swingx.mapviewer.TileFactory;
import org.netbeans.api.annotations.common.StaticResource;
import org.openide.awt.DropDownButtonFactory;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.ExplorerUtils;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;
import org.openide.windows.TopComponent;
/**
*
* @author Serdar
*/
@NbBundle.Messages({
"CLT_Show_Hide_Layers=Shows/Hides Layers",
"CLT_Show_Hide_Layer_View=Shows/Hides Layer View",
"CLT_Fit_Map_To_Size_Tooltip=Zoom the map to the size of the viewport.",
"CLT_StatusBar_Button_Tooltip=Status bar enable/disable"
})
public class EvaluatorTopComponent extends TopComponent implements ExplorerManager.Provider {
private static final long serialVersionUID = 1L;
@StaticResource
private static final String LAYER_ICON_PATH = "de/fub/maps/project/plugins/tasks/eval/layersIcon.png";
@StaticResource
private static final String LAYERVIEW_ICON_PATH = "de/fub/maps/project/plugins/tasks/eval/layerview.png";
@StaticResource
private static final String FIT_MAP_TO_SIZE_BUTTON_ICON_PATH = "de/fub/maps/project/plugins/tasks/eval/zoomToMap.png";
// @StaticResource
// private static final String STATUS_BAR_VISIBLE_ICON_PATH = "de/fub/mapsforge/plugins/tasks/eval/statusbarIcon.png";
private final OSMEvaluatorProcess osmEvaluatorProcess = new OSMEvaluatorProcess();
private final ExplorerManager explorerManager = new ExplorerManager();
private JComboBox<TileFactory> tileSourceComboBox;
private JPopupMenu layersMenu;
private JButton layersButton;
private JToggleButton layerViewButton;
private JButton fitToSizeButton;
private transient final LayerNodeFactory nodeFactory = new LayerNodeFactory();
private transient final Object MUTEX_UPDATE = new Object();
private transient final RequestProcessor requestProcessor = new RequestProcessor();
private RoadNetwork roadNetwork;
/**
* Creates new form EvaluatorTopComponent
*/
public EvaluatorTopComponent() {
super();
initComponents();
initGui();
}
public EvaluatorTopComponent(MapMatcher mapMatcher, MapProvider mapProvider, RoadNetwork roadNetwork) {
this();
assert mapMatcher != null && mapProvider != null && roadNetwork != null;
setDisplayName(MessageFormat.format("Map Evaluation: [{0}/{1}]", mapMatcher.getClass().getSimpleName(), mapProvider.getClass().getSimpleName()));
this.roadNetwork = roadNetwork;
osmEvaluatorProcess.setInput(roadNetwork);
osmEvaluatorProcess.setMapMatcher(mapMatcher);
osmEvaluatorProcess.setMapProvider(mapProvider);
associateLookup(new ProxyLookup(ExplorerUtils.createLookup(explorerManager, getActionMap()), Lookups.fixed(jPanel3)));
}
private void initGui() {
jSplitPane1.setResizeWeight(1);
jSplitPane1.setDividerLocation(1);
mappingCost.setText(String.valueOf(0));
avgMappingDistance.setText(String.valueOf(0));
explorerManager.setRootContext(new AbstractNode(Children.create(nodeFactory, true)));
outlineView1.getOutline().setRowHeight(300);
outlineView1.getOutline().setRootVisible(false);
outlineView1.getOutline().setDefaultRenderer(Object.class, new LayerTableCellRender());
jSplitPane1.setDividerLocation(Integer.MAX_VALUE);
for (AbstractLayer<?> layer : osmEvaluatorProcess.getLayers()) {
aggTopComponent1.addLayer(layer);
}
// set up fit map to size button
if (fitToSizeButton == null) {
fitToSizeButton = new JButton(ImageUtilities.loadImageIcon(FIT_MAP_TO_SIZE_BUTTON_ICON_PATH, true));
fitToSizeButton.setToolTipText(Bundle.CLT_Fit_Map_To_Size_Tooltip());
fitToSizeButton.addActionListener(new FitToSizeButtonActionListenerImpl());
toolbar.add(fitToSizeButton, 0);
toolbar.add(new JToolBar.Separator(), 0);
}
// set up layer view button
if (layerViewButton == null) {
layerViewButton = new JToggleButton(ImageUtilities.loadImageIcon(LAYERVIEW_ICON_PATH, true));
layerViewButton.setSelected(false);
layerViewButton.setToolTipText(Bundle.CLT_Show_Hide_Layer_View());
layerViewButton.addActionListener(new LayerViewButtonActionListenerImpl());
toolbar.add(layerViewButton, 0);
}
// set up layer show/hide drop down button
if (layersMenu == null) {
layersMenu = new JPopupMenu();
initPopupMenu();
layersButton = DropDownButtonFactory.createDropDownButton(ImageUtilities.loadImageIcon(LAYER_ICON_PATH, true), layersMenu);
layersButton.setToolTipText(Bundle.CLT_Show_Hide_Layers());
layersButton.addActionListener(new LayerButtonActionListenerImpl());
toolbar.add(layersButton, 0);
} else {
layersMenu.removeAll();
initPopupMenu();
}
// set up tilesource combobox
if (tileSourceComboBox == null) {
ArrayList<? extends MapViewerTileFactory> tileSources = new ArrayList<MapViewerTileFactory>(Lookup.getDefault().lookupResult(MapViewerTileFactory.class).allInstances());
Collections.sort(tileSources);
tileSourceComboBox = new JComboBox<TileFactory>(tileSources.toArray(new TileFactory[tileSources.size()]));
tileSourceComboBox.setMaximumSize(new Dimension(150, 16));
tileSourceComboBox.setPreferredSize(tileSourceComboBox.getMaximumSize());
if (!tileSources.isEmpty()) {
tileSourceComboBox.setSelectedItem(tileSources.iterator().next());
}
tileSourceComboBox.addItemListener(new TileSourceComboBoxItemListenerImpl());
toolbar.add(new JToolBar.Separator(), 0);
toolbar.add(tileSourceComboBox, 0);
}
}
/**
* initializes and sets up the drop down menu of the Layer visiblity menu.
*/
private void initPopupMenu() {
nodeFactory.clear();
aggTopComponent1.clear();
for (final AbstractLayer<?> layer : osmEvaluatorProcess.getLayers()) {
aggTopComponent1.addLayer(layer);
nodeFactory.add(layer);
final JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem(layer.getName());
jCheckBoxMenuItem.setState(layer.isVisible());
jCheckBoxMenuItem.addActionListener(new LayerActionListener(layer, jCheckBoxMenuItem));
layersMenu.add(jCheckBoxMenuItem);
}
}
@Override
protected void componentOpened() {
super.componentOpened();
RequestProcessor.getDefault().post(new Runnable() {
@Override
public void run() {
osmEvaluatorProcess.start();
mappingCost.setText(String.format(Locale.ENGLISH, "%f", osmEvaluatorProcess.getMappingCost()));
avgMappingDistance.setText(String.format(Locale.ENGLISH, "%f", osmEvaluatorProcess.getAvgMappingDistance()));
}
});
}
private void updateMap() {
if (fitToSizeButton.isEnabled()) {
synchronized (MUTEX_UPDATE) {
fitToSizeButton.setEnabled(false);
try {
Area totalBoundingBox = new Area();
if (roadNetwork != null) {
Set<Road> roads = roadNetwork.getRoads();
for (Road road : roads) {
for (ILocation location : road.getNodes()) {
totalBoundingBox.add(new Area(new Rectangle2D.Double(location.getLat(), location.getLon(), 0.00000025, 0.00000025)));
}
}
}
Rectangle2D bounds = totalBoundingBox.getBounds2D();
aggTopComponent1.showArea(
new DoubleRect(
bounds.getX(),
bounds.getY(),
bounds.getWidth(),
bounds.getHeight()));
} finally {
fitToSizeButton.setEnabled(true);
}
}
}
}
private void updateLayerView() {
if (layerViewButton.isSelected()) {
jSplitPane1.setEnabled(true);
jSplitPane1.setDividerLocation(.8);
} else {
jSplitPane1.setEnabled(false);
jSplitPane1.setDividerLocation(1d);
}
}
@Override
public ExplorerManager getExplorerManager() {
return explorerManager;
}
@Override
public int getPersistenceType() {
return TopComponent.PERSISTENCE_NEVER;
}
private static class LayerActionListener implements ActionListener {
private final AbstractLayer<?> layer;
private final JCheckBoxMenuItem jCheckBoxMenuItem;
public LayerActionListener(AbstractLayer<?> layer, JCheckBoxMenuItem jCheckBoxMenuItem) {
this.layer = layer;
this.jCheckBoxMenuItem = jCheckBoxMenuItem;
}
@Override
public void actionPerformed(ActionEvent e) {
layer.setVisible(jCheckBoxMenuItem.getState());
}
}
private class LayerViewButtonActionListenerImpl implements ActionListener {
public LayerViewButtonActionListenerImpl() {
}
@Override
public void actionPerformed(ActionEvent e) {
updateLayerView();
}
}
private class TileSourceComboBoxItemListenerImpl implements ItemListener {
public TileSourceComboBoxItemListenerImpl() {
}
@Override
public void itemStateChanged(ItemEvent e) {
if (tileSourceComboBox.getSelectedItem() instanceof TileFactory) {
aggTopComponent1.setTileFactory((TileFactory) tileSourceComboBox.getSelectedItem());
}
}
}
private class LayerButtonActionListenerImpl implements ActionListener {
public LayerButtonActionListenerImpl() {
}
private boolean allVisible = true;
@Override
public void actionPerformed(ActionEvent e) {
allVisible = !allVisible;
MenuElement[] subElements = layersMenu.getSubElements();
for (MenuElement element : subElements) {
if (element instanceof JCheckBoxMenuItem) {
JCheckBoxMenuItem item = (JCheckBoxMenuItem) element;
item.doClick();
}
}
}
}
private class FitToSizeButtonActionListenerImpl implements ActionListener {
public FitToSizeButtonActionListenerImpl() {
}
@Override
public void actionPerformed(ActionEvent e) {
requestProcessor.post(new Runnable() {
@Override
public void run() {
updateMap();
}
});
}
}
/**
* 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() {
jPanel3 = new javax.swing.JPanel();
jPanel1 = new javax.swing.JPanel();
toolbar = new javax.swing.JToolBar();
jSeparator1 = new javax.swing.JToolBar.Separator();
jLabel1 = new javax.swing.JLabel();
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(4, 0), new java.awt.Dimension(4, 0), new java.awt.Dimension(4, 32767));
avgMappingDistance = new javax.swing.JLabel();
filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(16, 0), new java.awt.Dimension(16, 0), new java.awt.Dimension(16, 32767));
jLabel3 = new javax.swing.JLabel();
filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(4, 0), new java.awt.Dimension(4, 0), new java.awt.Dimension(4, 32767));
mappingCost = new javax.swing.JLabel();
jPanel2 = new javax.swing.JPanel();
jSplitPane1 = new javax.swing.JSplitPane();
aggTopComponent1 = new de.fub.agg2graphui.AggTopComponent();
outlineView1 = new org.openide.explorer.view.OutlineView("Layers");
setLayout(new java.awt.BorderLayout());
jPanel3.setLayout(new java.awt.BorderLayout());
jPanel1.setMaximumSize(new java.awt.Dimension(32767, 24));
jPanel1.setMinimumSize(new java.awt.Dimension(10, 24));
jPanel1.setPreferredSize(new java.awt.Dimension(100, 24));
jPanel1.setLayout(new java.awt.BorderLayout());
toolbar.setFloatable(false);
toolbar.setRollover(true);
toolbar.add(jSeparator1);
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(EvaluatorTopComponent.class, "EvaluatorTopComponent.jLabel1.text")); // NOI18N
toolbar.add(jLabel1);
toolbar.add(filler1);
avgMappingDistance.setBackground(new java.awt.Color(204, 204, 204));
avgMappingDistance.setFont(new java.awt.Font("Courier New", 0, 11)); // NOI18N
avgMappingDistance.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
org.openide.awt.Mnemonics.setLocalizedText(avgMappingDistance, org.openide.util.NbBundle.getMessage(EvaluatorTopComponent.class, "EvaluatorTopComponent.avgMappingDistance.text")); // NOI18N
avgMappingDistance.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(204, 204, 204)));
avgMappingDistance.setMaximumSize(new java.awt.Dimension(120, 14));
avgMappingDistance.setMinimumSize(new java.awt.Dimension(100, 14));
toolbar.add(avgMappingDistance);
toolbar.add(filler2);
org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(EvaluatorTopComponent.class, "EvaluatorTopComponent.jLabel3.text")); // NOI18N
toolbar.add(jLabel3);
toolbar.add(filler3);
mappingCost.setBackground(new java.awt.Color(204, 204, 204));
mappingCost.setFont(new java.awt.Font("Courier New", 0, 11)); // NOI18N
mappingCost.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
org.openide.awt.Mnemonics.setLocalizedText(mappingCost, org.openide.util.NbBundle.getMessage(EvaluatorTopComponent.class, "EvaluatorTopComponent.mappingCost.text")); // NOI18N
mappingCost.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(204, 204, 204)));
mappingCost.setMaximumSize(new java.awt.Dimension(100, 14));
toolbar.add(mappingCost);
jPanel1.add(toolbar, java.awt.BorderLayout.CENTER);
jPanel3.add(jPanel1, java.awt.BorderLayout.NORTH);
jPanel2.setLayout(new java.awt.BorderLayout());
jSplitPane1.setLeftComponent(aggTopComponent1);
jSplitPane1.setRightComponent(outlineView1);
jPanel2.add(jSplitPane1, java.awt.BorderLayout.CENTER);
jPanel3.add(jPanel2, java.awt.BorderLayout.CENTER);
add(jPanel3, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private de.fub.agg2graphui.AggTopComponent aggTopComponent1;
private javax.swing.JLabel avgMappingDistance;
private javax.swing.Box.Filler filler1;
private javax.swing.Box.Filler filler2;
private javax.swing.Box.Filler filler3;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel3;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JPanel jPanel3;
private javax.swing.JToolBar.Separator jSeparator1;
private javax.swing.JSplitPane jSplitPane1;
private javax.swing.JLabel mappingCost;
private org.openide.explorer.view.OutlineView outlineView1;
private javax.swing.JToolBar toolbar;
// End of variables declaration//GEN-END:variables
}