X-Git-Url: http://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fsave%2FKmlExporter.java;h=7f90dbc8cca16e897ee70072aabc1e88c8f82b10;hb=f35b6d628f68e3b5ef19965ad8988d0dd1eb8efa;hp=11474a6c8e8fb37f911f53f3f79e51edebc5fcf4;hpb=5625a1abadb5f2ca5f017fe7dbda1d5141cb637b;p=GpsPrune.git diff --git a/tim/prune/save/KmlExporter.java b/tim/prune/save/KmlExporter.java index 11474a6..7f90dbc 100644 --- a/tim/prune/save/KmlExporter.java +++ b/tim/prune/save/KmlExporter.java @@ -1,11 +1,14 @@ package tim.prune.save; import java.awt.BorderLayout; +import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; @@ -25,76 +28,101 @@ import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JFileChooser; -import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JTextField; import javax.swing.SwingConstants; -import javax.swing.filechooser.FileFilter; +import tim.prune.App; +import tim.prune.GenericFunction; import tim.prune.I18nManager; +import tim.prune.UpdateMessageBroker; +import tim.prune.config.ColourUtils; +import tim.prune.config.Config; +import tim.prune.data.Altitude; import tim.prune.data.Coordinate; import tim.prune.data.DataPoint; +import tim.prune.data.Field; import tim.prune.data.Track; import tim.prune.data.TrackInfo; +import tim.prune.gui.ColourChooser; +import tim.prune.gui.ColourPatch; +import tim.prune.gui.DialogCloser; import tim.prune.gui.ImageUtils; +import tim.prune.load.GenericFileFilter; /** * Class to export track information - * into a specified Kml file + * into a specified Kml or Kmz file */ -public class KmlExporter implements Runnable +public class KmlExporter extends GenericFunction implements Runnable { - private JFrame _parentFrame = null; private TrackInfo _trackInfo = null; private Track _track = null; private JDialog _dialog = null; private JTextField _descriptionField = null; + private PointTypeSelector _pointTypeSelector = null; + private JCheckBox _altitudesCheckbox = null; private JCheckBox _kmzCheckbox = null; private JCheckBox _exportImagesCheckbox = null; + private ColourPatch _colourPatch = null; + private JLabel _progressLabel = null; private JProgressBar _progressBar = null; + private Dimension[] _imageDimensions = null; private JFileChooser _fileChooser = null; private File _exportFile = null; + private JButton _okButton = null; + private boolean _cancelPressed = false; + private ColourChooser _colourChooser = null; // Filename of Kml file within zip archive private static final String KML_FILENAME_IN_KMZ = "doc.kml"; - // Width and height of thumbnail images in Kmz - private static final int THUMBNAIL_WIDTH = 240; - private static final int THUMBNAIL_HEIGHT = 180; + // Default width and height of thumbnail images in Kmz + private static final int DEFAULT_THUMBNAIL_WIDTH = 240; + private static final int DEFAULT_THUMBNAIL_HEIGHT = 240; + // Default track colour + private static final Color DEFAULT_TRACK_COLOUR = new Color(204, 0, 0); // red /** - * Constructor giving frame and track - * @param inParentFrame parent frame - * @param inTrackInfo track info object to save + * Constructor + * @param inApp app object */ - public KmlExporter(JFrame inParentFrame, TrackInfo inTrackInfo) + public KmlExporter(App inApp) { - _parentFrame = inParentFrame; - _trackInfo = inTrackInfo; - _track = inTrackInfo.getTrack(); + super(inApp); + _trackInfo = inApp.getTrackInfo(); + _track = _trackInfo.getTrack(); } + /** Get name key */ + public String getNameKey() { + return "function.exportkml"; + } /** * Show the dialog to select options and export file */ - public void showDialog() + public void begin() { // Make dialog window including whether to compress to kmz (and include pictures) or not if (_dialog == null) { - _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.exportkml.title"), true); + _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true); _dialog.setLocationRelativeTo(_parentFrame); _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); _dialog.getContentPane().add(makeDialogComponents()); _dialog.pack(); + _colourChooser = new ColourChooser(_dialog); } enableCheckboxes(); + _descriptionField.setEnabled(true); + _okButton.setEnabled(true); + _progressLabel.setText(""); _progressBar.setVisible(false); - _dialog.show(); + _dialog.setVisible(true); } @@ -105,7 +133,7 @@ public class KmlExporter implements Runnable private Component makeDialogComponents() { JPanel dialogPanel = new JPanel(); - dialogPanel.setLayout(new BorderLayout()); + dialogPanel.setLayout(new BorderLayout(0, 5)); JPanel mainPanel = new JPanel(); mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); // Make a central panel with the text box and checkboxes @@ -113,12 +141,41 @@ public class KmlExporter implements Runnable descPanel.setLayout(new FlowLayout()); descPanel.add(new JLabel(I18nManager.getText("dialog.exportkml.text"))); _descriptionField = new JTextField(20); + _descriptionField.addKeyListener(new DialogCloser(_dialog)); descPanel.add(_descriptionField); + descPanel.setAlignmentX(Component.CENTER_ALIGNMENT); mainPanel.add(descPanel); dialogPanel.add(mainPanel, BorderLayout.CENTER); + // point type selection + _pointTypeSelector = new PointTypeSelector(); + _pointTypeSelector.setAlignmentX(Component.CENTER_ALIGNMENT); + mainPanel.add(_pointTypeSelector); + // Colour definition + Color trackColour = ColourUtils.colourFromHex(Config.getConfigString(Config.KEY_KML_TRACK_COLOUR)); + if (trackColour == null) { + trackColour = DEFAULT_TRACK_COLOUR; + } + _colourPatch = new ColourPatch(trackColour); + _colourPatch.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + _colourChooser.showDialog(_colourPatch.getBackground()); + Color colour = _colourChooser.getChosenColour(); + if (colour != null) _colourPatch.setColour(colour); + } + }); + JPanel colourPanel = new JPanel(); + colourPanel.add(new JLabel(I18nManager.getText("dialog.exportkml.trackcolour"))); + colourPanel.add(_colourPatch); + mainPanel.add(colourPanel); + // Checkbox for altitude export + _altitudesCheckbox = new JCheckBox(I18nManager.getText("dialog.exportkml.altitude")); + _altitudesCheckbox.setHorizontalTextPosition(SwingConstants.LEFT); + _altitudesCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT); + mainPanel.add(_altitudesCheckbox); // Checkboxes for kmz export and image export _kmzCheckbox = new JCheckBox(I18nManager.getText("dialog.exportkml.kmz")); _kmzCheckbox.setHorizontalTextPosition(SwingConstants.LEFT); + _kmzCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT); _kmzCheckbox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -129,29 +186,35 @@ public class KmlExporter implements Runnable mainPanel.add(_kmzCheckbox); _exportImagesCheckbox = new JCheckBox(I18nManager.getText("dialog.exportkml.exportimages")); _exportImagesCheckbox.setHorizontalTextPosition(SwingConstants.LEFT); + _exportImagesCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT); mainPanel.add(_exportImagesCheckbox); mainPanel.add(Box.createVerticalStrut(10)); + _progressLabel = new JLabel("..."); + _progressLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + mainPanel.add(_progressLabel); _progressBar = new JProgressBar(0, 100); _progressBar.setVisible(false); + _progressBar.setAlignmentX(Component.CENTER_ALIGNMENT); mainPanel.add(_progressBar); mainPanel.add(Box.createVerticalStrut(10)); // button panel at bottom JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); - JButton okButton = new JButton(I18nManager.getText("button.ok")); + _okButton = new JButton(I18nManager.getText("button.ok")); ActionListener okListener = new ActionListener() { public void actionPerformed(ActionEvent e) { startExport(); } }; - okButton.addActionListener(okListener); + _okButton.addActionListener(okListener); _descriptionField.addActionListener(okListener); - buttonPanel.add(okButton); + buttonPanel.add(_okButton); JButton cancelButton = new JButton(I18nManager.getText("button.cancel")); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { + _cancelPressed = true; _dialog.dispose(); } }); @@ -166,6 +229,9 @@ public class KmlExporter implements Runnable */ private void enableCheckboxes() { + _pointTypeSelector.init(_trackInfo); + boolean hasAltitudes = _track.hasData(Field.ALTITUDE); + if (!hasAltitudes) {_altitudesCheckbox.setSelected(false);} boolean hasPhotos = _trackInfo.getPhotoList() != null && _trackInfo.getPhotoList().getNumPhotos() > 0; _exportImagesCheckbox.setSelected(hasPhotos && _kmzCheckbox.isSelected()); _exportImagesCheckbox.setEnabled(hasPhotos && _kmzCheckbox.isSelected()); @@ -177,28 +243,27 @@ public class KmlExporter implements Runnable */ private void startExport() { - // OK pressed, so choose output file + // OK pressed, now validate selection checkboxes + if (!_pointTypeSelector.getAnythingSelected()) { + JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.notypesselected"), + I18nManager.getText("dialog.saveoptions.title"), JOptionPane.WARNING_MESSAGE); + return; + } + // Choose output file if (_fileChooser == null) - {_fileChooser = new JFileChooser();} - _fileChooser.setDialogType(JFileChooser.SAVE_DIALOG); - _fileChooser.setFileFilter(new FileFilter() { - public boolean accept(File f) - { - return (f != null && (f.isDirectory() - || f.getName().toLowerCase().endsWith(".kml") || f.getName().toLowerCase().endsWith(".kmz"))); - } - public String getDescription() - { - return I18nManager.getText("dialog.exportkml.filetype"); - } - }); - String requiredExtension = null, otherExtension = null; - if (_kmzCheckbox.isSelected()) { + _fileChooser = new JFileChooser(); + _fileChooser.setDialogType(JFileChooser.SAVE_DIALOG); + _fileChooser.setFileFilter(new GenericFileFilter("filetype.kmlkmz", new String[] {"kml", "kmz"})); + // start from directory in config which should be set + String configDir = Config.getConfigString(Config.KEY_TRACK_DIR); + if (configDir != null) {_fileChooser.setCurrentDirectory(new File(configDir));} + } + String requiredExtension = null, otherExtension = null; + if (_kmzCheckbox.isSelected()) { requiredExtension = ".kmz"; otherExtension = ".kml"; } - else - { + else { requiredExtension = ".kml"; otherExtension = ".kmz"; } _fileChooser.setAcceptAllFileFilterUsed(false); @@ -230,6 +295,7 @@ public class KmlExporter implements Runnable { // New file or overwrite confirmed, so initiate export in separate thread _exportFile = file; + _cancelPressed = false; new Thread(this).start(); } else @@ -246,12 +312,25 @@ public class KmlExporter implements Runnable */ public void run() { - // Initialise progress bar + // Disable ok button to stop second go + _okButton.setEnabled(false); + _descriptionField.setEnabled(false); + // Initialise progress indicators + _progressLabel.setText(I18nManager.getText("confirm.running")); _progressBar.setVisible(true); _progressBar.setValue(0); boolean exportToKmz = _kmzCheckbox.isSelected(); boolean exportImages = exportToKmz && _exportImagesCheckbox.isSelected(); _progressBar.setMaximum(exportImages?getNumPhotosToExport():1); + + // Determine photo thumbnail size from config + int thumbWidth = Config.getConfigInt(Config.KEY_KMZ_IMAGE_WIDTH); + if (thumbWidth < DEFAULT_THUMBNAIL_WIDTH) {thumbWidth = DEFAULT_THUMBNAIL_WIDTH;} + int thumbHeight = Config.getConfigInt(Config.KEY_KMZ_IMAGE_HEIGHT); + if (thumbHeight < DEFAULT_THUMBNAIL_HEIGHT) {thumbHeight = DEFAULT_THUMBNAIL_HEIGHT;} + // Create array for image dimensions in case it's required + _imageDimensions = new Dimension[_track.getNumPoints()]; + OutputStreamWriter writer = null; ZipOutputStream zipOutputStream = null; try @@ -266,13 +345,22 @@ public class KmlExporter implements Runnable { // kmz requested - need zip output stream zipOutputStream = new ZipOutputStream(new FileOutputStream(_exportFile)); + // Export images into zip file too if requested + if (exportImages) + { + // Create thumbnails of each photo in turn and add to zip as images/image.jpg + // This is done first so that photo sizes are known for later + exportThumbnails(zipOutputStream, thumbWidth, thumbHeight); + } writer = new OutputStreamWriter(zipOutputStream); // Make an entry in the zip file for the kml file ZipEntry kmlEntry = new ZipEntry(KML_FILENAME_IN_KMZ); zipOutputStream.putNextEntry(kmlEntry); } // write file - int numPoints = exportData(writer, exportImages); + final int numPoints = exportData(writer, exportImages); + // update config with selected track colour + Config.setConfigString(Config.KEY_KML_TRACK_COLOUR, ColourUtils.makeHexCode(_colourPatch.getBackground())); // update progress bar _progressBar.setValue(1); @@ -283,27 +371,23 @@ public class KmlExporter implements Runnable writer.flush(); // Close off this entry in the zip file zipOutputStream.closeEntry(); - // Export images into zip file too if requested - if (exportImages) - { - // Create thumbnails of each photo in turn and add to zip as images/image.jpg - exportThumbnails(zipOutputStream); - } } // close file writer.close(); - JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.ok1") - + " " + numPoints + " " + I18nManager.getText("dialog.save.ok2") - + " " + _exportFile.getAbsolutePath(), - I18nManager.getText("dialog.save.oktitle"), JOptionPane.INFORMATION_MESSAGE); + _imageDimensions = null; + // Store directory in config for later + Config.setConfigString(Config.KEY_TRACK_DIR, _exportFile.getParentFile().getAbsolutePath()); + // show confirmation + UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1") + + " " + numPoints + " " + I18nManager.getText("confirm.save.ok2") + + " " + _exportFile.getAbsolutePath()); // export successful so need to close dialog and return _dialog.dispose(); return; } catch (IOException ioe) { - // System.out.println("Exception: " + ioe.getClass().getName() + " - " + ioe.getMessage()); try { if (writer != null) writer.close(); } @@ -326,36 +410,58 @@ public class KmlExporter implements Runnable private int exportData(OutputStreamWriter inWriter, boolean inExportImages) throws IOException { - // TODO: Look at segments of track, and split into separate lines in Kml if necessary + boolean writeTrack = _pointTypeSelector.getTrackpointsSelected(); + boolean writeWaypoints = _pointTypeSelector.getWaypointsSelected(); + boolean writePhotos = _pointTypeSelector.getPhotopointsSelected(); + boolean writeAudios = _pointTypeSelector.getAudiopointsSelected(); + boolean justSelection = _pointTypeSelector.getJustSelection(); inWriter.write("\n\n\n"); inWriter.write("\t"); if (_descriptionField != null && _descriptionField.getText() != null && !_descriptionField.getText().equals("")) { inWriter.write(_descriptionField.getText()); } - else - { + else { inWriter.write("Export from Prune"); } inWriter.write("\n"); + // Examine selection if required + int selStart = -1, selEnd = -1; + if (justSelection) { + selStart = _trackInfo.getSelection().getStart(); + selEnd = _trackInfo.getSelection().getEnd(); + } + + boolean absoluteAltitudes = _altitudesCheckbox.isSelected(); int i = 0; DataPoint point = null; boolean hasTrackpoints = false; - // Loop over waypoints - boolean writtenPhotoHeader = false; - int numPoints = _track.getNumPoints(); + boolean writtenPhotoHeader = false, writtenAudioHeader = false; + final int numPoints = _track.getNumPoints(); + int numSaved = 0; int photoNum = 0; + // Loop over waypoints for (i=0; i=selStart && i<=selEnd); // Make a blob for each waypoint if (point.isWaypoint()) { - exportWaypoint(point, inWriter); + if (writeWaypoints && writeCurrentPoint) + { + exportWaypoint(point, inWriter, absoluteAltitudes); + numSaved++; + } + } + else if (!point.hasMedia()) + { + hasTrackpoints = true; } // Make a blob with description for each photo - if (point.getPhoto() != null) + // Photos have already been written so picture sizes already known + if (point.getPhoto() != null && writePhotos && writeCurrentPoint) { if (!writtenPhotoHeader) { @@ -363,51 +469,105 @@ public class KmlExporter implements Runnable writtenPhotoHeader = true; } photoNum++; - exportPhotoPoint(point, inWriter, inExportImages, photoNum); + exportPhotoPoint(point, inWriter, inExportImages, i, photoNum, absoluteAltitudes); + numSaved++; } - else + // Make a blob with description for each audio file + if (point.getAudio() != null && writeAudios && writeCurrentPoint) { - hasTrackpoints = true; + if (!writtenAudioHeader) + { + inWriter.write(""); + writtenAudioHeader = true; + } + exportAudioPoint(point, inWriter, absoluteAltitudes); + numSaved++; } } // Make a line for the track, if there is one - if (hasTrackpoints) + if (hasTrackpoints && writeTrack) { - inWriter.write("\t\n\t\ttrack\n\t\t\n\t\t\n\t\t\t"); + // Set up strings for start and end of track segment + String trackStart = "\t\n\t\ttrack\n\t\t\n\t\t\n"; + if (absoluteAltitudes) { + trackStart += "\t\t\t1\n\t\t\tabsolute\n"; + } + else { + trackStart += "\t\t\tclampToGround\n"; + } + trackStart += "\t\t\t"; + String trackEnd = "\t\t\t\n\t\t\n\t"; + + // Start segment + inWriter.write(trackStart); // Loop over track points + boolean firstTrackpoint = true; for (i=0; i=selStart && i<=selEnd); + if (!point.isWaypoint() && writeCurrentPoint) { - exportTrackpoint(point, inWriter); + // start new track segment if necessary + if (point.getSegmentStart() && !firstTrackpoint) { + inWriter.write(trackEnd); + inWriter.write(trackStart); + } + if (point.getPhoto() == null) + { + exportTrackpoint(point, inWriter); + numSaved++; + firstTrackpoint = false; + } } } - inWriter.write("\t\t\t\n\t\t\n\t"); + // end segment + inWriter.write(trackEnd); } inWriter.write("\n"); - return numPoints; + return numSaved; } + /** + * Reverse the hex code for the colours for KML's stupid backwards format + * @param inCode colour code rrggbb + * @return kml code bbggrr + */ + private static String reverse(String inCode) + { + return inCode.substring(4, 6) + inCode.substring(2, 4) + inCode.substring(0, 2); + } /** * Export the specified waypoint into the file * @param inPoint waypoint to export * @param inWriter writer object + * @param inAbsoluteAltitude true for absolute altitude * @throws IOException on write failure */ - private void exportWaypoint(DataPoint inPoint, Writer inWriter) throws IOException + private void exportWaypoint(DataPoint inPoint, Writer inWriter, boolean inAbsoluteAltitude) throws IOException { - inWriter.write("\t\n\t\t"); - inWriter.write(inPoint.getWaypointName().trim()); - inWriter.write("\n"); - inWriter.write("\t\t\n\t\t\t"); - inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL)); - inWriter.write(','); - inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL)); - inWriter.write(",0\n\t\t\n\t\n"); + String name = inPoint.getWaypointName().trim(); + exportNamedPoint(inPoint, inWriter, name, null, null, inAbsoluteAltitude); + } + + + /** + * Export the specified audio point into the file + * @param inPoint audio point to export + * @param inWriter writer object + * @param inAbsoluteAltitude true for absolute altitude + * @throws IOException on write failure + */ + private void exportAudioPoint(DataPoint inPoint, Writer inWriter, boolean inAbsoluteAltitude) throws IOException + { + String name = inPoint.getAudio().getFile().getName(); + String desc = inPoint.getAudio().getFile().getAbsolutePath(); + exportNamedPoint(inPoint, inWriter, name, desc, "audio_icon", inAbsoluteAltitude); } @@ -416,31 +576,80 @@ public class KmlExporter implements Runnable * @param inPoint data point including photo * @param inWriter writer object * @param inImageLink flag to set whether to export image links or not + * @param inPointNumber number of point for accessing dimensions * @param inImageNumber number of image for filename + * @param inAbsoluteAltitude true for absolute altitudes * @throws IOException on write failure */ - private void exportPhotoPoint(DataPoint inPoint, Writer inWriter, boolean inImageLink, int inImageNumber) + private void exportPhotoPoint(DataPoint inPoint, Writer inWriter, boolean inImageLink, + int inPointNumber, int inImageNumber, boolean inAbsoluteAltitude) + throws IOException + { + String name = inPoint.getPhoto().getFile().getName(); + String desc = null; + if (inImageLink) + { + Dimension imageSize = _imageDimensions[inPointNumber]; + // Create html for the thumbnail images + desc = "" + + "
" + inPoint.getPhoto().getFile().getName() + "
]]>"; + } + // Export point + exportNamedPoint(inPoint, inWriter, name, desc, "camera_icon", inAbsoluteAltitude); + } + + + /** + * Export the specified named point into the file, like waypoint or photo point + * @param inPoint data point + * @param inWriter writer object + * @param inName name of point + * @param inDesc description of point, or null + * @param inStyle style of point, or null + * @param inAbsoluteAltitude true for absolute altitudes + * @throws IOException on write failure + */ + private void exportNamedPoint(DataPoint inPoint, Writer inWriter, String inName, + String inDesc, String inStyle, boolean inAbsoluteAltitude) throws IOException { inWriter.write("\t\n\t\t"); - inWriter.write(inPoint.getPhoto().getFile().getName()); + inWriter.write(inName); inWriter.write("\n"); - if (inImageLink) + if (inDesc != null) + { + // Write out description + inWriter.write(""); + inWriter.write(inDesc); + inWriter.write(""); + } + if (inStyle != null) { - // Work out image dimensions of thumbnail - Dimension picSize = inPoint.getPhoto().getSize(); - Dimension thumbSize = ImageUtils.getThumbnailSize(picSize.width, picSize.height, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT); - // Write out some html for the thumbnail images - inWriter.write("" - + "
Caption for the photo
]]>
"); + inWriter.write("#"); + inWriter.write(inStyle); + inWriter.write("\n"); + } + inWriter.write("\t\t\n"); + if (inAbsoluteAltitude && inPoint.hasAltitude()) { + inWriter.write("\t\t\tabsolute\n"); + } + else { + inWriter.write("\t\t\tclampToGround\n"); } - inWriter.write("#camera_icon\n"); - inWriter.write("\t\t\n\t\t\t"); - inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL)); + inWriter.write("\t\t\t"); + inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT)); inWriter.write(','); - inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL)); - inWriter.write(",0\n\t\t\n\t
\n"); + inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT)); + inWriter.write(','); + // Altitude if point has one + if (inPoint.hasAltitude()) { + inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.Format.METRES)); + } + else { + inWriter.write('0'); + } + inWriter.write("\n\t\t\n\t\n"); } @@ -451,36 +660,54 @@ public class KmlExporter implements Runnable */ private void exportTrackpoint(DataPoint inPoint, Writer inWriter) throws IOException { - inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL)); + inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT)); inWriter.write(','); - inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL)); - // Altitude not exported, locked to ground by Google Earth - inWriter.write(",0\n"); + inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT)); + // Altitude if point has one + inWriter.write(','); + if (inPoint.hasAltitude()) { + inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.Format.METRES)); + } + else { + inWriter.write('0'); + } + inWriter.write('\n'); } /** * Loop through the photos and create thumbnails * @param inZipStream zip stream to save image files to + * @param inThumbWidth thumbnail width + * @param inThumbHeight thumbnail height */ - private void exportThumbnails(ZipOutputStream inZipStream) throws IOException + private void exportThumbnails(ZipOutputStream inZipStream, int inThumbWidth, int inThumbHeight) + throws IOException { // set up image writer - Iterator writers = ImageIO.getImageWritersByFormatName("jpg"); + Iterator writers = ImageIO.getImageWritersByFormatName("jpg"); if (writers == null || !writers.hasNext()) { throw new IOException("no JPEG writer found"); } - ImageWriter imageWriter = (ImageWriter) writers.next(); + ImageWriter imageWriter = writers.next(); + + // Check selection checkbox + boolean justSelection = _pointTypeSelector.getJustSelection(); + int selStart = -1, selEnd = -1; + if (justSelection) { + selStart = _trackInfo.getSelection().getStart(); + selEnd = _trackInfo.getSelection().getEnd(); + } int numPoints = _track.getNumPoints(); DataPoint point = null; int photoNum = 0; // Loop over all points in track - for (int i=0; i=selStart && i<=selEnd))) { photoNum++; // Make a new entry in zip file @@ -490,10 +717,10 @@ public class KmlExporter implements Runnable ImageIcon icon = new ImageIcon(point.getPhoto().getFile().getAbsolutePath()); // Scale and smooth image to required size - Dimension outputSize = ImageUtils.getThumbnailSize( - point.getPhoto().getWidth(), point.getPhoto().getHeight(), - THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT); - BufferedImage bufferedImage = ImageUtils.createScaledImage(icon.getImage(), outputSize.width, outputSize.height); + BufferedImage bufferedImage = ImageUtils.rotateImage(icon.getImage(), + inThumbWidth, inThumbHeight, point.getPhoto().getRotationDegrees()); + // Store image dimensions so that it doesn't have to be calculated again for the points + _imageDimensions[i] = new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight()); imageWriter.setOutput(ImageIO.createImageOutputStream(inZipStream)); imageWriter.write(bufferedImage); @@ -518,8 +745,7 @@ public class KmlExporter implements Runnable for (int i=0; i