Changeset 29178 in osm


Ignore:
Timestamp:
2013-01-07T22:17:29+01:00 (12 years ago)
Author:
oliverw
Message:

Bugfix #8007: Implemented 'deep file inspection' for CSV files to avoid import handler clashes with opendata plugin.

Location:
applications/editors/josm/plugins/ColumbusCSV/src/org/openstreetmap/josm/plugins/columbusCSV
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/ColumbusCSV/src/org/openstreetmap/josm/plugins/columbusCSV/ColumbusCSVImporter.java

    r28420 r29178  
    1717import static org.openstreetmap.josm.tools.I18n.tr;
    1818
     19import java.io.BufferedReader;
     20import java.io.DataInputStream;
    1921import java.io.File;
     22import java.io.FileInputStream;
     23import java.io.FileNotFoundException;
    2024import java.io.IOException;
     25import java.io.InputStreamReader;
     26
    2127import org.openstreetmap.josm.Main;
    2228import org.openstreetmap.josm.actions.AutoScaleAction;
     
    2430import org.openstreetmap.josm.data.gpx.GpxData;
    2531import org.openstreetmap.josm.gui.layer.GpxLayer;
    26 import org.openstreetmap.josm.gui.layer.markerlayer.Marker;
    2732import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
    2833import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
     
    3742 */
    3843public class ColumbusCSVImporter extends FileImporter {
    39         public static final String COLUMBUS_FILE_EXT = "csv";
    40         public static final String COLUMBUS_FILE_EXT_DOT = "." + COLUMBUS_FILE_EXT;
     44    public static final String COLUMBUS_FILE_EXT = "csv";
     45    public static final String COLUMBUS_FILE_EXT_DOT = "." + COLUMBUS_FILE_EXT;
    4146
    42         public ColumbusCSVImporter() {
    43                 super(new ExtensionFileFilter(COLUMBUS_FILE_EXT, COLUMBUS_FILE_EXT,
    44                                 tr("Columbus V-900 CSV Files") + " (*" + COLUMBUS_FILE_EXT_DOT
    45                                                 + ")"));
     47    public ColumbusCSVImporter() {
     48        super(new ExtensionFileFilter(COLUMBUS_FILE_EXT, COLUMBUS_FILE_EXT,
     49                tr("Columbus V-900 CSV Files") + " (*" + COLUMBUS_FILE_EXT_DOT
     50                        + ")"));
     51    }
     52
     53    @Override
     54    public boolean acceptFile(File pathname) {
     55        try {
     56            // do some deep packet inspection...
     57            boolean ok = super.acceptFile(pathname)
     58                    && ColumbusCSVReader.isColumbusFile(pathname);
     59            return ok;
     60        } catch (Exception ex) {
     61            return false;
     62        }
     63    }
     64
     65    /*
     66     * (non-Javadoc)
     67     *
     68     * @see org.openstreetmap.josm.io.FileImporter#importData(java.io.File,
     69     * org.openstreetmap.josm.gui.progress.ProgressMonitor)
     70     */
     71    @Override
     72    public void importData(File file, ProgressMonitor progressMonitor)
     73            throws IOException, IllegalDataException {
     74        String fn = file.getPath();
     75
     76        if (progressMonitor == null) { // make sure that there is a progress
     77                                       // monitor...
     78            progressMonitor = NullProgressMonitor.INSTANCE;
    4679        }
    4780
    48         /* (non-Javadoc)
    49          * @see org.openstreetmap.josm.io.FileImporter#importData(java.io.File, org.openstreetmap.josm.gui.progress.ProgressMonitor)
    50          */
    51         @Override
    52         public void importData(File file, ProgressMonitor progressMonitor)
    53                         throws IOException, IllegalDataException {
    54                 String fn = file.getPath();
     81        progressMonitor.beginTask(String.format(
     82                tr("Importing CSV file ''%s''..."), file.getName(), 4));
     83        progressMonitor.setTicksCount(1);
    5584
    56                 if (progressMonitor == null) { // make sure that there is a progress
    57                                                                                 // monitor...
    58                         progressMonitor = NullProgressMonitor.INSTANCE;
    59                 }
     85        if (fn.toLowerCase().endsWith(COLUMBUS_FILE_EXT_DOT)) {
     86            try {
     87                ColumbusCSVReader r = new ColumbusCSVReader();
    6088
    61                 progressMonitor.beginTask(String.format(tr("Importing CSV file ''%s''..."),
    62                                 file.getName(), 4));
     89                // transform CSV into GPX
     90                GpxData gpxData = r.transformColumbusCSV(fn);
     91                assert (gpxData != null);
    6392                progressMonitor.setTicksCount(1);
    6493
    65                 if (fn.toLowerCase().endsWith(COLUMBUS_FILE_EXT_DOT)) {
    66                         try {
    67                                 ColumbusCSVReader r = new ColumbusCSVReader();
     94                r.dropBufferLists();
    6895
    69                                 // transform CSV into GPX
    70                                 GpxData gpxData = r.transformColumbusCSV(fn);
    71                                 progressMonitor.setTicksCount(1);
     96                progressMonitor.setTicksCount(2);
    7297
    73                                 r.dropBufferLists();
     98                GpxLayer gpxLayer = new GpxLayer(gpxData, file.getName());
     99                assert (gpxLayer != null);
    74100
    75                                 progressMonitor.setTicksCount(2);
     101                // add layer to show way points
     102                Main.main.addLayer(gpxLayer);
    76103
    77                                 GpxLayer gpxLayer = new GpxLayer(gpxData, file.getName());
    78                                
    79                                 // add layer to show way points
    80                                 Main.main.addLayer(gpxLayer);
     104                progressMonitor.setTicksCount(3);
    81105
    82                                 progressMonitor.setTicksCount(3);
     106                // ... and scale view appropriately - if wished by user
     107                if (ColumbusCSVPreferences.zoomAfterImport()) {
     108                    AutoScaleAction action = new AutoScaleAction("data");
     109                    action.autoScale();
     110                }
     111                progressMonitor.setTicksCount(4);
    83112
    84                                 // ... and scale view appropriately - if wished by user
    85                                 if (ColumbusCSVPreferences.zoomAfterImport()) {
    86                                         AutoScaleAction action = new AutoScaleAction("data");
    87                                         action.autoScale();
    88                                 }
    89                                 progressMonitor.setTicksCount(4);
     113                if (Main.pref.getBoolean("marker.makeautomarkers", true)) {
     114                    try {
     115                        MarkerLayer ml = new MarkerLayer(gpxData,
     116                                tr("Markers of ") + file.getName(), file,
     117                                gpxLayer);
    90118
    91                                 if (Main.pref.getBoolean("marker.makeautomarkers", true)) {
    92                                         MarkerLayer ml = new MarkerLayer(gpxData, String.format(tr("Markers from %s"), file.getName()), file, gpxLayer);
    93                                         if (ml.data.size() > 0) {
    94                                                 Main.main.addLayer(ml);
    95                                         } else {
    96                                                 System.err.println("Warning: File contains no markers.");
    97                                         }
    98                                         /* WORKAROUND (Bugfix: #6912): Set marker offset to 0.0 to avoid message "This is after the end of the recording" 
    99                                         for (Marker marker : ml.data) {
    100                                                 marker.offset = 0.0;                                           
    101                                         }*/
    102                                 } else {
    103                                         System.err.println("Warning: Option 'marker.makeautomarkers' is not set; audio marker layer is not created.");
    104                                 }
    105                         } catch (Exception e) {
    106                                 // catch and forward exception
    107                                 e.printStackTrace(System.err);
    108                                 throw new IllegalDataException(e);
    109                         } finally { // take care of monitor...
    110                                 progressMonitor.finishTask();
     119                        assert (ml != null);
     120                        assert (ml.data != null);
     121
     122                        System.out.println("Layer: " + ml);
     123                        System.out.println("Data: " + ml.data != null);
     124                        System.out.println("Data size: " + ml.data.size());
     125
     126                        Main.main.addLayer(ml);
     127                        if (ml.data.size() > 0) {
     128
     129                        } else {
     130                            System.out
     131                                    .println("Warning: File contains no markers.");
    111132                        }
     133                    } catch (Exception exLayer) {
     134                        System.out.println(exLayer);
     135                        exLayer.printStackTrace(System.err);
     136                    }
    112137                } else {
    113                         throw new IOException(
    114                                         tr(String
    115                                                         .format(
    116                                                                         "Unsupported file extension (file '%s' does not end with '%s')!",
    117                                                                         file.getName(), COLUMBUS_FILE_EXT)));
     138                    System.out
     139                            .println("Warning: Option 'marker.makeautomarkers' is not set; audio marker layer is not created.");
    118140                }
     141            } catch (Exception e) {
     142                // catch and forward exception
     143                e.printStackTrace(System.err);
     144                throw new IllegalDataException(e);
     145            } finally { // take care of monitor...
     146                progressMonitor.finishTask();
     147            }
     148        } else {
     149            throw new IOException(
     150                    tr(String
     151                            .format("Unsupported file extension (file '%s' does not end with '%s')!",
     152                                    file.getName(), COLUMBUS_FILE_EXT)));
    119153        }
     154    }
    120155}
  • applications/editors/josm/plugins/ColumbusCSV/src/org/openstreetmap/josm/plugins/columbusCSV/ColumbusCSVReader.java

    r28040 r29178  
    7373 */
    7474public class ColumbusCSVReader {
    75         public static final String AUDIO_WAV_LINK = "audio/wav";
    76         /* GPX tags not provided by the GPXReader class */
    77         private static final String VDOP_TAG = "vdop";
    78         private static final String HDOP_TAG = "hdop";
    79         private static final String PDOP_TAG = "pdop";
    80         private static final String ELEVATIONHEIGHT_TAG = "ele";
    81         private static final String TIME_TAG = "time";
    82         private static final String COMMENT_TAG = "cmt";
    83         private static final String DESC_TAG = "desc";
    84         private static final String FIX_TAG = "fix";
    85         private static final String TYPE_TAG = "columbus:type";
    86 
    87         private static String[] EMPTY_LINE = new String[] {};
    88         private static final String SEPS = ",";
    89 
    90         private int dopConversionErrors = 0;
    91         private int dateConversionErrors = 0;
     75    public static final String AUDIO_WAV_LINK = "audio/wav";
     76    /* GPX tags not provided by the GPXReader class */
     77    private static final String VDOP_TAG = "vdop";
     78    private static final String HDOP_TAG = "hdop";
     79    private static final String PDOP_TAG = "pdop";
     80    private static final String ELEVATIONHEIGHT_TAG = "ele";
     81    private static final String TIME_TAG = "time";
     82    private static final String COMMENT_TAG = "cmt";
     83    private static final String DESC_TAG = "desc";
     84    private static final String FIX_TAG = "fix";
     85    private static final String TYPE_TAG = "columbus:type";
     86
     87    private static String[] EMPTY_LINE = new String[] {};
     88    private static final String SEPS = ",";
     89    /* Lines to read before deciding on Columbus file yes/no */
     90    private static final int MAX_SCAN_LINES = 20;
     91    private static final int MIN_SCAN_LINES = 10;
     92
     93    private int dopConversionErrors = 0;
     94    private int dateConversionErrors = 0;
     95
     96    private int firstVoxNumber = -1, lastVoxNumber = -1;
     97
     98    private HashMap<String, WayPoint> voxFiles = new HashMap<String, WayPoint>();
     99    private Collection<Collection<WayPoint>> allTrackPts = new ArrayList<Collection<WayPoint>>();
     100    private List<WayPoint> trackPts = new ArrayList<WayPoint>();
     101    private List<WayPoint> allWpts = new ArrayList<WayPoint>();
     102    private String fileDir;
     103
     104    /**
     105     * Transforms a Columbus V-900 CSV file into a JOSM GPX layer.
     106     *
     107     * @param fileName The Columbus file to import.
     108     * @return GPX representation of Columbus track file.
     109     * @throws IOException
     110     * @throws DataFormatException
     111     */
     112    public GpxData transformColumbusCSV(String fileName) throws IOException,
     113            IllegalDataException {
     114        if (fileName == null || fileName.length() == 0) {
     115            throw new IllegalArgumentException(
     116                    "File name must not be null or empty");
     117        }
     118
     119        // GPX data structures
     120        GpxData gpxData = new GpxData();
     121
     122        File f = new File(fileName);
     123        fileDir = f.getParent();
     124        FileInputStream fstream = new FileInputStream(fileName);
     125        // Get the object of DataInputStream
     126        DataInputStream in = new DataInputStream(fstream);
     127        BufferedReader br = new BufferedReader(new InputStreamReader(in));
     128        String strLine;
     129        // Initial values
     130        int line = 1;
     131        initImport();
     132        dropBufferLists();
     133
     134        int waypts = 0, trkpts = 0, audiopts = 0, missaudio = 0, rescaudio = 0;
     135        try {
     136            // Read File Line By Line
     137            while ((strLine = br.readLine()) != null) {
     138                String[] csvFields = getCSVLine(strLine); // Get the columns of
     139                                                          // the current line
     140                if (csvFields.length == 0 || line <= 1) { // Skip, if line is
     141                                                          // header or contains
     142                                                          // no data
     143                    ++line;
     144                    continue;
     145                }
     146
     147                try {
     148                    WayPoint wpt = createWayPoint(csvFields, fileDir);
     149                    String wptType = (String) wpt.attr.get(TYPE_TAG);
     150                    String oldWptType = csvFields[1];
     151
     152                    if ("T".equals(wptType)) { // point of track (T)
     153                        trackPts.add(wpt);
     154                        trkpts++;
     155                    } else { // way point (C) / have voice file: V)
     156                        if (!wptType.equals(oldWptType)) { // type changed?
     157                            if ("V".equals(oldWptType)) { // missing audiofile
     158                                missaudio++;
     159                            }
     160                            if ("C".equals(oldWptType)) { // rescued audiofile
     161                                rescaudio++;
     162                            }
     163                        } else {
     164                            if ("V".equals(wptType)) { // wpt with vox
     165                                audiopts++;
     166                            }
     167                        }
     168
     169                        gpxData.waypoints.add(wpt); // add the waypoint to the
     170                                                    // track
     171                        waypts++;
     172                    }
     173
     174                    allWpts.add(wpt);
     175
     176                    wpt.attr.remove(TYPE_TAG);
     177                } catch (Exception ex) {
     178                    br.close();
     179                    throw new IllegalDataException(tr("Error in line " + line
     180                            + ": " + ex.toString()));
     181                }
     182                ++line;
     183            }
     184        } finally {
     185            // Close the input stream
     186            br.close();
     187        }
     188
     189        // do some sanity checks
     190        assert (trackPts.size() == trkpts);
     191        assert (gpxData.waypoints.size() == waypts);
     192        assert (firstVoxNumber <= lastVoxNumber);
     193
     194        rescaudio += searchForLostAudioFiles(gpxData);
     195
     196        // compose the track
     197        allTrackPts.add(trackPts);
     198        GpxTrack trk = new ImmutableGpxTrack(allTrackPts,
     199                Collections.<String, Object> emptyMap());
     200        gpxData.tracks.add(trk);
     201
     202        assert (gpxData.routes.size() == 1);
     203
     204        // Issue conversion warning, if needed
     205        if (ColumbusCSVPreferences.warnConversion()
     206                && (dateConversionErrors > 0 || dopConversionErrors > 0)) {
     207            String message = String.format(
     208                    "%d date conversion faults and %d DOP conversion errors",
     209                    dateConversionErrors, dopConversionErrors);
     210            ColumbusCSVUtils.showWarningMessage(tr(message));
     211        }
     212        // Show summary
     213        if (ColumbusCSVPreferences.showSummary()) {
     214            showSummary(waypts, trkpts, audiopts, missaudio, rescaudio);
     215        }
     216
     217        String desc = String.format(
     218                "Converted by ColumbusCSV plugin from track file '%s'",
     219                f.getName());
     220        gpxData.attr.put(GpxData.META_DESC, desc);
     221        gpxData.storageFile = f;
     222        return gpxData;
     223    }
     224
     225    /**
     226     * Checks a (CSV) file for Columbus tags. This method is a simplified copy
     227     * of the @link transformColumbusCSV and just checks a small amount of
     228     * lines.
     229     *
     230     * @param file The file to check.
     231     * @return true, if given file is a Columbus file; otherwise false.
     232     */
     233    public static boolean isColumbusFile(File file) throws IOException {
     234        if (file == null) return false;
    92235       
    93         private int firstVoxNumber = -1, lastVoxNumber = -1;
    94        
    95         private HashMap<String, WayPoint> voxFiles = new HashMap<String, WayPoint>();
    96         private Collection<Collection<WayPoint>> allTrackPts = new ArrayList<Collection<WayPoint>>();
    97         private List<WayPoint> trackPts = new ArrayList<WayPoint>();   
    98         private List<WayPoint> allWpts = new ArrayList<WayPoint>();
    99         private String fileDir;
    100 
    101         /**
    102          * Transforms a Columbus V-900 CSV file into a JOSM GPX layer.
    103          *
    104          * @param fileName
    105          * @return
    106          * @throws IOException
    107          * @throws DataFormatException
    108          */
    109         public GpxData transformColumbusCSV(String fileName) throws IOException,
    110                         IllegalDataException {
    111                 if (fileName == null || fileName.length() == 0) {
    112                         throw new IllegalArgumentException(
    113                                         "File name must not be null or empty");
     236        FileInputStream fstream = new FileInputStream(file);
     237        // Get the object of DataInputStream
     238        DataInputStream in = new DataInputStream(fstream);
     239        BufferedReader br = new BufferedReader(new InputStreamReader(in));
     240        String strLine;
     241        // Initial values
     242        int line = 0;
     243        int columbusLines = 0;
     244        try {
     245            // Read File Line By Line until we either exceed the maximum scan
     246            // lines or we are sure that we have a columbus file
     247            while ((strLine = br.readLine()) != null
     248                    && (line < MAX_SCAN_LINES || columbusLines > MIN_SCAN_LINES)) {
     249                String[] csvFields = getCSVLine(strLine); // Get the columns of
     250                                                          // the current line
     251                ++line;
     252                if (csvFields.length == 0 || line <= 1) { // Skip, if line is
     253                                                          // header or contains
     254                                                          // no data
     255                    continue;
    114256                }
    115257
    116                 // GPX data structures
    117                 GpxData gpxData = new GpxData();               
    118                
    119                 File f = new File(fileName);
    120                 fileDir = f.getParent();
    121                 FileInputStream fstream = new FileInputStream(fileName);
    122                 // Get the object of DataInputStream
    123                 DataInputStream in = new DataInputStream(fstream);
    124                 BufferedReader br = new BufferedReader(new InputStreamReader(in));
    125                 String strLine;
    126                 // Initial values
    127                 int line = 1;
    128                 initImport();
    129                 dropBufferLists();
    130                
    131                 int waypts = 0, trkpts = 0, audiopts = 0, missaudio = 0, rescaudio = 0;
    132                 try {
    133                         // Read File Line By Line
    134                         while ((strLine = br.readLine()) != null) {                             
    135                                 String[] csvFields = getCSVLine(strLine);       // Get the columns of the current line                         
    136                                 if (csvFields.length == 0 || line <= 1) {       // Skip, if line is header or contains no data
    137                                         ++line;
    138                                         continue;
    139                                 }
    140 
    141                                 try {
    142                                         WayPoint wpt = createWayPoint(csvFields, fileDir);
    143                                         String wptType = (String) wpt.attr.get(TYPE_TAG);
    144                                         String oldWptType = csvFields[1];
    145                                        
    146                                         if ("T".equals(wptType)) { // point of track (T)
    147                                                 trackPts.add(wpt);
    148                                                 trkpts++;
    149                                         } else { // way point (C) / have voice file: V)
    150                                                 if (!wptType.equals(oldWptType)) { // type changed?                                                     
    151                                                         if ("V".equals(oldWptType)) { // missing audiofile
    152                                                                 missaudio++;
    153                                                         }                                                       
    154                                                         if ("C".equals(oldWptType)) { // rescued audiofile
    155                                                                 rescaudio++;
    156                                                         }
    157                                                 } else {                                                       
    158                                                         if ("V".equals(wptType)) { // wpt with vox
    159                                                                 audiopts++;
    160                                                         }
    161                                                 }
    162                                                                                                
    163                                                 gpxData.waypoints.add(wpt); // add the waypoint to the track
    164                                                 waypts++;
    165                                         }
    166                                        
    167                                         allWpts.add(wpt);
    168                                        
    169                                         wpt.attr.remove(TYPE_TAG);
    170                                 } catch (Exception ex) {
    171                                         throw new IllegalDataException(tr("Error in line " + line
    172                                                         + ": " + ex.toString()));
    173                                 }
    174                                 ++line;
    175                         }
    176                 } finally {
    177                         // Close the input stream
    178                         in.close();
     258                String wptType = csvFields[1];
     259                // Check for columbus tag
     260                if ("T".equals(wptType) || "V".equals(wptType)
     261                        || "C".equals(wptType)) {
     262                    // ok, we found one line but still not convinced ;-)
     263                    columbusLines++;
    179264                }
    180 
    181                 // do some sanity checks
    182                 assert (trackPts.size() == trkpts);
    183                 assert (gpxData.waypoints.size() == waypts);
    184                 assert (firstVoxNumber <= lastVoxNumber);
    185                
    186                 rescaudio += searchForLostAudioFiles(gpxData);
    187 
    188                 // compose the track
    189                 allTrackPts.add(trackPts);
    190                 GpxTrack trk = new ImmutableGpxTrack(allTrackPts, Collections
    191                                 .<String, Object> emptyMap());
    192                 gpxData.tracks.add(trk);
    193 
    194                 assert (gpxData.routes.size() == 1);
    195 
    196                 // Issue conversion warning, if needed
    197                 if (ColumbusCSVPreferences.warnConversion()
    198                                 && (dateConversionErrors > 0 || dopConversionErrors > 0)) {
    199                         String message = String.format(
    200                                         "%d date conversion faults and %d DOP conversion errors",
    201                                         dateConversionErrors, dopConversionErrors);
    202                         ColumbusCSVUtils.showWarningMessage(tr(message));
     265            }
     266        } finally {
     267            // Close the input stream
     268            br.close();
     269        }
     270
     271        return columbusLines > MIN_SCAN_LINES;
     272    }
     273
     274    /**
     275     * Searches for unlinked audio files and tries to link them with the closest
     276     * way point. This requires that the file date of the wav files is kept -
     277     * there is no other way to assign the audio files to way points.
     278     *
     279     * @param gpx
     280     * @return
     281     */
     282    private int searchForLostAudioFiles(GpxData gpx) {
     283        HashMap<String, WayPoint> voxFiles = getVoxFileMap();
     284
     285        int first, last;
     286        first = getFirstVoxNumber();
     287        last = getLastVoxNumber();
     288
     289        int rescuedFiles = 0;
     290
     291        for (int i = first; i < last; i++) {
     292            String voxFile = String.format("vox%05d.wav", i);
     293            String nextVoxFile = String.format("vox%05d.wav", i + 1);
     294            if (!voxFiles.containsKey(voxFile)) {
     295                System.out.println("Found lost vox file " + voxFile);
     296
     297                File f = getVoxFilePath(voxFile);
     298                WayPoint nearestWpt = null;
     299                List<WayPoint> wpts = getAllWayPoints();
     300                // Attach recording to the way point right before the next vox
     301                // file
     302                if (voxFiles.containsKey(nextVoxFile)) {
     303                    WayPoint nextWpt = voxFiles.get(nextVoxFile);
     304                    int idx = getAllWayPoints().indexOf(nextWpt) - 5;
     305                    if (idx >= 0) {
     306                        nearestWpt = wpts.get(idx);
     307                    } else {
     308                        nearestWpt = wpts.get(0);
     309                    }
     310                } else { // attach to last way point
     311                    nearestWpt = wpts.get(wpts.size() - 1);
    203312                }
    204                 // Show summary
    205                 if (ColumbusCSVPreferences.showSummary()) {
    206                         showSummary(waypts, trkpts, audiopts, missaudio, rescaudio);
     313
     314                // Add link to found way point
     315                if (nearestWpt != null) {
     316                    if (addLinkToWayPoint(nearestWpt, "*" + voxFile + "*", f)) {
     317                        System.out.println(String.format(
     318                                "Linked file %s to position %s", voxFile,
     319                                nearestWpt.getCoor().toDisplayString()));
     320                        // Add linked way point to way point list of GPX;
     321                        // otherwise
     322                        // it would not be shown correctly
     323                        gpx.waypoints.add(nearestWpt);
     324                        rescuedFiles++;
     325                    } else {
     326                        System.err
     327                                .println(String
     328                                        .format("Could not link vox file %s due to invalid parameters.",
     329                                                voxFile));
     330                    }
    207331                }
    208 
    209                 String desc = String.format("Converted by ColumbusCSV plugin from track file '%s'", f.getName());
    210                 gpxData.attr.put(GpxData.META_DESC, desc);
    211                 gpxData.storageFile = f;
    212                 return gpxData;
    213         }
    214        
    215         /**
    216          * Searches for unlinked audio files and tries to link them with the closest
    217          * way point. This requires that the file date of the wav files is kept -
    218          * there is no other way to assign the audio files to way points.
    219          *
    220          * @param gpx
    221          * @return
    222          */
    223         private int searchForLostAudioFiles(GpxData gpx) {
    224                 HashMap<String,WayPoint> voxFiles = getVoxFileMap();
    225 
    226                 int first, last;
    227                 first = getFirstVoxNumber();
    228                 last = getLastVoxNumber();
    229 
    230                 int rescuedFiles = 0;
    231 
    232                 for (int i = first; i < last; i++) {                   
    233                         String voxFile = String.format("vox%05d.wav", i);
    234                         String nextVoxFile = String.format("vox%05d.wav", i+1);
    235                         if (!voxFiles.containsKey(voxFile)) {
    236                                 System.out.println("Found lost vox file " + voxFile);
    237 
    238                                 File f = getVoxFilePath(voxFile);
    239                                 WayPoint nearestWpt = null;
    240                                 List<WayPoint> wpts = getAllWayPoints();
    241                                 // Attach recording to the way point right before the next vox file
    242                                 if (voxFiles.containsKey(nextVoxFile)) {
    243                                         WayPoint nextWpt = voxFiles.get(nextVoxFile);
    244                                         int idx = getAllWayPoints().indexOf(nextWpt) - 5;
    245                                         if (idx >= 0) {
    246                                                 nearestWpt = wpts.get(idx);
    247                                         } else {
    248                                                 nearestWpt = wpts.get(0);
    249                                         }
    250                                 } else { // attach to last way point
    251                                         nearestWpt = wpts.get(wpts.size() - 1);
    252                                 }
    253 
    254                                 // Add link to found way point
    255                                 if (nearestWpt != null) {
    256                                         if (addLinkToWayPoint(nearestWpt, "*" + voxFile + "*", f)) {
    257                                                 System.out.println(String.format(
    258                                                                 "Linked file %s to position %s", voxFile,
    259                                                                 nearestWpt.getCoor().toDisplayString()));
    260                                                 // Add linked way point to way point list of GPX; otherwise
    261                                                 // it would not be shown correctly
    262                                                 gpx.waypoints.add(nearestWpt);
    263                                                 rescuedFiles++;
    264                                         } else {
    265                                                 System.err
    266                                                                 .println(String
    267                                                                                 .format(
    268                                                                                                 "Could not link vox file %s due to invalid parameters.",
    269                                                                                                 voxFile));
    270                                         }
    271                                 }
    272                         }
    273                 }
    274 
    275                 return rescuedFiles;
    276         }
    277 
    278         /**
     332            }
     333        }
     334
     335        return rescuedFiles;
     336    }
     337
     338    /**
    279339         *
    280340         */
    281         private void initImport() {
    282                 dateConversionErrors = 0;
    283                 dopConversionErrors = 0;
    284                 firstVoxNumber = Integer.MAX_VALUE;
    285                 lastVoxNumber = Integer.MIN_VALUE;
    286         }
    287 
    288         /**
    289          * Clears all temporary buffers.
    290          */
    291         void dropBufferLists() {
    292                 allTrackPts.clear();
    293                 trackPts.clear();
    294                 voxFiles.clear();
    295         }
    296 
    297         /**
    298          * Shows the summary to the user.
    299          * @param waypts The number of imported way points
    300          * @param trkpts The number of imported track points
    301          * @param audiopts The number of imported way points with vox
    302          * @param missaudio The number of missing audio files
    303          * @param rescaudio  The number of rescued audio files
    304          */
    305         private void showSummary(int waypts, int trkpts, int audiopts,
    306                         int missaudio, int rescaudio) {
    307                 String message = "";
    308                 if (missaudio > 0) {
    309                         message = String
    310                                 .format(
    311                                                 "Imported %d track points and %d way points (%d with audio, %d rescued).\nNote: %d audio files could not be found, please check marker comments!",
    312                                                 trkpts, waypts, audiopts, rescaudio, missaudio);
    313                 } else {
    314                         message = String
    315                         .format(
    316                                         "Imported %d track points and %d way points (%d with audio, %d rescued).",
    317                                         trkpts, waypts, audiopts, rescaudio);
     341    private void initImport() {
     342        dateConversionErrors = 0;
     343        dopConversionErrors = 0;
     344        firstVoxNumber = Integer.MAX_VALUE;
     345        lastVoxNumber = Integer.MIN_VALUE;
     346    }
     347
     348    /**
     349     * Clears all temporary buffers.
     350     */
     351    void dropBufferLists() {
     352        allTrackPts.clear();
     353        trackPts.clear();
     354        voxFiles.clear();
     355    }
     356
     357    /**
     358     * Shows the summary to the user.
     359     *
     360     * @param waypts
     361     *            The number of imported way points
     362     * @param trkpts
     363     *            The number of imported track points
     364     * @param audiopts
     365     *            The number of imported way points with vox
     366     * @param missaudio
     367     *            The number of missing audio files
     368     * @param rescaudio
     369     *            The number of rescued audio files
     370     */
     371    private void showSummary(int waypts, int trkpts, int audiopts,
     372            int missaudio, int rescaudio) {
     373        String message = "";
     374        if (missaudio > 0) {
     375            message = String
     376                    .format("Imported %d track points and %d way points (%d with audio, %d rescued).\nNote: %d audio files could not be found, please check marker comments!",
     377                            trkpts, waypts, audiopts, rescaudio, missaudio);
     378        } else {
     379            message = String
     380                    .format("Imported %d track points and %d way points (%d with audio, %d rescued).",
     381                            trkpts, waypts, audiopts, rescaudio);
     382        }
     383        ColumbusCSVUtils.showInfoMessage(tr(message));
     384    }
     385
     386    /**
     387     * Creates a GPX way point from a tokenized CSV line. The attributes of the
     388     * way point depends on whether the Columbus logger runs in simple or
     389     * professional mode.
     390     *
     391     * @param csvLine
     392     *            The columns of a single CSV line.
     393     * @return The corresponding way point instance.
     394     * @throws DataFormatException
     395     */
     396    private WayPoint createWayPoint(String[] csvLine, String fileDir)
     397            throws IOException {
     398        // Sample line in simple mode
     399        // INDEX,TAG,DATE,TIME,LATITUDE N/S,LONGITUDE
     400        // E/W,HEIGHT,SPEED,HEADING,VOX
     401        // 1,T,090430,194134,48.856330N,009.089779E,318,20,0,
     402
     403        // Sample line in extended mode
     404        // INDEX,TAG,DATE,TIME,LATITUDE N/S,LONGITUDE
     405        // E/W,HEIGHT,SPEED,HEADING,FIX MODE,VALID,PDOP,HDOP,VDOP,VOX
     406        // 1,T,090508,191448,48.856928N,009.091153E,330,3,0,3D,SPS ,1.4,1.2,0.8,
     407        if (csvLine.length != 10 && csvLine.length != 15)
     408            throw new IOException("Invalid number of tokens: " + csvLine.length);
     409        boolean isExtMode = csvLine.length > 10;
     410
     411        // Extract latitude/longitude first
     412        String lat = csvLine[4];
     413        double latVal = Double.parseDouble(lat.substring(0, lat.length() - 1));
     414        if (lat.endsWith("S")) {
     415            latVal = -latVal;
     416        }
     417
     418        String lon = csvLine[5];
     419        double lonVal = Double.parseDouble(lon.substring(0, lon.length() - 1));
     420        if (lon.endsWith("W")) {
     421            lonVal = -lonVal;
     422        }
     423        LatLon pos = new LatLon(latVal, lonVal);
     424        WayPoint wpt = new WayPoint(pos);
     425
     426        // set wpt type
     427        wpt.attr.put(TYPE_TAG, csvLine[1]);
     428
     429        // Check for audio file and link it, if present
     430        String voxFile = null;
     431        if (isExtMode) {
     432            voxFile = csvLine[14];
     433        } else {
     434            voxFile = csvLine[9];
     435        }
     436
     437        if (!ColumbusCSVUtils.isStringNullOrEmpty(voxFile)) {
     438            voxFile = voxFile + ".wav";
     439            File file = getVoxFilePath(fileDir, voxFile);
     440            if (file != null && file.exists()) {
     441                // link vox file
     442                int voxNum = getNumberOfVoxfile(voxFile);
     443                lastVoxNumber = Math.max(voxNum, lastVoxNumber);
     444                firstVoxNumber = Math.min(voxNum, firstVoxNumber);
     445
     446                addLinkToWayPoint(wpt, voxFile, file);
     447
     448                if (!"V".equals(csvLine[1])) {
     449                    System.out
     450                            .println("Rescued unlinked audio file " + voxFile);
    318451                }
    319                 ColumbusCSVUtils.showInfoMessage(tr(message));
    320         }
    321 
    322         /**
    323          * Creates a GPX way point from a tokenized CSV line. The attributes of the
    324          * way point depends on whether the Columbus logger runs in simple or
    325          * professional mode.
    326          *
    327          * @param csvLine The columns of a single CSV line.
    328          * @return The corresponding way point instance.
    329          * @throws DataFormatException
    330          */
    331         private WayPoint createWayPoint(String[] csvLine, String fileDir)
    332                         throws IOException {
    333                 // Sample line in simple mode
    334                 // INDEX,TAG,DATE,TIME,LATITUDE N/S,LONGITUDE
    335                 // E/W,HEIGHT,SPEED,HEADING,VOX
    336                 // 1,T,090430,194134,48.856330N,009.089779E,318,20,0,
    337 
    338                 // Sample line in extended mode
    339                 // INDEX,TAG,DATE,TIME,LATITUDE N/S,LONGITUDE
    340                 // E/W,HEIGHT,SPEED,HEADING,FIX MODE,VALID,PDOP,HDOP,VDOP,VOX
    341                 // 1,T,090508,191448,48.856928N,009.091153E,330,3,0,3D,SPS ,1.4,1.2,0.8,
    342                 if (csvLine.length != 10 && csvLine.length != 15)
    343                         throw new IOException("Invalid number of tokens: " + csvLine.length);
    344                 boolean isExtMode = csvLine.length > 10;
    345 
    346                 // Extract latitude/longitude first
    347                 String lat = csvLine[4];
    348                 double latVal = Double.parseDouble(lat.substring(0, lat.length() - 1));
    349                 if (lat.endsWith("S")) {
    350                         latVal = -latVal;
     452                voxFiles.put(voxFile, wpt);
     453
     454                // set type to way point with vox
     455                wpt.attr.put(TYPE_TAG, "V");
     456            } else { // audio file not found -> issue warning
     457                System.err.println("File " + voxFile + " not found!");
     458                String warnMsg = tr("Missing audio file") + ": " + voxFile;
     459                System.err.println(warnMsg);
     460                if (ColumbusCSVPreferences.warnMissingAudio()) {
     461                    ColumbusCSVUtils.showInfoMessage(warnMsg);
    351462                }
    352 
    353                 String lon = csvLine[5];
    354                 double lonVal = Double.parseDouble(lon.substring(0, lon.length() - 1));
    355                 if (lon.endsWith("W")) {
    356                         lonVal = -lonVal;
    357                 }
    358                 LatLon pos = new LatLon(latVal, lonVal);
    359                 WayPoint wpt = new WayPoint(pos);
    360                
    361                 // set wpt type
    362                 wpt.attr.put(TYPE_TAG, csvLine[1]);
    363                
    364                 // Check for audio file and link it, if present
    365                 String voxFile = null;
    366                 if (isExtMode) {
    367                         voxFile = csvLine[14];
    368                 } else {
    369                         voxFile = csvLine[9];
    370                 }
    371 
    372                 if (!ColumbusCSVUtils.isStringNullOrEmpty(voxFile)) {
    373                         voxFile = voxFile + ".wav";
    374                         File file = getVoxFilePath(fileDir, voxFile);
    375                         if (file != null && file.exists()) {
    376                                 // link vox file
    377                                 int voxNum = getNumberOfVoxfile(voxFile);
    378                                 lastVoxNumber = Math.max(voxNum, lastVoxNumber);
    379                                 firstVoxNumber = Math.min(voxNum, firstVoxNumber);
    380                                                                
    381                                 addLinkToWayPoint(wpt, voxFile, file);
    382                                
    383                                 if (!"V".equals(csvLine[1])) {
    384                                         System.out.println("Rescued unlinked audio file " + voxFile);
    385                                 }
    386                                 voxFiles.put(voxFile, wpt);
    387                                
    388                                 // set type to way point with vox
    389                                 wpt.attr.put(TYPE_TAG, "V");
    390                         } else { // audio file not found -> issue warning
    391                                 System.err.println("File " + voxFile + " not found!");
    392                                 String warnMsg = tr("Missing audio file") + ": " + voxFile;
    393                                 System.err.println(warnMsg);
    394                                 if (ColumbusCSVPreferences.warnMissingAudio()) {                                       
    395                                         ColumbusCSVUtils.showInfoMessage(warnMsg);
    396                                 }
    397                                 wpt.attr.put(ColumbusCSVReader.COMMENT_TAG, warnMsg);
    398                                 // set type to ordinary way point
    399                                 wpt.attr.put(TYPE_TAG, "C");
    400                         }
    401                        
    402                 }
    403 
    404                 // Extract date/time
    405                 SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyMMdd/HHmmss");
    406                 Date d = null;
    407 
    408                 try {
    409                        
    410                         d = sdf.parse(csvLine[2] + "/" + csvLine[3]);
    411                         // format date according to GPX
    412                         SimpleDateFormat f = new SimpleDateFormat(
    413                                         "yyyy-MM-dd'T'HH:mm:ss'Z'");
    414 
    415                         wpt.attr.put(ColumbusCSVReader.TIME_TAG, f.format(d).toString());
    416                         wpt.setTime();
    417                 } catch (ParseException ex) {
    418                         dateConversionErrors++;
    419                         System.err.println(ex);
    420                 }
    421 
    422                 // Add further attributes
    423                 // Elevation height (altitude provided by GPS signal)
    424                 wpt.attr.put(ColumbusCSVReader.ELEVATIONHEIGHT_TAG, csvLine[6]);
    425                
    426                 // Add data of extended mode, if applicable
    427                 if (isExtMode && !ColumbusCSVPreferences.ignoreDOP()) {
    428                         addExtendedGPSData(csvLine, wpt);
    429                 }
    430 
    431                 return wpt;
    432         }
    433        
    434         /**
    435          * Gets the full path of the audio file. Same as <code>getVoxFilePath(getWorkingDirOfImport(), voxFile)</code>.
    436          * @param voxFile The name of the audio file without dir and extension.
    437          * @return
    438          *
    439          */
    440         public File getVoxFilePath(String voxFile) {
    441                 return getVoxFilePath(getWorkingDirOfImport(), voxFile);
    442         }
    443 
    444         /**
    445          * Gets the full path of the audio file.
    446          * @param fileDir The directory containing the audio file.
    447          * @param voxFile The name of the audio file without dir and extension.
    448          * @return
    449          */
    450         public File getVoxFilePath(String fileDir, String voxFile) {
    451                 // The FAT16 file name is interpreted differently from case-sensitive file systems, so we
    452                 // have to test several variants
    453                 String[] fileNameVariants = new String[] {voxFile, voxFile.toLowerCase(), voxFile.toUpperCase()};
    454                
    455                 for (int i = 0; i < fileNameVariants.length; i++) {
    456                         File file = new File(fileDir + File.separator + fileNameVariants[i]);
    457                         if (file.exists()) {
    458                                 return file;
    459                         }
    460                 }
    461                 return null; // give up...
    462                
    463         }
    464 
    465         /**
    466          * Adds extended GPS data (*DOP and fix mode) to the way point
    467          * @param csvLine
    468          * @param wpt
    469          */
    470         private void addExtendedGPSData(String[] csvLine, WayPoint wpt) {
    471                 // Fix mode
    472                 wpt.attr.put(FIX_TAG, csvLine[9].toLowerCase());
    473                
    474                 Float f;
    475                 // Position errors (dop = dilution of position)
    476                 f = ColumbusCSVUtils.floatFromString(csvLine[11]);
    477                 if (f != Float.NaN) {
    478                         wpt.attr.put(ColumbusCSVReader.PDOP_TAG, f);
    479                 } else {
    480                         dopConversionErrors++;
    481                 }
    482 
    483                 f = ColumbusCSVUtils.floatFromString(csvLine[12]);
    484                 if (f != Float.NaN) {
    485                         wpt.attr.put(ColumbusCSVReader.HDOP_TAG, f);
    486                 } else {
    487                         dopConversionErrors++;
    488                 }
    489 
    490                 f = ColumbusCSVUtils.floatFromString(csvLine[13]);
    491                 if (f != Float.NaN) {
    492                         wpt.attr.put(ColumbusCSVReader.VDOP_TAG, f);
    493                 } else {
    494                         dopConversionErrors++;
    495                 }
    496         }
    497 
    498         /**
    499          * Adds a link to a way point.
    500          * @param wpt The way point to add the link to.
    501          * @param voxFile
    502          * @param file
    503          * @return True, if link has been added; otherwise false
    504          */
    505         public boolean addLinkToWayPoint(WayPoint wpt, String voxFile, File file) {
    506                 if (file == null || wpt == null || voxFile == null) return false;
    507                
    508                 GpxLink lnk = new GpxLink(file.toURI().toString());
    509                 lnk.type = ColumbusCSVReader.AUDIO_WAV_LINK;
    510                 lnk.text = voxFile;
    511                                                
    512                 // JOSM expects a collection of links here...
    513                 Collection<GpxLink> linkList = new ArrayList<GpxLink>(1);
    514                 linkList.add(lnk);
    515 
    516                 wpt.attr.put(GpxData.META_LINKS, linkList);                             
    517                 wpt.attr.put(ColumbusCSVReader.COMMENT_TAG, "Audio recording");
    518                 wpt.attr.put(ColumbusCSVReader.DESC_TAG, voxFile);
    519                 return true;
    520         }
    521        
    522         /**
    523          * Splits a line of the CSV files into it's tokens.
    524          *
    525          * @param line
    526          * @return Array containing the tokens of the CSV file.
    527          */
    528         private String[] getCSVLine(String line) {
    529                 if (line == null || line.length() == 0)
    530                         return EMPTY_LINE;
    531 
    532                 StringTokenizer st = new StringTokenizer(line, SEPS, false);
    533                 int n = st.countTokens();
    534 
    535                 String[] res = new String[n];
    536                 for (int i = 0; i < n; i++) {
    537                         res[i] = st.nextToken().trim();
    538                 }
    539                 return res;
    540         }
    541        
    542         /**
    543          * Extracts the number from a VOX file name, e. g. for a
    544          * file named "VOX01524" this method will return 1524.
    545          * @param fileName The vox file name.
    546          * @return The number of the vox file or -1; if the given name was not valid.
    547          */
    548         private int getNumberOfVoxfile(String fileName) {
    549                 if (fileName == null) return -1;
    550                
    551                 try {
    552                         String num = fileName.substring(3);
    553                         int val = Integer.parseInt(num);
    554                         return val;
    555                 } catch (NumberFormatException e) {                     
    556                         return -1;
    557                 }
    558         }
    559 
    560         /**
    561          * Return the number of date conversion errors.
    562          *
    563          * @return
    564          */
    565         public int getNumberOfDateConversionErrors() {
    566                 return dateConversionErrors;
    567         }
    568 
    569         /**
    570          * Return the number of pdop/vdop/hdop conversion errors.
    571          *
    572          * @return
    573          */
    574         public int getNumberOfDOPConversionErrors() {
    575                 return dopConversionErrors;
    576         }
    577 
    578         /**
    579          * Gets the number of first vox file.
    580          * @return
    581          */
    582         public int getFirstVoxNumber() {
    583                 return firstVoxNumber;
    584         }
    585 
    586         /**
    587          * Gets the number of last vox file.
    588          * @return
    589          */
    590         public int getLastVoxNumber() {
    591                 return lastVoxNumber;
    592         }
    593 
    594         /**
    595          * Gets the map containing the vox files with their associated way point.
    596          * @return
    597          */
    598         public HashMap<String, WayPoint> getVoxFileMap() {
    599                 return voxFiles;
    600         }
    601 
    602         /**
    603          * Gets the list containing all imported track and way points.
    604          * @return
    605          */
    606         public List<WayPoint> getAllWayPoints() {
    607                 return allWpts;
    608         }
    609 
    610         /**
    611          * Gets the import directory.
    612          * @return
    613          */
    614         public String getWorkingDirOfImport() {
    615                 return fileDir;
    616         }
     463                wpt.attr.put(ColumbusCSVReader.COMMENT_TAG, warnMsg);
     464                // set type to ordinary way point
     465                wpt.attr.put(TYPE_TAG, "C");
     466            }
     467
     468        }
     469
     470        // Extract date/time
     471        SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyMMdd/HHmmss");
     472        Date d = null;
     473
     474        try {
     475
     476            d = sdf.parse(csvLine[2] + "/" + csvLine[3]);
     477            // format date according to GPX
     478            SimpleDateFormat f = new SimpleDateFormat(
     479                    "yyyy-MM-dd'T'HH:mm:ss'Z'");
     480
     481            wpt.attr.put(ColumbusCSVReader.TIME_TAG, f.format(d).toString());
     482            wpt.setTime();
     483        } catch (ParseException ex) {
     484            dateConversionErrors++;
     485            System.err.println(ex);
     486        }
     487
     488        // Add further attributes
     489        // Elevation height (altitude provided by GPS signal)
     490        wpt.attr.put(ColumbusCSVReader.ELEVATIONHEIGHT_TAG, csvLine[6]);
     491
     492        // Add data of extended mode, if applicable
     493        if (isExtMode && !ColumbusCSVPreferences.ignoreDOP()) {
     494            addExtendedGPSData(csvLine, wpt);
     495        }
     496
     497        return wpt;
     498    }
     499
     500    /**
     501     * Gets the full path of the audio file. Same as
     502     * <code>getVoxFilePath(getWorkingDirOfImport(), voxFile)</code>.
     503     *
     504     * @param voxFile
     505     *            The name of the audio file without dir and extension.
     506     * @return
     507     *
     508     */
     509    public File getVoxFilePath(String voxFile) {
     510        return getVoxFilePath(getWorkingDirOfImport(), voxFile);
     511    }
     512
     513    /**
     514     * Gets the full path of the audio file.
     515     *
     516     * @param fileDir
     517     *            The directory containing the audio file.
     518     * @param voxFile
     519     *            The name of the audio file without dir and extension.
     520     * @return
     521     */
     522    public File getVoxFilePath(String fileDir, String voxFile) {
     523        // The FAT16 file name is interpreted differently from case-sensitive
     524        // file systems, so we
     525        // have to test several variants
     526        String[] fileNameVariants = new String[] { voxFile,
     527                voxFile.toLowerCase(), voxFile.toUpperCase() };
     528
     529        for (int i = 0; i < fileNameVariants.length; i++) {
     530            File file = new File(fileDir + File.separator + fileNameVariants[i]);
     531            if (file.exists()) {
     532                return file;
     533            }
     534        }
     535        return null; // give up...
     536
     537    }
     538
     539    /**
     540     * Adds extended GPS data (*DOP and fix mode) to the way point
     541     *
     542     * @param csvLine
     543     * @param wpt
     544     */
     545    private void addExtendedGPSData(String[] csvLine, WayPoint wpt) {
     546        // Fix mode
     547        wpt.attr.put(FIX_TAG, csvLine[9].toLowerCase());
     548
     549        Float f;
     550        // Position errors (dop = dilution of position)
     551        f = ColumbusCSVUtils.floatFromString(csvLine[11]);
     552        if (f != Float.NaN) {
     553            wpt.attr.put(ColumbusCSVReader.PDOP_TAG, f);
     554        } else {
     555            dopConversionErrors++;
     556        }
     557
     558        f = ColumbusCSVUtils.floatFromString(csvLine[12]);
     559        if (f != Float.NaN) {
     560            wpt.attr.put(ColumbusCSVReader.HDOP_TAG, f);
     561        } else {
     562            dopConversionErrors++;
     563        }
     564
     565        f = ColumbusCSVUtils.floatFromString(csvLine[13]);
     566        if (f != Float.NaN) {
     567            wpt.attr.put(ColumbusCSVReader.VDOP_TAG, f);
     568        } else {
     569            dopConversionErrors++;
     570        }
     571    }
     572
     573    /**
     574     * Adds a link to a way point.
     575     *
     576     * @param wpt
     577     *            The way point to add the link to.
     578     * @param voxFile
     579     * @param file
     580     * @return True, if link has been added; otherwise false
     581     */
     582    public boolean addLinkToWayPoint(WayPoint wpt, String voxFile, File file) {
     583        if (file == null || wpt == null || voxFile == null)
     584            return false;
     585
     586        GpxLink lnk = new GpxLink(file.toURI().toString());
     587        lnk.type = ColumbusCSVReader.AUDIO_WAV_LINK;
     588        lnk.text = voxFile;
     589
     590        // JOSM expects a collection of links here...
     591        Collection<GpxLink> linkList = new ArrayList<GpxLink>(1);
     592        linkList.add(lnk);
     593
     594        wpt.attr.put(GpxData.META_LINKS, linkList);
     595        wpt.attr.put(ColumbusCSVReader.COMMENT_TAG, "Audio recording");
     596        wpt.attr.put(ColumbusCSVReader.DESC_TAG, voxFile);
     597        return true;
     598    }
     599
     600    /**
     601     * Splits a line of the CSV files into it's tokens.
     602     *
     603     * @param line
     604     * @return Array containing the tokens of the CSV file.
     605     */
     606    private static String[] getCSVLine(String line) {
     607        if (line == null || line.length() == 0)
     608            return EMPTY_LINE;
     609
     610        StringTokenizer st = new StringTokenizer(line, SEPS, false);
     611        int n = st.countTokens();
     612
     613        String[] res = new String[n];
     614        for (int i = 0; i < n; i++) {
     615            res[i] = st.nextToken().trim();
     616        }
     617        return res;
     618    }
     619
     620    /**
     621     * Extracts the number from a VOX file name, e. g. for a file named
     622     * "VOX01524" this method will return 1524.
     623     *
     624     * @param fileName
     625     *            The vox file name.
     626     * @return The number of the vox file or -1; if the given name was not
     627     *         valid.
     628     */
     629    private int getNumberOfVoxfile(String fileName) {
     630        if (fileName == null)
     631            return -1;
     632
     633        try {
     634            String num = fileName.substring(3);
     635            int val = Integer.parseInt(num);
     636            return val;
     637        } catch (NumberFormatException e) {
     638            return -1;
     639        }
     640    }
     641
     642    /**
     643     * Return the number of date conversion errors.
     644     *
     645     * @return
     646     */
     647    public int getNumberOfDateConversionErrors() {
     648        return dateConversionErrors;
     649    }
     650
     651    /**
     652     * Return the number of pdop/vdop/hdop conversion errors.
     653     *
     654     * @return
     655     */
     656    public int getNumberOfDOPConversionErrors() {
     657        return dopConversionErrors;
     658    }
     659
     660    /**
     661     * Gets the number of first vox file.
     662     *
     663     * @return
     664     */
     665    public int getFirstVoxNumber() {
     666        return firstVoxNumber;
     667    }
     668
     669    /**
     670     * Gets the number of last vox file.
     671     *
     672     * @return
     673     */
     674    public int getLastVoxNumber() {
     675        return lastVoxNumber;
     676    }
     677
     678    /**
     679     * Gets the map containing the vox files with their associated way point.
     680     *
     681     * @return
     682     */
     683    public HashMap<String, WayPoint> getVoxFileMap() {
     684        return voxFiles;
     685    }
     686
     687    /**
     688     * Gets the list containing all imported track and way points.
     689     *
     690     * @return
     691     */
     692    public List<WayPoint> getAllWayPoints() {
     693        return allWpts;
     694    }
     695
     696    /**
     697     * Gets the import directory.
     698     *
     699     * @return
     700     */
     701    public String getWorkingDirOfImport() {
     702        return fileDir;
     703    }
    617704}
Note: See TracChangeset for help on using the changeset viewer.