/** * This file is part of OSM2ShareNav * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * * Copyright (C) 2008 Kai Krueger * */ package net.sharenav.osmToShareNav; import net.sharenav.osmToShareNav.Configuration; import static net.sharenav.osmToShareNav.GetText._; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Desktop; import java.awt.Dialog; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.geom.Area; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.net.URISyntaxException; import java.util.Enumeration; import java.util.LinkedList; import java.util.Vector; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import java.util.regex.Pattern; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JEditorPane; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import javax.swing.filechooser.FileFilter; import org.openstreetmap.gui.jmapviewer.Coordinate; import org.openstreetmap.gui.jmapviewer.JMapViewer; import org.openstreetmap.gui.jmapviewer.MapArea; import org.openstreetmap.gui.jmapviewer.MapMarkerDot; import org.openstreetmap.gui.jmapviewer.MemoryTileCache; import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker; import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle; import net.sharenav.osmToShareNav.model.Bounds; import net.sharenav.osmToShareNav.route.Location; import net.sharenav.osmToShareNav.route.LocationTableModel; import net.sharenav.osmToShareNav.route.Route; public class GuiConfigWizard extends JFrame implements Runnable, ActionListener, SelectionListener { protected class TeeOutputStream extends OutputStream { OutputStream s1; OutputStream s2; protected TeeOutputStream(OutputStream stream1, OutputStream stream2) { s1 = stream1; s2 = stream2; } @Override public void write(byte[] b, int off, int len){ try { s1.write(b,off,len); s2.write(b,off,len); } catch (IOException ioe) { System.err.println("Error in writing to stream: " + ioe.getMessage()); } } @Override public void write(byte [] b) { try{ s1.write(b); s2.write(b); } catch (IOException ioe) { System.err.println("Error in writing to stream: " + ioe.getMessage()); } } /* (non-Javadoc) * @see java.io.OutputStream#write(int) */ /* (non-Javadoc) * @see java.io.OutputStream#write(int) */ @Override public void write(int i) throws IOException { try{ s1.write(i); s2.write(i); } catch (IOException ioe) { System.err.println("Error in writing to stream: " + ioe.getMessage()); } } } protected class StreamGobbler extends OutputStream { JTextArea jta; JScrollPane jsp; protected StreamGobbler(JTextArea jta, JScrollPane jsp) { this.jta = jta; this.jsp = jsp; } @Override public void write(byte[] b, int off, int len) { jta.append(new String(b,off,len)); int max = jsp.getVerticalScrollBar().getMaximum(); jsp.getVerticalScrollBar().setValue(max); } @Override public void write(byte [] b) { jta.append(new String(b)); } /* (non-Javadoc) * @see java.io.OutputStream#write(int) */ @Override public void write(int b) throws IOException { throw new IOException("Not yet Implemented"); } } /** Needed as this class is somehow serializable. */ private static final long serialVersionUID = 1L; private static final String CHOOSE_SRC = "Choose your map data source"; private static final String FILE_SRC = "Load .osm.bz2/.osm.pbf File (recommended)"; private static final String XAPI_SRC = "OsmXapi"; private static final String ROMA_SRC = "ROMA"; private static final String CELL_SRC_NONE = "Include no Cell IDs"; private static final String CELL_SRC_FILE = "Load cell ID file"; private static final String CELL_SRC_DLOAD = "Download cell ID DB"; private static final String SOUND_NONE = "Include no sound files"; private static final String SOUND_AMR = "Include AMR sound files"; private static final String SOUND_WAV = "Include WAV sound files"; private static final String SOUND_WAV_AMR = "Include WAV and AMR files"; private static final String JCB_EDITING = "Enable online OSM editing support"; private static final String JCB_HOUSENUMBERS = "Enable house number support"; private static final String JCB_CELLIDNOLAC = "Store cellids in a format usable by phones with no LAC support"; private static final String JCB_GENERATESEA = "Generate sea from coastlines"; private static final String ORS_URL="http://openrouteservice.org/php/OpenLSRS_DetermineRoute.php"; private String useLang = null; private String useLangName = null; String [] planetFiles = {CHOOSE_SRC, FILE_SRC, XAPI_SRC, ROMA_SRC}; Vector cellidFiles = new Vector(); String [] soundFormats = {SOUND_NONE, SOUND_AMR, SOUND_WAV, SOUND_WAV_AMR}; private static final String LOAD_PROP = "Load .properties file"; private static final String LAST_PROP = "Last used properties"; private static final String CUSTOM_PROP = "Custom properties"; String [] propertiesList = {LOAD_PROP, LAST_PROP, CUSTOM_PROP}; private static final String BUILTIN_STYLE_NORMAL = "Built-in style-file.xml"; private static final String BUILTIN_STYLE_MINI = "Built-in mini-style-file.xml"; private static final String BUILTIN_STYLE_REDUCED = "Built-in reduced-style-file.xml"; private static final String BUILTIN_STYLE_STREET = "Built-in street-style-file.xml"; private static final String LOAD_STYLE = "Load custom style file"; private boolean customSoundfiles = false; private String origUseLang = "*"; /** Preferences stored in a location determined automatically by the runtime */ Preferences prefs; Configuration config; String planet; JComboBox jcbPlanet; JComboBox jcbProperties; JComboBox jcbPhone; JComboBox jcbTileSize; JComboBox jcbStyle; JTextField jtfRouting; JTextField jtfName; JComboBox jcbSoundFormats; JCheckBox jcbEditing; JCheckBox jcbcellIDnoLAC; JCheckBox jcbGenerateSea; JCheckBox jcbHousenumbers; String langList[] = { "*", "en", "cs", "de", "es", "fi", "fr", "it", "pl", "ru", "sk" }; String langNameList[] = { "", "English(5)", "Čeština(5)", "Deutsch(4)", "Spanish(2)", "suomi(4)", "French(1)", "Italian(2)", "Portugese(2)", "Russian(4)", "Slovak(5)" }; JCheckBox languages[] = new JCheckBox[langList.length]; JComboBox jcbCellSource; JButton jbCreate; JButton jbCreateZip; JButton jbClose; JButton jbClearRoute; JButton jbCalcRoute; /** File chooser dialog for OSM file */ JFileChooser jOsmFileChooser; /** File chooser dialog for bundle .properties file */ JFileChooser jPropFileChooser; /** File chooser dialog for style file */ JFileChooser jStyleFileChooser; /** Component handling the map display */ JMapViewer map; Pattern startPattern=Pattern.compile("<gml:LineString"); Pattern posPattern=Pattern.compile("<gml:pos>([0-9.]+) ([0-9.]+)</gml:pos>"); Vector<Coordinate> routeResult=new Vector<Coordinate>(); boolean dialogFinished = false; private JTable destList; public GuiConfigWizard() { //this.config = c; // Load preferences, the package name of this class is relevant for // finding them again. The runtime chooses an appropriate location for // them, usually in the user's directory. prefs = Preferences.userNodeForPackage(this.getClass()); } public Configuration startWizard(String[] args) { System.out.println("Starting configuration wizard"); config = new Configuration(args); setupWizard(); return config; } public void setupWizard() { GridBagLayout gbl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); this.setTitle("Osm2ShareNav V" + Configuration.getConfiguration().getVersion() + " (" + Configuration.getConfiguration().getBundleDate() + ")"); this.setLayout(gbl); // Default constructor uses the DefaultMapController, so we need to use // the specialized constructor. map = new JMapViewer(new MemoryTileCache(), 4); SelectionMapController mapController = new SelectionMapController(map, this); map.setSize(600, 400); gbc.gridwidth = 8; gbc.weighty = 1; gbc.fill = GridBagConstraints.BOTH; gbc.gridx = 0; gbc.gridy = 0; add(map, gbc); JPanel jpRouteCorridor = new JPanel(new GridBagLayout()); gbc.gridx = 8; gbc.gridy = 0; gbc.gridwidth = 1; gbc.weighty = 0; add(jpRouteCorridor, gbc); JLabel jlSeparator1 = new JLabel(" "); gbc.gridwidth = 1; gbc.weightx = 0; gbc.weighty = 0; gbc.fill = GridBagConstraints.CENTER; gbc.gridx = 0; gbc.gridy = 0; jpRouteCorridor.add(jlSeparator1, gbc); JLabel jlRouteCorridor = new JLabel("Optional Route Corridor Destinations"); gbc.gridwidth = 1; gbc.weightx = 0; gbc.weighty = 0; gbc.fill = GridBagConstraints.CENTER; gbc.gridx = 0; gbc.gridy = 1; jpRouteCorridor.add(jlRouteCorridor, gbc); destList=new JTable(new LocationTableModel(config.getRouteList())); destList.setToolTipText("Add route corridor destinations with Alt+Click or Shift+Click on the map"); gbc.gridwidth = 1; gbc.weightx = 1; gbc.weighty = 1; gbc.fill = GridBagConstraints.BOTH; gbc.gridx = 0; gbc.gridy = 2; jpRouteCorridor.add(destList, gbc); jbClearRoute = new JButton("Clear Route Corridor"); jbClearRoute.setActionCommand("ClearRoute-click"); jbClearRoute.addActionListener(this); gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = 1; gbc.weighty = 0; gbc.gridx = 0; gbc.gridy = 3; jpRouteCorridor.add(jbClearRoute, gbc); jbCalcRoute = new JButton("Calculate Route Corridor"); jbCalcRoute.setActionCommand("CalculateRoute-click"); jbCalcRoute.addActionListener(this); gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = 1; gbc.weighty = 0; gbc.gridx = 0; gbc.gridy = 4; jpRouteCorridor.add(jbCalcRoute, gbc); JPanel langOptions = new JPanel(new GridBagLayout()); gbc.gridwidth = 1; gbc.weightx = 0; gbc.weighty = 0; gbc.fill = GridBagConstraints.CENTER; gbc.gridx = 0; gbc.gridy = 5; jpRouteCorridor.add(langOptions, gbc); JLabel langLabel = new JLabel("Lang:"); gbc.gridx = 0; gbc.gridy = 0; gbc.weighty = 0; langOptions.add(langLabel, gbc); for (int i = 0; i < langList.length ; i++) { languages[i] = new JCheckBox(langList[i]); languages[i].addActionListener(this); // enable * and English by default gbc.gridx = i+1; gbc.gridy = 0; gbc.weighty = 0; langOptions.add(languages[i], gbc); if (i == 0 || i == 1) { languages[i].setSelected(true); } } JPanel jpFiles = new JPanel(new GridBagLayout()); gbc.gridx = 0; gbc.gridy = 1; gbc.gridwidth = 3; gbc.weighty = 0; add(jpFiles, gbc); JLabel jlPlanet = new JLabel(_("Openstreetmap data source: ")); gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 1; gbc.weighty = 0; jpFiles.add(jlPlanet, gbc); jcbPlanet = new JComboBox(planetFiles); jcbPlanet.setSelectedItem(CHOOSE_SRC); jcbPlanet.addActionListener(this); jcbPlanet.setToolTipText("Select the .osm file to use in conversion. ROMA and OsmXapi are online servers and should only be used for small areas."); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1; gbc.gridx = 1; gbc.gridy = 0; jpFiles.add(jcbPlanet, gbc); if (!CHOOSE_SRC.equals((String)jcbPlanet.getSelectedItem())) { config.setPlanetName((String)jcbPlanet.getSelectedItem()); } JLabel jlStyle = new JLabel("Style file: "); gbc.gridx = 0; gbc.gridy = 2; gbc.weighty = 0; jpFiles.add(jlStyle, gbc); jcbStyle = new JComboBox(); jcbStyle.addItem(BUILTIN_STYLE_NORMAL); jcbStyle.addItem(BUILTIN_STYLE_MINI); jcbStyle.addItem(BUILTIN_STYLE_REDUCED); jcbStyle.addItem(BUILTIN_STYLE_STREET); jcbStyle.addItem(LOAD_STYLE); jcbStyle.addActionListener(this); jcbStyle.setToolTipText("Select the style file to determine which features of the raw data get included in the map/bundle"); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1; gbc.gridx = 1; gbc.gridy = 2; jpFiles.add(jcbStyle, gbc); JLabel jlProps = new JLabel("Properties template: "); gbc.gridx = 0; gbc.gridy = 1; gbc.weighty = 0; jpFiles.add(jlProps, gbc); Vector<String> propertiesName = enumerateBuiltinProperties(); propertiesName.add(0, LOAD_PROP); propertiesName.add(0, LAST_PROP); propertiesName.add(0, CUSTOM_PROP); jcbProperties = new JComboBox(propertiesName.toArray()); jcbProperties.addActionListener(this); jcbProperties.setToolTipText("Select a predefined configuration file"); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.gridx = 1; gbc.gridy = 1; gbc.gridwidth = 1; jpFiles.add(jcbProperties, gbc); JPanel jpOptions = new JPanel(new GridBagLayout()); gbc.gridx = 3; gbc.gridy = 1; gbc.gridwidth = 3; gbc.weighty = 0; add(jpOptions, gbc); JLabel jlRouting = new JLabel("Routing modes:"); gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 1; jpOptions.add(jlRouting, gbc); jtfRouting = new JTextField(); jtfRouting.setText("motorcar, bicycle"); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.gridx = 1; gbc.gridy = 0; gbc.gridwidth = 1; jpOptions.add(jtfRouting, gbc); JLabel jlName = new JLabel("Bundle/map name:"); gbc.gridx = 0; gbc.gridy = 1; gbc.weighty = 0; jpOptions.add(jlName, gbc); jtfName = new JTextField(); gbc.gridx = 1; gbc.gridy = 1; gbc.weighty = 0; jpOptions.add(jtfName, gbc); JLabel jlPhone = new JLabel("Phone capabilities template: "); gbc.gridx = 0; gbc.gridy = 2; gbc.weighty = 0; jpOptions.add(jlPhone, gbc); jcbPhone = new JComboBox(enumerateAppParam().toArray()); jcbPhone.setToolTipText("Select the compilation version that contains the features supported by your phone. Generic-full-connected with net services access or Generic-full without it should work well in most cases."); jcbPhone.addActionListener(this); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.gridx = 1; gbc.gridy = 2; gbc.gridwidth = 1; jpOptions.add(jcbPhone, gbc); JLabel jlTileSize = new JLabel("Map tile file count vs. size: "); gbc.gridx = 0; gbc.gridy = 3; gbc.weighty = 0; jpOptions.add(jlTileSize, gbc); Vector vTileSize = new Vector(); vTileSize.addElement("Many small map tile files"); vTileSize.addElement("Average map tile file size and count"); vTileSize.addElement("Fewer but big map tile files"); vTileSize.addElement("Even fewer and large map tile files"); vTileSize.addElement("Custom - loaded from .properties"); jcbTileSize = new JComboBox(vTileSize); jcbTileSize.setToolTipText("Some devices do not support many files in the jar, other require small map tile files to be able to load them into their limited RAM"); jcbTileSize.addActionListener(this); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.gridx = 1; gbc.gridy = 3; gbc.gridwidth = 1; jpOptions.add(jcbTileSize, gbc); JPanel jpOptions2 = new JPanel(new GridBagLayout()); gbc.gridx = 6; gbc.gridy = 1; gbc.gridwidth = 3; gbc.weighty = 0; add(jpOptions2, gbc); jcbEditing = new JCheckBox(JCB_EDITING); jcbEditing.addActionListener(this); gbc.gridx = 0; gbc.gridy = 0; gbc.weighty = 0; jpOptions2.add(jcbEditing, gbc); jcbHousenumbers = new JCheckBox(JCB_HOUSENUMBERS); jcbHousenumbers.addActionListener(this); gbc.gridx = 0; gbc.gridy = 1; gbc.weighty = 0; jpOptions2.add(jcbHousenumbers, gbc); jcbcellIDnoLAC = new JCheckBox(JCB_CELLIDNOLAC); jcbcellIDnoLAC.addActionListener(this); gbc.gridx = 0; gbc.gridy = 2; gbc.weighty = 0; jpOptions2.add(jcbcellIDnoLAC, gbc); jcbGenerateSea = new JCheckBox(JCB_GENERATESEA); jcbGenerateSea.addActionListener(this); gbc.gridx = 0; gbc.gridy = 3; gbc.weighty = 0; jpOptions2.add(jcbGenerateSea, gbc); jcbSoundFormats = new JComboBox(soundFormats); jcbSoundFormats.setSelectedIndex(1); jcbSoundFormats.addActionListener(this); jcbSoundFormats.setToolTipText("Select sound formats to include into the map/bundle, e.g. most Windows Mobile devices support .wav but cannot replay .amr. ShareNav will use the first successful playing sound format included"); gbc.gridx = 0; gbc.gridy = 1; gbc.weighty = 0; jpOptions2.add(jcbSoundFormats, gbc); cellidFiles.addElement(CELL_SRC_NONE); cellidFiles.addElement(CELL_SRC_FILE); cellidFiles.addElement(CELL_SRC_DLOAD); jcbCellSource = new JComboBox(cellidFiles); if (!config.getString("cellSource").equals("")) { cellidFiles.addElement(config.getString("cellSource")); jcbCellSource.setSelectedIndex(3); } jcbCellSource.addActionListener(this); jcbCellSource.setToolTipText("Select a source of the Cell ID db for cell based location."); gbc.gridx = 0; gbc.gridy = 3; gbc.weighty = 0; jpOptions2.add(jcbCellSource, gbc); jbCreate = new JButton("Create ShareNav bundle"); jbCreate.setActionCommand("Create-bundle"); jbCreate.addActionListener(this); gbc.gridwidth = 2; gbc.weighty = 0; gbc.fill = GridBagConstraints.BOTH; gbc.gridx = 0; gbc.gridy = 4; add(jbCreate, gbc); jbCreateZip = new JButton("Create ShareNav map zip"); jbCreateZip.setActionCommand("Create-map"); jbCreateZip.addActionListener(this); gbc.gridwidth = 2; gbc.weighty = 0; gbc.fill = GridBagConstraints.BOTH; gbc.gridx = 2; gbc.gridy = 4; add(jbCreateZip, gbc); jbClose = new JButton("Close"); jbClose.setActionCommand("Close-click"); jbClose.addActionListener(this); gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = 2; gbc.weighty = 0; gbc.gridx = 4; gbc.gridy = 4; add(jbClose, gbc); JButton jbHelp = new JButton("Help"); jbHelp.setActionCommand("Help-click"); jbHelp.addActionListener(this); gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = 3; gbc.weighty = 0; gbc.gridx = 6; gbc.gridy = 4; add(jbHelp, gbc); pack(); setVisible(true); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { exitApplication(); } }); updatePropertiesSelectors(); Thread t = new Thread(this); t.start(); try { t.join(); } catch (InterruptedException e) { // Nothing to do } jbClose.setEnabled(false); jbCreate.setEnabled(false); jbCreateZip.setEnabled(false); jcbPlanet.setEnabled(false); jcbProperties.setEnabled(false); jcbStyle.setEnabled(false); jtfRouting.setEnabled(false); jtfName.setEnabled(false); jcbPhone.setEnabled(false); jcbTileSize.setEnabled(false); jcbSoundFormats.setEnabled(false); jcbCellSource.setEnabled(false); jcbEditing.setEnabled(false); jcbHousenumbers.setEnabled(false); jcbcellIDnoLAC.setEnabled(false); jcbGenerateSea.setEnabled(false); destList.setVisible(false); jbCalcRoute.setEnabled(false); jbClearRoute.setEnabled(false); JTextArea jtaConsoleOut = new JTextArea(); jtaConsoleOut.setAutoscrolls(true); JScrollPane jspConsoleOut = new JScrollPane(jtaConsoleOut); jspConsoleOut.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEtchedBorder(), "Console Output:")); jspConsoleOut.setMinimumSize(new Dimension(400, 300)); gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = 9; gbc.weighty = 9; gbc.gridx = 0; gbc.gridy = 5; gbc.gridheight=1; add(jspConsoleOut, gbc); JTextArea jtaConsoleErr = new JTextArea(); jtaConsoleErr.setAutoscrolls(true); JScrollPane jspConsoleErr = new JScrollPane(jtaConsoleErr); jspConsoleErr.setBorder(BorderFactory.createTitledBorder("Errors:")); jspConsoleErr.setMinimumSize(new Dimension(400, 200)); gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = 9; gbc.weighty = 3; gbc.gridx = 0; gbc.gridy = 6; add(jspConsoleErr, gbc); remove(map); this.validate(); System.setOut(new PrintStream(new TeeOutputStream(System.out,new StreamGobbler(jtaConsoleOut, jspConsoleOut)))); System.setErr(new PrintStream(new TeeOutputStream(System.err, new StreamGobbler(jtaConsoleErr, jspConsoleErr)))); } /** All actions that result in an exit of the application *must* call this * method to allow proper saving of data. */ private void exitApplication() { updateSettings(true); writeProperties("last.properties"); // Update persistent settings for next program run if (jOsmFileChooser != null) { File file = jOsmFileChooser.getSelectedFile(); if (file != null) { String parent = file.getParent(); if (parent != null) { prefs.put("planet-file.lastDirectory", parent); } } } try { prefs.flush(); } catch (BackingStoreException bse) { JOptionPane.showMessageDialog(this, "Failed to save preferences, error is: " + bse.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); bse.printStackTrace(); } System.exit(0); } /** Takes the bounds from the config object and puts them on the map. */ private void addMapMarkers() { LinkedList<MapRectangle> rects = new LinkedList<MapRectangle>(); Vector<Bounds> bounds = config.getBounds(); for (Bounds b : bounds) { Coordinate boundTopLeft = new Coordinate(b.maxLat, b.maxLon); Coordinate boundBottomRight = new Coordinate(b.minLat, b.minLon); MapArea boundMarker = new MapArea(Color.BLACK, new Color(0x2fffff70, true), boundTopLeft, boundBottomRight); rects.add(boundMarker); } map.setMapRectangleList(rects); } /** Takes the route destinations from the config object and puts them on the map. */ private void addRouteDestMarkers() { LinkedList<MapMarker> mapMarkers = new LinkedList<MapMarker>(); Vector<Location> locations = config.getRouteList(); for (Location lc : locations) { MapMarkerDot d = new MapMarkerDot(lc.getNode().lat, lc.getNode().lon); mapMarkers.add(d); } map.setMapMarkerList(mapMarkers); } /** Updates the GUI elements from the settings currently found in config. * This is usually needed after reading a bundle file. */ private void updatePropertiesSelectors() { String styleFile = config.getStyleFileName(); String mapSource = config.getPlanetName(); if (mapSource != null && !mapSource.equals("")) { planet = mapSource; jcbPlanet.addItem(mapSource); jcbPlanet.setSelectedItem(mapSource); } if (styleFile != null) { System.out.println("Updating GUI elements\n Style: " + styleFile); //jcbStyle.removeItem(styleFile); boolean isAlreadyIn = false; for (int i = 0; i < jcbStyle.getItemCount(); i++) { if (((String)jcbStyle.getItemAt(i)).equalsIgnoreCase(styleFile)) { isAlreadyIn = true; } } if (!isAlreadyIn) { jcbStyle.addItem(styleFile); } // Avoid trigger of another setStyleFile() through handleComboBoxChanged() jcbStyle.removeActionListener(this); jcbStyle.setSelectedItem(styleFile); jcbStyle.addActionListener(this); } System.out.println(" useRouting: " + config.useRouting); jtfRouting.setText(config.useRouting); System.out.println(" app: " + config.getString("app")); jcbPhone.removeActionListener(this); String appName = config.getString("app"); if (appName.startsWith("ShareNav-")) { appName = appName.substring(appName.indexOf("-")+1); } jcbPhone.setSelectedItem(appName); jcbPhone.addActionListener(this); jcbTileSize.removeActionListener(this); jcbTileSize.setSelectedIndex(config.getTileSizeVsCountId()); jcbTileSize.addActionListener(this); System.out.println(" cellSource: " + config.getString("cellSource")); if (!config.getString("cellSource").equals("")) { jcbCellSource.removeActionListener(this); cellidFiles.addElement(config.getString("cellSource")); jcbCellSource.setSelectedIndex(3); jcbCellSource.addActionListener(this); } System.out.println(" bundle.name: " + config.getBundleOrMidletString()); jtfName.setText(config.getBundleOrMidletString()); guiSettingsFromConfig(); jcbEditing.setSelected(config.enableEditingSupport); jcbHousenumbers.setSelected(config.useHouseNumbers); jcbcellIDnoLAC.setSelected(config.getCellIDnoLAC()); jcbGenerateSea.setSelected(config.getGenerateSea()); } /** Finds all files in the Osm2ShareNav JAR that match the pattern "ShareNav-*.jar" or "ShareNav-*.apk" * and puts their names in a vector, cutting off at the last "-". * E.g. ShareNav-Generic-full-0.6.4-map65.jar -> ShareNav-Generic-full * * @return Vector containing the names */ private Vector<String> enumerateAppParam() { Vector<String> res = new Vector<String>(); try { File jarFileName = new File(this.getClass().getProtectionDomain() .getCodeSource().getLocation().toURI()); JarFile jarFile = new JarFile(jarFileName); Enumeration<JarEntry> jes = jarFile.entries(); while (jes.hasMoreElements()) { String entryName = jes.nextElement().getName(); if ((entryName.startsWith("ShareNav-")) && (entryName.endsWith(".jar") || entryName.endsWith(".apk"))) { if (!res.contains(entryName.substring(0, entryName.lastIndexOf("-", entryName.lastIndexOf("-")-1)))) { entryName = entryName.substring(entryName.indexOf("-")+1); res.add(entryName.substring(0, entryName.lastIndexOf("-", entryName.lastIndexOf("-")-1))); } } } } catch (URISyntaxException e1) { e1.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return res; } /** Finds all files in the Osm2ShareNav JAR that match the pattern "*.properties" * and puts their names in a vector, without the ".properties". * E.g. Cologne.properties -> Cologne * * @return Vector containing the names */ private Vector<String> enumerateBuiltinProperties() { Vector<String> res = new Vector<String>(); try { File jarFileName = new File(this.getClass().getProtectionDomain() .getCodeSource().getLocation().toURI()); JarFile jarFile = new JarFile(jarFileName); Enumeration<JarEntry> jes = jarFile.entries(); while (jes.hasMoreElements()) { String entryName = jes.nextElement().getName(); if (entryName.endsWith(".properties") && !entryName.endsWith("version.properties")) { res.add(entryName.substring(0, entryName.length() - 11)); } } } catch (URISyntaxException e1) { e1.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return res; } /** Opens a file chooser dialog for the OSM XML (.osm or .bz2 or .gz) file. * Updates the config when the file was chosen. */ private boolean askOsmFile() { if (jOsmFileChooser == null) { // Use the previously chosen directory if available, else use the user directory. String chosenDir = prefs.get("planet-file.lastDirectory", System.getProperty("user.dir")); jOsmFileChooser = new JFileChooser(chosenDir); FileFilter ff = new FileFilter() { @Override public boolean accept(File f) { if (f.isDirectory() || f.getAbsolutePath().endsWith(".osm") || f.getAbsolutePath().endsWith(".osm.bz2") || f.getAbsolutePath().endsWith(".osm.pbf") || f.getAbsolutePath().endsWith(".osm.gz")) { return true; } return false; } @Override public String getDescription() { return "Openstreetmap file (*.osm.pbf, *.osm.bz2, *.osm)"; } }; jOsmFileChooser.setFileFilter(ff); } int returnVal = jOsmFileChooser.showOpenDialog(null); if (returnVal == JFileChooser.APPROVE_OPTION) { // Update configuration planet = jOsmFileChooser.getSelectedFile().getAbsolutePath(); if (!planet.equalsIgnoreCase(CHOOSE_SRC)) { config.setPlanetName(planet); // Add as entry to the drop down list jcbPlanet.addItem(planet); jcbPlanet.setSelectedItem(planet); } return true; } else { return false; } } /** Opens a file chooser dialog for the style file. * Lets the config read the file when it was chosen. */ private void askStyleFile() { if (jStyleFileChooser == null) { jStyleFileChooser = new JFileChooser(System.getProperty("user.dir")); FileFilter ff = new FileFilter() { @Override public boolean accept(File f) { if (f.isDirectory() || f.getAbsolutePath().endsWith(".xml")) { return true; } return false; } @Override public String getDescription() { return "style file"; } }; jStyleFileChooser.setFileFilter(ff); } int returnVal = jStyleFileChooser.showOpenDialog(null); if (returnVal == JFileChooser.APPROVE_OPTION) { try { String styleName = jStyleFileChooser.getSelectedFile().getAbsolutePath(); config.setStyleFileName(styleName); jcbStyle.addItem(styleName); jcbStyle.setSelectedItem(styleName); } catch (IOException ioe) { JOptionPane.showMessageDialog(this, ioe.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); ioe.printStackTrace(); } } } /** Sets GUI settings from the loaded .properties file. */ private void guiSettingsFromConfig() { // Set desired languages String propLang[] = config.getUseLang().split("[;,]", 200); for (int i = 2; i < languages.length ; i++) { languages[i].setSelected(false); for (int j = 0; j < propLang.length ; j++) { //System.out.println ("Comparing strings: " + propLang[j] + " " + langList[i]); if (propLang[j].equals(langList[i])) { languages[i].setSelected(true); } if (propLang[j].equals("*")) { languages[0].setSelected(true); } } } origUseLang = getSelectedUseLang(); } /** Opens a file chooser dialog for the bundle .properties file. * Lets the config read the file when it was chosen. */ private void askPropFile() { if (jPropFileChooser == null) { jPropFileChooser = new JFileChooser(System.getProperty("user.dir")); FileFilter ff = new FileFilter() { @Override public boolean accept(File f) { if (f.isDirectory() || f.getAbsolutePath().endsWith(".properties")) { return true; } return false; } @Override public String getDescription() { return ".properties files"; } }; jPropFileChooser.setFileFilter(ff); } int returnVal = jPropFileChooser.showOpenDialog(null); if (returnVal == JFileChooser.APPROVE_OPTION) { String propName = jPropFileChooser.getSelectedFile().getAbsolutePath(); try { System.out.println("Loading properties specified by GUI: " + propName); config.loadPropFile(new FileInputStream(propName)); addRouteDestMarkers(); destList.repaint(); } catch (IOException ioe) { JOptionPane.showMessageDialog(this, "Failed to load properties file. Error is: " + ioe.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); ioe.printStackTrace(); } } } /** Opens a file chooser dialog for the file containing the CellID data. * Updates config when file was chosen. */ private void askCellFile() { JFileChooser chooser = new JFileChooser(System.getProperty("user.dir")); FileFilter ff = new FileFilter() { @Override public boolean accept(File f) { if (f.isDirectory() || f.getAbsolutePath().endsWith(".txt.gz")) { return true; } return false; } @Override public String getDescription() { return ".txt.gz files"; } }; chooser.setFileFilter(ff); int returnVal = chooser.showOpenDialog(null); if (returnVal == JFileChooser.APPROVE_OPTION) { String cellSource = chooser.getSelectedFile().getAbsolutePath(); System.out.println("Setting CellID source: " + cellSource); config.setCellSource(cellSource); } } /* * Simply do nothing while the dialog is still open. This is used to * block on the dialog i.e. to prevent the Bundle creation process * from starting immediately. */ public void run() { while (dialogFinished == false) { synchronized (this) { try { this.wait(1000); } catch (InterruptedException e) { // Nothing to do } } } } /** * Writes the current properties to a .properties file * TODO: Shouldn't useCellID be written too? * TODO: Add useHouseNumbers and useWordSearch * And what about the cellSource variable from Configuration.java? * @param fileName Path name of file to write */ private void writeProperties(String fileName) { File file = new File(fileName); try { FileWriter fw = new FileWriter(file); fw.write("# Properties file generated by the Osm2ShareNav Wizard\r\n"); fw.write("\r\n"); fw.write("# Name of the bundle on the phone\r\n"); fw.write("bundle.name = " + config.getBundleName() + "\r\n"); fw.write("\r\n"); if (config.getPlanetName() != null && !"".equals(config.getPlanetName()) && !CHOOSE_SRC.equals(config.getPlanetName())) { // quote possible backslashes fw.write("mapSource = " + config.getPlanetName().replace("\\", "\\\\") + "\r\n"); } fw.write("# To choose a different device specific build, use the app property.\r\n"); fw.write("# ShareNav-Generic-full-connected (for net-connected use)"); fw.write("# or ShareNav-Generic-full (for non-net-connected use) should work for most phones (except BlackBerry).\r\n"); String app = config.getAppParam(); fw.write("app = " + app + "\r\n"); Vector<String>apps = enumerateAppParam(); // write out available app parameters except for the selected one for (String a: apps) { a = "ShareNav-" + a; if (! a.equals(app)) { fw.write("#app = " + a + "\r\n"); } } fw.write("\r\n"); fw.write("# Style-file containing which way, area and POI types to include in the Bundle.\r\n"); fw.write("# This will default to style-file.xml, set style-file=min-style-file.xml for a smaller version with less features in the map.\r\n"); fw.write("# If there is no internal version in Osm2ShareNav for the png / sound files, you must provide external versions\r\n"); fw.write("# in the current directory or sub-directories 'sound' and 'png' inside Osm2ShareNav.jar (when using internal style-file)\r\n"); fw.write("# or sub-directories 'sound' and 'png' in the same directory as the external style-file.\r\n"); fw.write("style-file = " + config.getStyleFileName().replace("\\", "\\\\") + "\r\n"); fw.write("\r\n"); fw.write("# You can have up to 9 regions.\r\n"); fw.write("# Ways and POIs in any of the regions will be written to the bundle.\r\n"); Vector<Bounds> bounds = config.getBounds(); if (bounds != null) { int i = 1; for (Bounds b : bounds) { fw.write(b.toPropertyString(i++)); } } fw.write("\r\n"); fw.write("# Route corridor destinations\r\n"); fw.write("# Coordinates of route destinations which are used to calculate the route corridor.\r\n"); fw.write("# Osm2ShareNav " + config.getVersion() + " supports this only with Osm2ShareNav Wizard.\r\n"); if (config.getRouteList() != null) { int i = 1; for (Location lc : config.getRouteList()) { fw.write(lc.toPropertyString(i++)); } } fw.write("\r\n"); fw.write("# Triangle area format (needed for J2ME).\r\n"); fw.write("triangleAreaFormat = " + config.getTriangleAreaFormat() + "\r\n"); fw.write("\r\n"); fw.write("# Outline area format (good for Android).\r\n"); fw.write("outlineAreaFormat = " + config.getOutlineAreaFormat() + "\r\n"); fw.write("\r\n"); fw.write("# Routing ability can be disabled to save space in the map/bundle by setting to false.\r\n"); fw.write("# Or set to one or more defined in the style-file, e.g. motorcar, bicycle, foot.\r\n"); fw.write("useRouting = " + config.useRouting + "\r\n"); fw.write("\r\n"); fw.write("# Honor barriers when building routing information.\r\n"); fw.write("useBarriers = " + config.useBarriers + "\r\n"); fw.write("\r\n"); fw.write("# Build word indexes.\r\n"); fw.write("useWordSearch = " + config.getUseWordSearch() + "\r\n"); fw.write("\r\n"); fw.write("# Housenumber support.\r\n"); fw.write("useHouseNumbers = " + config.useHouseNumbers + "\r\n"); fw.write("\r\n"); fw.write("# Editing support.\r\n"); fw.write("enableEditing = " + config.enableEditingSupport + "\r\n"); fw.write("\r\n"); fw.write("# Generate sea from coastlines.\r\n"); fw.write("generateSea = " + config.getGenerateSea() + "\r\n"); fw.write("\r\n"); fw.write("# Use sea tiles (experimentally speeds up sea generation).\r\n"); fw.write("useSeaTiles = " + config.getUseSeaTiles() + "\r\n"); fw.write("\r\n"); fw.write("# Sound formats to be included in the map/bundle, default is useSounds=amr.\r\n"); fw.write("# Osm2ShareNav includes from all sound files wav, amr and mp3 variants.\r\n"); fw.write("# Wav is the most compatible, loudest but also the most size intensive format.\r\n"); fw.write("# Example to include wav AND amr: useSounds=wav, amr\r\n"); fw.write("# ShareNav will try a fallback to another included sound format when trying to play a format unsupported by the device.\r\n"); fw.write("useSounds = " + config.getUseSounds() + "\r\n"); fw.write("\r\n"); if (useLang != null) { fw.write("# Languages to be included in the map/bundle\r\n"); fw.write("lang = " + useLang + "\r\n"); fw.write("\r\n"); } if (useLangName != null) { fw.write("# Language names to be included in the map/bundle\r\n"); fw.write("langName = " + useLangName + "\r\n"); fw.write("\r\n"); } fw.write("# Directory/Directories with sound files and syntax.cfg, default is useSoundFilesWithSyntax=sound\r\n"); fw.write("# syntax.cfg is a text file defining which sound files\r\n"); fw.write("# are played by ShareNav for the various routing instructions in which order (to respect grammar)\r\n"); fw.write("# Osm2ShareNav includes all sound files referenced in the syntax.cfg either from an internal folder\r\n"); fw.write("# or the directory with the specified name relative to the style-file.\r\n"); fw.write("# File Format examples are at:\r\n"); fw.write("# English: http://sharenav.git.sourceforge.net/git/gitweb.cgi?p=sharenav/ShareNav;a=blob;f=Osm2ShareNav/resources/media/sound/syntax.cfg\r\n"); fw.write("# German: http://sharenav.git.sourceforge.net/git/gitweb.cgi?p=sharenav/ShareNav;a=blob;f=Osm2ShareNav/resources/media/sound-de/syntax.cfg\r\n"); fw.write("# Currently the following sound-files with syntax are internal to Osm2ShareNav:\r\n"); fw.write("# English: sound German: sound-de Finnish: sound-fi\r\n"); fw.write("# Example to include the Finnish and German sound files: useSoundFilesWithSyntax=sound-de, sound-fi\r\n"); fw.write("# Generally there's no need to set this if you just want to use the standard sound files with the windowed Osm2ShareNav\r\n"); fw.write("# - it's set automatically for you from selected languages\r\n"); // comment out if we didn't read a custom soundfile setting, created automatically // from selected language(s) if (! customSoundfiles || !getSelectedUseLang().equals(origUseLang)) { fw.write("# "); } fw.write("useSoundFilesWithSyntax = " + config.getSoundFiles() + "\r\n"); fw.write("\r\n"); fw.write("# Sign created apk after creating.\r\n"); fw.write("signApk = " + config.getSignApk() + "\r\n"); fw.write("\r\n"); if (config.getSignApk()) { fw.write("# Command or path to jarsigner. Default is jarsigner\r\n"); fw.write("# e.g. jarsignerPath = jarsigner on GNU/Linux\r\n"); fw.write("# or maybe something like jarsignerPath = /usr/lib/jvm/default-java/bin/jarsigner\r\n"); fw.write("# or jarsignerPath = %ProgramFiles%\\\\Java\\\\jdk1.6.0_24\\\\bin\\\\jarsigner.exe on Windows\r\n"); fw.write("# Could be also jarsignerPath = %ProgramFiles(x86)%\\\\Java\\\\jdk1.6.0_24\\\\jdk1.6.0_24\\\\bin\\\\jarsigner.exe on Windows\r\n"); fw.write("# or could have e.g. jdk1.6.0_24, jdk1.6.0_26, jdk1.6.0_29, jdk1.6.0_31, jdk1.6.0_33 or jdk1.7.0_05 instead of jdk1.6.0_24\r\n"); fw.write("# Quoting: If you have a path containing '\\', you must write it as '\\\\'\r\n"); if (!"".equals(config.getJarsignerPath())) { // quote possible backslashes fw.write("jarsignerPath = " + config.getJarsignerPath().replace("\\", "\\\\") + "\r\n"); } fw.write("\r\n"); fw.write("# Password for jarsigner for signing the apk.\r\n"); fw.write("# signApkPassword = " + "[ put your password here ]" + "\r\n"); fw.write("\r\n"); } fw.write("# Add this line to .manifest / .jad.\r\n"); fw.write("# e.g. MIDlet-Touch-Support:true to hide keyboard on Samsung Bada mobiles\r\n"); fw.write("# or LGE-MIDlet-Display-Nav-Keypad:no on LG mobiles\r\n"); fw.write("addToManifest = " + config.getAddToManifest() + "\r\n"); fw.write("\r\n"); fw.write("# File endings of files to not compress.\r\n"); fw.write("# e.g. for Android and WinCE uncompressed WAV files are required\r\n"); fw.write("# Example to not compress files ending with wav: dontCompress = wav\r\n"); fw.write("dontCompress = " + config.getDontCompress() + "\r\n"); fw.write("\r\n"); fw.write("# == Advanced parameters for configuring number of files in the map/bundle ===\r\n"); fw.write("# With less files more memory will be required on the device to run ShareNav.\r\n"); fw.write("# Larger dictionary depth will reduce the number of dictionary files in ShareNav.\r\n"); fw.write("maxDictDepth = " + config.getMaxDictDepth() + "\r\n"); fw.write("# Larger tile size will reduce the number of tile files in the map/bundle.\r\n"); fw.write("# Maximum route tile size in bytes\r\n"); fw.write("routing.maxTileSize = " + config.getMaxRouteTileSize() + "\r\n"); fw.write("# Maximum tile size in bytes\r\n"); fw.write("maxTileSize = " + config.getMaxTileSize() + "\r\n"); fw.write("# Maximum ways contained in tiles for level 0-3\r\n"); for (int i=0;i < 4; i++) { fw.write("maxTileWays" + i + " = " + config.getMaxTileWays(i) + "\r\n"); } fw.write("\r\n"); fw.write("# Whether to include icons for icon menu and their size to include.\r\n"); fw.write("# Possible values: false|small|true|big|large|huge, true is the default medium size\r\n"); fw.write("useIcons = " + config.getUseIcons() + "\r\n"); fw.write("\r\n"); if (!"".equals(config.getCellSource())) { // quote possible backslashes fw.write("cellSource = " + config.getCellSource().replace("\\", "\\\\") + "\r\n"); fw.write("useCellID = " + config.getString("useCellID") + "\r\n"); } fw.write("# Store cellids for phones without LAC.\r\n"); fw.write("cellIDnoLAC = " + config.getCellIDnoLAC() + "\r\n"); fw.write("\r\n"); fw.close(); } catch (IOException ioe) { } } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ public void actionPerformed(ActionEvent event) { if ("Create-bundle".equalsIgnoreCase(event.getActionCommand())) { handleCreateClicked(true); } else if ("Create-map".equalsIgnoreCase(event.getActionCommand())) { handleCreateClicked(false); } else if ("Close-click".equalsIgnoreCase(event.getActionCommand())) { exitApplication(); } else if ("Help-click".equalsIgnoreCase(event.getActionCommand())) { handleHelpClicked(); } else if ("enable Routing".equalsIgnoreCase(event.getActionCommand())) { // TODO: expose different vehicles for routing in GuiConfigWizard instead of always assuming motorcar if ( ((JCheckBox)event.getSource()).isSelected() ) { config.setRouting("motorcar"); } } else if ("ClearRoute-click".equalsIgnoreCase(event.getActionCommand())) { config.getRouteList().clear(); map.setMapMarkerList(new LinkedList<MapMarker>()); destList.repaint(); } else if (JCB_HOUSENUMBERS.equalsIgnoreCase(event.getActionCommand())) { config.useHouseNumbers = ((JCheckBox)event.getSource()).isSelected(); } else if (JCB_CELLIDNOLAC.equalsIgnoreCase(event.getActionCommand())) { config.setCellIDnoLAC(((JCheckBox)event.getSource()).isSelected()); } else if (JCB_GENERATESEA.equalsIgnoreCase(event.getActionCommand())) { config.setGenerateSea(((JCheckBox)event.getSource()).isSelected()); } else if ("CalculateRoute-click".equalsIgnoreCase(event.getActionCommand())) { handleCalculateRoute(); } else if (JCB_EDITING.equalsIgnoreCase(event.getActionCommand())) { config.enableEditingSupport = ((JCheckBox)event.getSource()).isSelected(); if (config.enableEditingSupport && !((String)jcbPhone.getSelectedItem()).contains("Editing")) { //TODO: Need to find a way to select item without refering to hardcoded string names jcbPhone.setSelectedItem("Generic-full-connected"); JOptionPane.showMessageDialog(this, "Editing requires online (connected) support. Changed Phone capabilities setting accordingly"); } } else if ("comboBoxChanged".equalsIgnoreCase(event.getActionCommand())) { handleComboBoxChanged(event); } } /** * */ private void handleCalculateRoute() { if (config.getRouteList().size() > 1) { Route route = new Route(config.getRouteList(), 10000,map); Area a=route.createArea(); config.setArea(a); } else { JOptionPane.showMessageDialog(this, "Please add first at least two route destinations with Alt+Click or Shift+Click on the map" , "Route Corridor Calculation", JOptionPane.ERROR_MESSAGE); } } private String getSelectedUseLang() { String langString = ""; for (int i = 2; i < langList.length ; i++) { if (languages[i].isSelected()) { //System.out.println("Lang selected: " + langList[i]); langString += "," + langList[i]; } } return langString; } private void updateSettings(boolean bundle) { String soundFiles = "sound"; useLang = langList[1]; useLangName = langNameList[1]; for (int i = 2; i < langList.length ; i++) { if (languages[i].isSelected()) { //System.out.println("Lang selected: " + langList[i]); useLang += "," + langList[i]; useLangName += "," + langNameList[i]; // existence of sound dir will be checked later soundFiles += ",sound-" + langList[i]; } } // preserve custom sounds if (config.getSoundFiles().equals("sound") || (!getSelectedUseLang().equals(origUseLang))) { customSoundfiles = false; config.setSoundFiles(soundFiles); } else { customSoundfiles = true; soundFiles = config.getSoundFiles(); } config.setUseLang(useLang); config.setUseLangName(useLangName); // "*" is last if (languages[0].isSelected()) { config.setAllLang(true); useLang += ",*"; } if (languages[0].isSelected()) { config.setAllLang(true); useLangName += ",*"; } config.setBundleName(jtfName.getText()); config.setRouting(jtfRouting.getText()); config.setCodeBase( "ShareNav-" + (String)jcbPhone.getSelectedItem()); config.mapzip = !bundle; } /** Handles the case that the button "Create Bundle" was clicked. */ private void handleCreateClicked(boolean bundle) { if (((String)jcbPlanet.getSelectedItem()).equalsIgnoreCase(CHOOSE_SRC)) { if (askOsmFile() == false) { JOptionPane.showMessageDialog(this, "Osm2ShareNav can't create a map without suitable OpenStreetMap data.\n" + "Please choose an appropriate OpenStreetMap data source. See help for more details.", "OpenStreetMap data", JOptionPane.PLAIN_MESSAGE); return; } } updateSettings(bundle); System.out.println("Create Bundle clicked"); dialogFinished = true; writeProperties("last.properties"); } /** Handles the case that the button "Help" was clicked. */ private void handleHelpClicked() { final JEditorPane jepHelpMsg = new JEditorPane(); final JScrollPane scrPane = new JScrollPane(); jepHelpMsg.setPreferredSize(new Dimension(4000,4000)); jepHelpMsg.setEditable(false); jepHelpMsg.setContentType("text/html"); scrPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); scrPane.getViewport().add(jepHelpMsg); jepHelpMsg.setText( "<html><body>" + "<h1>Welcome to the Osm2ShareNav Wizard!</h1>" + "Osm2ShareNav and ShareNav are licensed under <a href =\"http://www.gnu.org/licenses/old-licenses/gpl-2.0.html\">GPLv2</a><br>" + "OpenStreetMap Data is licensed under <a href =\"http://creativecommons.org/licenses/by-sa/2.0/\">CC-BY-SA</a><br>" + "<br>" + "Osm2ShareNav is a conversion program to package map data from <a href=\"http://www.openstreetmap.org\">OpenStreetMap</a> into a map, or a 'bundle' called ShareNav.\n" + "The resulting map or bundle includes the specified map data (and program if it's a bundle), can be uploaded to a mobile device for offline navigation.\n" + "<br><br>" + "Usage:<br><ol>" + "<li> Specify which region of the world you want to include in your map or bundle. \n" + " This can be done in different ways. \n" + "<ol><li>by dragging over an area on the world map with the right mouse button\n</li>" + "<li>by specifying a .properties file that already contains the area you want.\n</li>" + "<li>by defining a route corridor with shift+click or alt+click (equivalent) on at least\n" + "two places on the map, and after that clicking on \"Calculate Route Corridor\"\n</li></ol>" + " You can delete boxes by double-clicking on them.\n" + " If you want to set all the parameters using this wizard, please leave 'Properties template' on 'Custom'.\n" + "<li> Specify a source for the OpenStreetMap data. Currently three sources are directly supported:\n" + "<ul>" + " <li> ROMA: This is the Read Only Map Api and downloads data directly from the API server (only for small regions like towns)</li>" + " <li> OsmXapi: This is an alternative server and very similar to ROMA (only for small regions like towns)</li>" + " <li> Load from file: Use a .osm or .osm.bz2 file previously downloaded to your computer (recommended)\n" + " Country level extracts in .osm.bz2 file format are available\n" + " i.e. at <a href=\"http://download.geofabrik.de/osm/\">GeoFabrik</a> and <a href=\"http://downloads.cloudmade.com/\">CloudMade</a></li>" + "</ul>" + "<li> Select languages for which to include on-screen translation and navigation instructions (when available).\n" + "The language selection \"*\" includes all available languages for on-screen use, to be selected with\n" + "language code or as device's default language\n" + "<li> Press 'Create ShareNav bundle' or 'Create ShareNav map zip'\n" + "</ol><br>" + "Your changes in the wizard are written to last.properties so you can use this as\n" + "a starting point for your .properties file.<br>" + "<br>" + "For more information please visit our <a href=\"http://sharenav.sourceforge.net/\">Homepage</a> and <a href=\"http://sharenav.sourceforge.net/\">Wiki</a>"+ "</body></html>"); jepHelpMsg.addHierarchyListener(new HierarchyListener() { public void hierarchyChanged(HierarchyEvent e) { Window window = SwingUtilities.getWindowAncestor(jepHelpMsg); if (window instanceof Dialog) { Dialog dialog = (Dialog)window; if (!dialog.isResizable()) { dialog.setResizable(true); } dialog.setSize(800, 650); } } }); jepHelpMsg.addHyperlinkListener(new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { if (Desktop.isDesktopSupported()) { try { Desktop.getDesktop().browse(e.getURL().toURI()); } catch (Exception ex) { //Nothing to do if we can't open a browser } } } } }); JOptionPane.showMessageDialog(this, scrPane, "Help", JOptionPane.PLAIN_MESSAGE); } /** Handles change events for the combo boxes * @param event ActionEvent describing the change */ private void handleComboBoxChanged(ActionEvent event) { if (event.getSource() == jcbProperties) { String chosenProperty = (String) jcbProperties.getSelectedItem(); if (chosenProperty.equalsIgnoreCase(LOAD_PROP)) { askPropFile(); } else if (chosenProperty.equalsIgnoreCase(LAST_PROP)) { // Entries added by askPropFile() have a full path name try { System.out.println("Loading properties from last.properties"); config.loadPropFile(new FileInputStream("last.properties")); addRouteDestMarkers(); destList.repaint(); } catch (IOException ioe) { JOptionPane.showMessageDialog(this, "Failed to load properties file. Error is: " + ioe.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); ioe.printStackTrace(); } } else if (chosenProperty.equalsIgnoreCase(CUSTOM_PROP)) { config.resetConfig(); } else if (chosenProperty.contains("/") || chosenProperty.contains("\\")) { // Entries added by askPropFile() have a full path name try { System.out.println("Loading properties specified by GUI: " + chosenProperty); config.loadPropFile(new FileInputStream(chosenProperty)); addRouteDestMarkers(); destList.repaint(); } catch (IOException ioe) { JOptionPane.showMessageDialog(this, "Failed to load properties file. Error is: " + ioe.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); ioe.printStackTrace(); } } else { // These are entries added with enumerateBuiltinProperties() try { System.out.println("Loading built in properties '" + chosenProperty + "'"); InputStream is = getClass().getResourceAsStream("/" + chosenProperty + ".properties"); if (is == null) { throw new IOException("Properties file could not be opened."); } config.loadPropFile(is); addRouteDestMarkers(); destList.repaint(); } catch (IOException ioe) { JOptionPane.showMessageDialog(this, "Failed to load built in properties. Error is: " + ioe.getMessage() + " Please report this bug.", "Error", JOptionPane.ERROR_MESSAGE); ioe.printStackTrace(); return; } } addMapMarkers(); map.setDisplayToFitMapRectangle(); updatePropertiesSelectors(); } if (event.getSource() == jcbPlanet) { String chosenProperty = (String) jcbPlanet.getSelectedItem(); if (chosenProperty.equalsIgnoreCase(FILE_SRC)) { if (!askOsmFile()) { jcbPlanet.setSelectedItem(CHOOSE_SRC); } } else { config.setPlanetName(chosenProperty); } } if (event.getSource() == jcbStyle) { try { String chosenProperty = (String) jcbStyle.getSelectedItem(); if (chosenProperty.equalsIgnoreCase(LOAD_STYLE)) { askStyleFile(); } else if (chosenProperty.equalsIgnoreCase(BUILTIN_STYLE_NORMAL)) { config.setStyleFileName("/style-file.xml"); } else if (chosenProperty.equalsIgnoreCase(BUILTIN_STYLE_MINI)) { config.setStyleFileName("/mini-style-file.xml"); } else if (chosenProperty.equalsIgnoreCase(BUILTIN_STYLE_REDUCED)) { config.setStyleFileName("/reduced-style-file.xml"); } else if (chosenProperty.equalsIgnoreCase(BUILTIN_STYLE_STREET)) { config.setStyleFileName("/street-style-file.xml"); } else { config.setStyleFileName(chosenProperty); } } catch (IOException ioe) { JOptionPane.showMessageDialog(this, ioe.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); ioe.printStackTrace(); } } if (event.getSource() == jcbPhone) { config.setCodeBase("ShareNav-" + (String)jcbPhone.getSelectedItem()); } if (event.getSource() == jcbTileSize) { config.setTileSizeVsCountId(jcbTileSize.getSelectedIndex()); } if (event.getSource() == jcbCellSource) { String chosenProperty = (String) jcbCellSource.getSelectedItem(); if (CELL_SRC_NONE.equalsIgnoreCase(chosenProperty)) { config.setCellOperator("false"); } else if (CELL_SRC_DLOAD.equalsIgnoreCase(chosenProperty)) { config.setCellOperator("true"); config.setCellSource("http://dump.opencellid.org/cellsIdData/cells.txt.gz"); } else if (CELL_SRC_FILE.equalsIgnoreCase(chosenProperty)) { config.setCellOperator("true"); askCellFile(); } else if (!chosenProperty.equals("")) { config.setCellOperator("true"); } } if (event.getSource() == jcbSoundFormats) { String chosenProperty = (String) jcbSoundFormats.getSelectedItem(); if (SOUND_NONE.equalsIgnoreCase(chosenProperty)) { config.setSounds("false"); } else if (SOUND_AMR.equalsIgnoreCase(chosenProperty)) { config.setSounds("amr"); } else if (SOUND_WAV.equalsIgnoreCase(chosenProperty)) { config.setSounds("wav"); } else if (SOUND_WAV_AMR.equalsIgnoreCase(chosenProperty)) { config.setSounds("wav, amr"); } } } /* (non-Javadoc) * @see net.sharenav.osmToShareNav.SelectionListener#regionMarked(net.sharenav.osmToShareNav.model.Bounds) */ public void regionMarked(Bounds bound) { System.out.println("Region marked: " + bound.toString()); if (config.getBounds().size() < Configuration.MAX_BOUND_BOXES) { config.addBounds(bound); addMapMarkers(); } else { JOptionPane.showMessageDialog(this, "You cannot create more than " + Configuration.MAX_BOUND_BOXES + " bounding boxes."); } } /* (non-Javadoc) * @see net.sharenav.osmToShareNav.SelectionListener#pointDoubleClicked(float, float) */ public void pointDoubleClicked(float lat, float lon) { System.out.println("Double click at lat=" + lat + "|lon=" + lon); Vector<Bounds> bounds = config.getBounds(); for (int i = 0; i < bounds.size(); i++) { if (bounds.elementAt(i).isIn(lat, lon)) { System.out.println(" Deleting box " + i + " " + bounds.elementAt(i).toString()); config.removeBoundsAt(i); addMapMarkers(); break; } } } /** Used to reenable the "Close" button from BundleShareNav (after bundle creation). */ public void reenableClose() { jbClose.setEnabled(true); } /* (non-Javadoc) * @see net.sharenav.osmToShareNav.SelectionListener#addRouteDestination(org.openstreetmap.gui.jmapviewer.Coordinate) */ @Override public void addRouteDestination(Coordinate clickPoint) { Location location = new Location((float)clickPoint.getLat(),(float)clickPoint.getLon()); config.addRouteDestination(location); destList.repaint(); } }