/*
* 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.datasource.ui;
import de.fub.gpxmodule.GPXDataObject;
import de.fub.gpxmodule.service.GPXProvider;
import de.fub.gpxmodule.xml.Gpx;
import de.fub.gpxmodule.xml.Trk;
import de.fub.gpxmodule.xml.Trkseg;
import de.fub.gpxmodule.xml.Wpt;
import de.fub.maps.project.datasource.spi.TrackSegmentBehaviour;
import de.fub.maps.project.datasource.spi.TrksegWrapper;
import de.fub.maps.project.datasource.spi.actions.SplitpanelAction;
import de.fub.maps.project.datasource.spi.actions.TrackSemgentExportAction;
import de.fub.maps.project.datasource.spi.factories.NodeFactory;
import de.fub.mapviewer.shapes.WaypointMarker;
import de.fub.utilsmodule.Collections.ObservableArrayList;
import de.fub.utilsmodule.Collections.ObservableList;
import de.fub.utilsmodule.color.ColorUtil;
import java.awt.Color;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.BeanInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import org.netbeans.api.annotations.common.StaticResource;
import org.netbeans.core.spi.multiview.CloseOperationState;
import org.netbeans.core.spi.multiview.MultiViewElement;
import org.netbeans.core.spi.multiview.MultiViewElementCallback;
import org.netbeans.swing.outline.Outline;
import org.openide.awt.UndoRedo;
import org.openide.explorer.ExplorerManager;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;
import org.openide.windows.TopComponent;
/**
*
* @author Serdar
*/
@MultiViewElement.Registration(
displayName = "#LBL_GPX_VISUAL",
iconBase = "de/fub/gpxmodule/gpx.png",
mimeType = "text/gpx+xml",
persistenceType = TopComponent.PERSISTENCE_ALWAYS,
preferredID = "GPXVisual",
position = 500)
@NbBundle.Messages({
"LBL_GPX_VISUAL=Map",
"CLT_Fit_Map_To_Size_Tooltip=Zoom the map to the size of the viewport."
})
public class MapViewElement extends javax.swing.JPanel implements MultiViewElement, ChangeListener, ExplorerManager.Provider {
@StaticResource
private static final String FIT_MAP_TO_SIZE_BUTTON_ICON_PATH = "de/fub/maps/project/datasource/ui/zoomToMap.png";
private static final long serialVersionUID = 1L;
private final JToolBar toolbar = new JToolBar();
private final ObservableList<TrksegWrapper> trackSegmentList = new ObservableArrayList<TrksegWrapper>();
private final HashMap<TrksegWrapper, List<WaypointMarker>> markerMap = new HashMap<TrksegWrapper, List<WaypointMarker>>();
private final ExplorerManager explorerManager = new ExplorerManager();
private final GPXDataObject obj;
private transient MultiViewElementCallback callback;
private transient GPXProvider gpxProvide;
private boolean modelChanged = true;
// mouselistener to check and display only the treseg that are visible
private final MouseListener mouseListener = new MouseAdapterImpl();
private boolean splitPanelVisble;
private final ProxyLookup lookup;
/**
* Creates new form MapViewElement
*/
public MapViewElement(Lookup lkp) {
obj = lkp.lookup(GPXDataObject.class);
assert obj != null;
lookup = new ProxyLookup(lkp, Lookups.singleton(MapViewElement.this));
init();
initOutlineView();
}
private void init() {
initComponents();
initToolBar();
explorerManager.setRootContext(new AbstractNode(Children.create(new NodeFactory(trackSegmentList), true)));
gpxProvide = obj.getLookup().lookup(GPXProvider.class);
gpxProvide.addChangeListener(WeakListeners.change(MapViewElement.this, gpxProvide));
update();
jSplitPane1.setDividerLocation(Integer.MAX_VALUE);
}
private void initOutlineView() {
outlineView1.setPropertyColumnDescription("visible", "Visible On/Off");
outlineView1.setDefaultActionAllowed(false);
Outline outline = outlineView1.getOutline();
outline.addMouseListener(WeakListeners.create(MouseListener.class, mouseListener, outline));
outline.setRootVisible(false);
TableColumnModel columnModel = outline.getColumnModel();
// replace the node column in which the segments bounding box is displayed
// to the end of the columns
int columnIndex = columnModel.getColumnIndex("Segment");
if (columnIndex == 0) {
TableColumn column = outline.getColumn("Segment");
columnModel.removeColumn(column);
columnModel.addColumn(column);
// set a fix width for the visible checkbox column
column = outline.getColumn("V");
if (column != null) {
column.setMaxWidth(24);
column.setMinWidth(24);
column.setPreferredWidth(24);
}
outlineView1.revalidate();
outline.repaint();
}
}
private void initToolBar() {
toolbar.setFloatable(false);
toolbar.add(new JToolBar.Separator());
JButton jButton = new JButton(new TrackSemgentExportAction(getExplorerManager()));
toolbar.add(jButton);
toolbar.add(new JToggleButton(new SplitpanelAction(MapViewElement.this)));
// set up fit map to size button
JButton 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 ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
abstractMapViewer1.setDisplayToFitMapMarkers();
}
});
toolbar.add(fitToSizeButton);
}
private void update() {
abstractMapViewer1.removeAllMarkers();
trackSegmentList.clear();
if (gpxProvide != null) {
Gpx gpx = gpxProvide.getGpx();
if (gpx != null) {
ColorUtil.ColorProvider colorProvider = ColorUtil.createColorProvider();
for (Trk trk : gpx.getTrk()) {
for (Trkseg trkseg : trk.getTrkseg()) {
Color color = colorProvider.getNextColor();
TrksegWrapper trksegWrapper = new TrksegWrapper(trk.getName(), trk.getDesc(), trkseg, color);
trackSegmentList.add(trksegWrapper);
for (Wpt trkpt : trkseg.getTrkpt()) {
WaypointMarker mapMarkerDot = new WaypointMarker(
color,
trkpt.getLat().doubleValue(),
trkpt.getLon().doubleValue());
putMarkerToMap(trksegWrapper, mapMarkerDot);
abstractMapViewer1.addMapMarker(mapMarkerDot);
}
}
}
abstractMapViewer1.setDisplayToFitMapMarkers();
}
}
modelChanged = false;
}
@Override
public String getName() {
return "GPXVisualElement";
}
@Override
public void addNotify() {
super.addNotify();
}
/**
* 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() {
jSplitPane1 = new javax.swing.JSplitPane();
abstractMapViewer1 = new de.fub.mapviewer.ui.AbstractMapViewer();
outlineViewPanel = new javax.swing.JPanel();
outlineView1 = new org.openide.explorer.view.OutlineView("Segment");
setLayout(new java.awt.BorderLayout());
jSplitPane1.setDividerLocation(1000000);
jSplitPane1.setDividerSize(0);
jSplitPane1.setResizeWeight(1.0);
jSplitPane1.setLeftComponent(abstractMapViewer1);
outlineViewPanel.setMinimumSize(new java.awt.Dimension(0, 0));
outlineViewPanel.setPreferredSize(new java.awt.Dimension(0, 100));
outlineViewPanel.setLayout(new java.awt.BorderLayout());
outlineView1.setPropertyColumns(new String[] {"visible", "V"});
outlineView1.setQuickSearchAllowed(false);
outlineViewPanel.add(outlineView1, java.awt.BorderLayout.CENTER);
jSplitPane1.setRightComponent(outlineViewPanel);
add(jSplitPane1, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private transient de.fub.mapviewer.ui.AbstractMapViewer abstractMapViewer1;
private javax.swing.JSplitPane jSplitPane1;
private transient org.openide.explorer.view.OutlineView outlineView1;
private javax.swing.JPanel outlineViewPanel;
// End of variables declaration//GEN-END:variables
public void setSplitPanelVisible(boolean visible) {
this.splitPanelVisble = visible;
if (splitPanelVisble) {
jSplitPane1.setDividerSize(5);
jSplitPane1.setDividerLocation(.75);
} else {
jSplitPane1.setDividerSize(0);
jSplitPane1.setDividerLocation(1.0);
}
}
public boolean isSplitpanelVisible() {
return this.splitPanelVisble;
}
@Override
public JComponent getVisualRepresentation() {
return this;
}
@Override
public JComponent getToolbarRepresentation() {
return toolbar;
}
@Override
public Action[] getActions() {
Action[] retValue;
// the multiviewObserver was passed to the element in setMultiViewCallback() method.
if (callback != null) {
retValue = callback.createDefaultActions();
// add you own custom actions here..
} else {
// fallback..
retValue = new Action[0];
}
return retValue;
}
@Override
public Lookup getLookup() {
return lookup;
}
@Override
public void componentOpened() {
}
@Override
public void componentClosed() {
}
@Override
public void componentShowing() {
if (modelChanged) {
update();
}
}
@Override
public void componentHidden() {
}
@Override
public void componentActivated() {
}
@Override
public void componentDeactivated() {
}
@Override
public UndoRedo getUndoRedo() {
return UndoRedo.NONE;
}
@Override
public void setMultiViewCallback(MultiViewElementCallback callback) {
this.callback = callback;
if (callback != null) {
Image icon = obj.getNodeDelegate().getIcon(BeanInfo.ICON_COLOR_16x16);
if (icon != null) {
callback.getTopComponent().setIcon(icon);
}
callback.getTopComponent().setDisplayName(obj.getName());
}
}
@Override
public CloseOperationState canCloseElement() {
return CloseOperationState.STATE_OK;
}
@Override
public void stateChanged(ChangeEvent e) {
if (e.getSource() != this) {
modelChanged = true;
}
}
@Override
public ExplorerManager getExplorerManager() {
return explorerManager;
}
private void putMarkerToMap(TrksegWrapper trkseg, WaypointMarker mapMarkerDot) {
if (!markerMap.containsKey(trkseg)) {
markerMap.put(trkseg, new ArrayList<WaypointMarker>());
}
markerMap.get(trkseg).add(mapMarkerDot);
}
private class MouseAdapterImpl extends MouseAdapter {
public MouseAdapterImpl() {
}
@Override
public void mouseClicked(MouseEvent e) {
Children children = getExplorerManager().getRootContext().getChildren();
for (Node node : children.getNodes()) {
if (node instanceof TrackSegmentBehaviour) {
TrackSegmentBehaviour trksegNode = (TrackSegmentBehaviour) node;
TrksegWrapper trkseg = node.getLookup().lookup(TrksegWrapper.class);
if (trkseg != null && markerMap.containsKey(trkseg)) {
for (WaypointMarker marker : markerMap.get(trkseg)) {
marker.setSelected(trksegNode.isSelected());
marker.setVisible(trksegNode.isVisible());
}
}
abstractMapViewer1.repaint();
}
}
}
}
}