/* GNU General Public License CacheWolf is a software for PocketPC, Win and Linux that enables paperless caching. It supports the sites geocaching.com and opencaching.de Copyright (C) 2006 CacheWolf development team See http://www.cachewolf.de/ for more information. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package CacheWolf.exp; import com.stevesoft.ewe_pat.Regex; import com.stevesoft.ewe_pat.Transformer; import CacheWolf.MainForm; import CacheWolf.Preferences; import CacheWolf.controls.InfoBox; import CacheWolf.database.CacheHolder; import CacheWolf.database.CacheSize; import CacheWolf.database.CacheType; import CacheWolf.navi.TransformCoordinates; import CacheWolf.utils.MyLocale; import ewe.filechooser.FileChooser; import ewe.filechooser.FileChooserBase; import ewe.io.BufferedWriter; import ewe.io.File; import ewe.io.FileWriter; import ewe.io.IOException; import ewe.io.JavaUtf8Codec; import ewe.io.PrintWriter; import ewe.io.TextCodec; import ewe.sys.Handle; import ewe.ui.FormBase; import ewe.ui.ProgressBarForm; import ewe.util.Hashtable; import ewe.util.Vector; /** * @author Kalle * Base class for exporter, handles basic things like selecting outputfile, display a counter etc. * * setExportMethod must be called with to identify which method should be called. * A new Exporter must only override the header(), record() and trailer() methods, corresponding to the setExportMethod. * */ public class Exporter { // export methods final static int EXPORT_METHOD_NO_PARAMS = 0; final static int EXPORT_METHOD_LAT_LON = 1; final static int EXPORT_METHOD_COUNT = 2; Vector DB; // mask in file chooser String outputFileExtension = "*.*"; String outputFileName; // decimal separator for lat- and lon-String char decimalSeparator = '.'; // selection, which export method should be called int recordMethod; int incompleteWaypoints = 0; // name of exporter for saving pathname and its preferences protected String exporterName; protected TextCodec useCodec; protected int anzVisibleCaches; int doneTillNow; protected PrintWriter outWriter; ProgressBarForm pbf = new ProgressBarForm(); Handle h = new Handle(); protected File outFile = null; public Exporter() { recordMethod = EXPORT_METHOD_LAT_LON; exporterName = this.getClass().getName(); // remove package and path from Classname int ab = exporterName.lastIndexOf(".") + 1; exporterName = exporterName.substring(ab); useCodec = new JavaUtf8Codec(); anzVisibleCaches = MainForm.profile.cacheDB.countVisible(); doneTillNow = 0; } /** * Does the work for exporting data * */ public void doIt() { doItStart(); export(); doItEnd(); } public void doItStart() { pbf.showMainTask = false; pbf.setTask(h, "Exporting ..."); pbf.exec(); } public void doItEnd() { pbf.exit(0); if (incompleteWaypoints > 0) { new InfoBox(MyLocale.getMsg(5500, "Error"), incompleteWaypoints + " incomplete waypoints have not been exported. See log for details.").wait(FormBase.OKB); } } /** * Do one File export, can be overwritten * */ public void export() { if (DB == null) { DB = MainForm.profile.cacheDB.getVectorDB(); } if (outFile == null) { askForOutputFile(); if (outFile == null) return; } exportHeader(); exportBody(); exportTrailer(); } public void exportHeader() { try { FileWriter fw = new FileWriter(outFile); fw.codec = this.useCodec; outWriter = new PrintWriter(new BufferedWriter(fw)); } catch (IOException ioE) { Preferences.itself().log("Error opening " + outputFileName, ioE); } String str = this.header(); if (str != null) outWriter.write(str); } public void exportBody() { exportCaches(); } public void exportTrailer() { String str; switch (this.recordMethod & EXPORT_METHOD_COUNT) { case EXPORT_METHOD_NO_PARAMS: str = trailer(); break; case EXPORT_METHOD_COUNT: str = trailer(anzVisibleCaches); break; default: str = null; break; } if (str != null) outWriter.write(str); outWriter.close(); } private void exportCaches() { String str; for (int i = 0; i < DB.size(); i++) { str = exportCache(i); if (str != null) { h.progress = (float) doneTillNow / (float) anzVisibleCaches; h.changed(); outWriter.write(str); } } } private String exportCache(int i) { CacheHolder ch = (CacheHolder) DB.get(i); String str = null; if (ch.isVisible()) { doneTillNow++; if (ch.isIncomplete()) { Preferences.itself().log("Incomplete waypoint " + ch.getCode(), null); incompleteWaypoints++; return null; } else { switch (this.recordMethod) { case EXPORT_METHOD_NO_PARAMS: str = record(ch); break; case EXPORT_METHOD_LAT_LON: if (!ch.getWpt().isValid()) return null; str = record(ch, ch.getWpt().getLatDeg(TransformCoordinates.DD).replace('.', this.decimalSeparator), ch.getWpt().getLonDeg(TransformCoordinates.DD).replace('.', this.decimalSeparator)); break; case EXPORT_METHOD_LAT_LON | EXPORT_METHOD_COUNT: if (!ch.getWpt().isValid()) return null; str = record(ch, ch.getWpt().getLatDeg(TransformCoordinates.DD).replace('.', this.decimalSeparator), ch.getWpt().getLonDeg(TransformCoordinates.DD).replace('.', this.decimalSeparator), i); break; default: str = null; break; } } // else if incomplete } // if visible return str; } /** * sets mask for filechooser * * @param mask */ public void setOutputFileExtension(String mask) { this.outputFileExtension = mask; } /** * sets ExportMethod * * @param paramBits */ public void setExportMethod(int paramBits) { this.recordMethod = paramBits; } /** * sets tmpFileName * * @param fName */ public void setOutputFile(String fName) { this.outputFileName = fName; outFile = new File(outputFileName); } /** * uses a filechooser to get the name of the export file * * @return */ public void askForOutputFile() { File file; FileChooser fc = new FileChooser(FileChooserBase.SAVE, Preferences.itself().getExportPath(exporterName + "-path")); fc.setTitle(MyLocale.getMsg(2102, "Choose target file")); fc.addMask(outputFileExtension); if (fc.execute() != FormBase.IDCANCEL) { file = fc.getChosenFile(); this.outputFileName = fc.getChosen(); Preferences.itself().setExportPref(exporterName + "-path", file.getPath()); outFile = file; } else { outFile = null; } } public String getOutputPath() { FileChooser fc = new FileChooser(FileChooserBase.DIRECTORY_SELECT, Preferences.itself().getExportPath(exporterName + "-path")); fc.setTitle(MyLocale.getMsg(148, "Select Target directory")); String targetDir; if (fc.execute() == FormBase.IDCANCEL) return ""; targetDir = fc.getChosen() + "/"; Preferences.itself().setExportPref(exporterName + "-path", targetDir); return targetDir; } /** * this method can be overided by an exporter class * * @return formated header data */ public String header() { return null; } /** * this method can be overided by an exporter class * * @param ch * cachedata * @return formated cache data */ public String record(CacheHolder chD) { return null; } /** * this method can be overided by an exporter class * * @param ch * cachedata * @param lat * @param lon * @return formated cache data */ public String record(CacheHolder ch, String lat, String lon) { return null; } /** * this method can be overided by an exporter class * * @param ch * cachedata * @param lat * @param lon * @param count * of actual record * @return formated cache data */ public String record(CacheHolder ch, String lat, String lon, int count) { return null; } /** * this method can be overided by an exporter class * * @return formated trailer data */ public String trailer() { return null; } /** * this method can be overided by an exporter class * * @param total * count of exported caches * @return */ public String trailer(int total) { return null; } // ///////////////////////////////////////////////// // Helper functions for string sanitisation // ///////////////////////////////////////////////// private static Hashtable iso2simpleMappings = new Hashtable(250); // ISO-8859-1 is CP1252 without chars 80-9f (=128..159) which is = 00..1f // will be converted to ISO-646 ( = ASCII, or US-ASCII) static { String[] mappingArray = new String[] { "34", "'", // "160", " ", "161", "i", "162", "c", "163", "$", "164", "o", "165", "$", "166", "!", "167", "$", "168", " ", "169", " ", // "170", " ", "171", "<", "172", " ", "173", "-", "174", " ", "175", "-", "176", " ", "177", "+/-", "178", "2", "179", "3", // "180", "'", "181", " ", "182", " ", "183", " ", "184", ",", "185", "1", "186", " ", "187", ">", "188", "1/4", "189", "1/2", // "190", "3/4", "191", "?", "192", "A", "193", "A", "194", "A", "195", "A", "196", "Ae", "197", "A", "198", "AE", "199", "C", // "200", "E", "201", "E", "202", "E", "203", "E", "204", "I", "205", "I", "206", "I", "207", "I", "208", "D", "209", "N", // "210", "O", "211", "O", "212", "O", "213", "O", "214", "Oe", "215", "x", "216", "O", "217", "U", "218", "U", "219", "U", // "220", "Ue", "221", "Y", "222", " ", "223", "ss", "224", "a", "225", "a", "226", "a", "227", "a", "228", "ae", "229", "a", // "230", "ae", "231", "c", "232", "e", "233", "e", "234", "e", "235", "e", "236", "i", "237", "i", "238", "i", "239", "i", // "240", "o", "241", "n", "242", "o", "243", "o", "244", "o", "245", "o", "246", "oe", "247", "/", "248", "o", "249", "u", // "250", "u", "251", "u", "252", "ue", "253", "y", "254", "p", "255", "y" }; for (int i = 0; i < mappingArray.length; i = i + 2) { iso2simpleMappings.put(Integer.valueOf(mappingArray[i]), mappingArray[i + 1]); } } protected static String char2simpleChar(char c) { if (c < 127) { // leave alone as equivalent string. return null; } else { String s = (String) iso2simpleMappings.get(new Integer(c)); if (s == null) // 127..159 not in table, replace with empty string return ""; else return s; } } // end charToEntity public static String simplifyString(String text) { if (text == null) return null; int originalTextLength = text.length(); StringBuffer sb = new StringBuffer(50); int charsToAppend = 0; for (int i = 0; i < originalTextLength; i++) { char c = text.charAt(i); String entity = char2simpleChar(c); if (entity == null) { // we could sb.append( c ), but that would be slower // than saving them up for a big append. charsToAppend++; } else { if (charsToAppend != 0) { sb.append(text.substring(i - charsToAppend, i)); charsToAppend = 0; } sb.append(entity); } } // end for // append chars to the right of the last entity. if (charsToAppend != 0) { sb.append(text.substring(originalTextLength - charsToAppend, originalTextLength)); } // if result is not longer, we did not do anything. Save RAM. return (sb.length() == originalTextLength) ? text : sb.toString(); } // end insertEntities public static String getShortDetails(CacheHolder ch) { StringBuffer strBuf = new StringBuffer(7); strBuf.append(CacheType.getExportShortId(ch.getType()).toLowerCase()); if (!ch.isAddiWpt()) { strBuf.append(ch.getDifficulty()); strBuf.append("/"); strBuf.append(ch.getTerrain()); strBuf.append(CacheSize.getExportShortId(ch.getSize())); } return strBuf.toString(); } protected String removeHtmlTags(String inString) { Transformer removeNumericEntities = new Transformer(true); removeNumericEntities.add(new Regex("&#([xX]?)([a-fA-F0-9]*?);", "")); Transformer handleLinebreaks = new Transformer(true); handleLinebreaks.add(new Regex("\r", "")); handleLinebreaks.add(new Regex("\n", " ")); handleLinebreaks.add(new Regex("<br>", "\n")); handleLinebreaks.add(new Regex("<p>", "\n")); handleLinebreaks.add(new Regex("<hr>", "\n")); handleLinebreaks.add(new Regex("<br />", "\n")); Transformer removeHTMLTags = new Transformer(true); removeHTMLTags.add(new Regex("<(.*?)>", "")); return removeHTMLTags.replaceAll(handleLinebreaks.replaceAll(removeNumericEntities.replaceAll(inString))); } }