/*******************************************************************************
* Copyright (c) MOBAC developers
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package mobac.gui.panels;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import mobac.data.gpx.gpx11.RteType;
import mobac.data.gpx.gpx11.TrkType;
import mobac.data.gpx.gpx11.TrksegType;
import mobac.data.gpx.gpx11.WptType;
import mobac.gui.actions.GpxAddPoint;
import mobac.gui.actions.GpxClear;
import mobac.gui.actions.GpxLoad;
import mobac.gui.actions.GpxNew;
import mobac.gui.actions.GpxSave;
import mobac.gui.components.JCollapsiblePanel;
import mobac.gui.gpxtree.GpxEntry;
import mobac.gui.gpxtree.GpxRootEntry;
import mobac.gui.gpxtree.GpxTreeListener;
import mobac.gui.gpxtree.RteEntry;
import mobac.gui.gpxtree.TrkEntry;
import mobac.gui.gpxtree.TrksegEntry;
import mobac.gui.gpxtree.WptEntry;
import mobac.gui.mapview.PreviewMap;
import mobac.gui.mapview.layer.GpxLayer;
import mobac.utilities.GBC;
import mobac.utilities.I18nUtils;
/**
* Allows to load, display, edit and save gpx files using a tree view. TODO warn unsaved changes on exit
*
*/
public class JGpxPanel extends JCollapsiblePanel {
private static final long serialVersionUID = 1L;
private JTree tree;
private DefaultMutableTreeNode rootNode;
private DefaultTreeModel model;
private ArrayList<String> openedFiles;
private PreviewMap previewMap;
public JGpxPanel(PreviewMap previewMap) {
super("Gpx", new GridBagLayout());
this.previewMap = previewMap;
JButton newGpx = new JButton(I18nUtils.localizedStringForKey("rp_gpx_new_gpx"));
newGpx.addActionListener(new GpxNew(this));
JButton loadGpx = new JButton(I18nUtils.localizedStringForKey("rp_gpx_load_gpx"));
loadGpx.addActionListener(new GpxLoad(this));
JButton saveGpx = new JButton(I18nUtils.localizedStringForKey("rp_gpx_save_gpx"));
saveGpx.addActionListener(new GpxSave(this));
JButton clearGpx = new JButton(I18nUtils.localizedStringForKey("rp_gpx_clear_gpx"));
clearGpx.addActionListener(new GpxClear(this));
JButton addPointGpx = new JButton(I18nUtils.localizedStringForKey("rp_gpx_add_wpt"));
addPointGpx.addActionListener(new GpxAddPoint(this));
rootNode = new DefaultMutableTreeNode(I18nUtils.localizedStringForKey("rp_gpx_default_node_name"));
tree = new JTree(rootNode);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.setRootVisible(false);
tree.setShowsRootHandles(true);
JScrollPane treeView = new JScrollPane(tree);
// treeView.setPreferredSize(new Dimension(100, 300));
model = (DefaultTreeModel) tree.getModel();
tree.addMouseListener(new GpxTreeListener());
openedFiles = new ArrayList<String>();
GBC eol = GBC.eol().fill(GBC.HORIZONTAL);
GBC std = GBC.std().fill(GBC.HORIZONTAL);
addContent(treeView, GBC.eol().fill());
addContent(clearGpx, std);
addContent(addPointGpx, eol);
addContent(newGpx, std);
addContent(loadGpx, std);
addContent(saveGpx, eol);
}
/**
* adds a layer for a new gpx file on the map and adds its structure to the treeview
*
*/
public GpxRootEntry addGpxLayer(GpxLayer layer) {
layer.setPanel(this);
GpxRootEntry gpxEntry = new GpxRootEntry(layer);
DefaultMutableTreeNode gpxNode = new DefaultMutableTreeNode(gpxEntry);
model.insertNodeInto(gpxNode, rootNode, rootNode.getChildCount());
TreePath path = new TreePath(gpxNode.getPath());
tree.scrollPathToVisible(new TreePath(path));
tree.setSelectionPath(path);
addRtes(layer, gpxNode);
addTrks(layer, gpxNode);
addWpts(layer, gpxNode);
if (layer.getFile() != null)
openedFiles.add(layer.getFile().getAbsolutePath());
previewMap.mapLayers.add(layer);
return gpxEntry;
}
/**
* @param layer
* @param gpxNode
* @param model
*/
private void addWpts(GpxLayer layer, DefaultMutableTreeNode gpxNode) {
List<WptType> wpts = layer.getGpx().getWpt();
for (WptType wpt : wpts) {
WptEntry wptEntry = new WptEntry(wpt, layer);
DefaultMutableTreeNode wptNode = new DefaultMutableTreeNode(wptEntry);
model.insertNodeInto(wptNode, gpxNode, gpxNode.getChildCount());
}
}
/**
* @param layer
* @param gpxNode
* @param model
*/
private void addTrks(GpxLayer layer, DefaultMutableTreeNode gpxNode) {
// tracks
List<TrkType> trks = layer.getGpx().getTrk();
for (TrkType trk : trks) {
TrkEntry trkEntry = new TrkEntry(trk, layer);
DefaultMutableTreeNode trkNode = new DefaultMutableTreeNode(trkEntry);
model.insertNodeInto(trkNode, gpxNode, gpxNode.getChildCount());
// trkseg
List<TrksegType> trksegs = trk.getTrkseg();
int counter = 1;
for (TrksegType trkseg : trksegs) {
TrksegEntry trksegEntry = new TrksegEntry(trkseg, counter, layer);
DefaultMutableTreeNode trksegNode = new DefaultMutableTreeNode(trksegEntry);
model.insertNodeInto(trksegNode, trkNode, trkNode.getChildCount());
counter++;
// add trkpts
List<WptType> trkpts = trkseg.getTrkpt();
for (WptType trkpt : trkpts) {
WptEntry trkptEntry = new WptEntry(trkpt, layer);
DefaultMutableTreeNode trkptNode = new DefaultMutableTreeNode(trkptEntry);
model.insertNodeInto(trkptNode, trksegNode, trksegNode.getChildCount());
}
}
}
}
/**
* adds routes and route points to the tree view
*
* @param layer
* @param gpxNode
*/
private void addRtes(GpxLayer layer, DefaultMutableTreeNode gpxNode) {
List<RteType> rtes = layer.getGpx().getRte();
for (RteType rte : rtes) {
RteEntry rteEntry = new RteEntry(rte, layer);
DefaultMutableTreeNode rteNode = new DefaultMutableTreeNode(rteEntry);
model.insertNodeInto(rteNode, gpxNode, gpxNode.getChildCount());
// add rtepts
List<WptType> rtepts = rte.getRtept();
for (WptType rtept : rtepts) {
WptEntry rteptEntry = new WptEntry(rtept, layer);
DefaultMutableTreeNode rteptNode = new DefaultMutableTreeNode(rteptEntry);
model.insertNodeInto(rteptNode, rteNode, rteNode.getChildCount());
}
}
}
/**
* Updates the tree view to show the newly added waypoint.
*
* @param wpt
* - new waypoint
* @param gpxEntry
* - parent entry in the tree
*/
public void addWpt(WptType wpt, GpxEntry gpxEntry) {
WptEntry wptEntry = new WptEntry(wpt, gpxEntry.getLayer());
DefaultMutableTreeNode wptNode = new DefaultMutableTreeNode(wptEntry);
model.insertNodeInto(wptNode, gpxEntry.getNode(), gpxEntry.getNode().getChildCount());
}
/**
* Updates the tree view after removing a waypoint.
*
* @param wpt
* - deleted waypoint
* @param gpxEntry
* - parent entry of the deleted element in the tree
*/
public void removeWpt(WptEntry wptEntry) {
DefaultMutableTreeNode wptNode = wptEntry.getNode();
model.removeNodeFromParent(wptNode);
// update layer (is changing the gpx enough? prolly not
// did remove it already...check wheter its enough
}
public GpxEntry getSelectedEntry() {
TreePath selection = tree.getSelectionPath();
if (selection == null) {
return null;
}
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) selection.getLastPathComponent();
GpxEntry gpxEntry = null;
try {
gpxEntry = (GpxEntry) selectedNode.getUserObject();
gpxEntry.setNode(selectedNode);
} catch (ClassCastException e) {
}
return gpxEntry;
}
public boolean isFileOpen(String path) {
return openedFiles.contains(path);
}
/**
* Resets the tree view. Used by GpxClear.
*
*/
public void resetModel() {
rootNode = new DefaultMutableTreeNode(I18nUtils.localizedStringForKey("rp_gpx_default_node_name"));
model.setRoot(rootNode);
openedFiles = new ArrayList<String>();
}
public DefaultTreeModel getTreeModel() {
return model;
}
}