/************************************************************************ * * BatchConverter.java * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Copyright: 2002-2009 by Henrik Just * * All Rights Reserved. * * Version 1.0 (2009-02-16) * */ package org.openoffice.da.comp.writer2xhtml; import java.io.IOException; import java.io.OutputStream; import java.net.URI; import java.net.URISyntaxException; import com.sun.star.lib.uno.adapter.XInputStreamToInputStreamAdapter; import com.sun.star.lib.uno.adapter.XOutputStreamToOutputStreamAdapter; import com.sun.star.beans.PropertyValue; import com.sun.star.beans.UnknownPropertyException; import com.sun.star.beans.XPropertySet; import com.sun.star.document.XDocumentInfoSupplier; import com.sun.star.frame.XComponentLoader; import com.sun.star.frame.XStorable; import com.sun.star.io.NotConnectedException; import com.sun.star.io.XInputStream; import com.sun.star.io.XOutputStream; import com.sun.star.lang.WrappedTargetException; import com.sun.star.lang.XComponent; import com.sun.star.lang.XServiceInfo; import com.sun.star.lang.XServiceName; import com.sun.star.lang.XTypeProvider; import com.sun.star.sheet.XSpreadsheetDocument; import com.sun.star.text.XTextDocument; import com.sun.star.ucb.CommandAbortedException; import com.sun.star.ucb.XSimpleFileAccess2; import com.sun.star.uno.AnyConverter; import com.sun.star.uno.Type; import com.sun.star.uno.UnoRuntime; import com.sun.star.uno.XComponentContext; //import writer2latex.api.BatchConverter; //import writer2latex.api.BatchHandler; //import writer2latex.api.Converter; import writer2latex.api.ConverterFactory; import writer2latex.api.IndexPageEntry; import writer2latex.api.MIMETypes; import writer2latex.api.OutputFile; // Import interfaces as defined in uno idl import org.openoffice.da.writer2xhtml.XBatchConverter; import org.openoffice.da.writer2xhtml.XBatchHandler; import org.openoffice.da.comp.w2lcommon.helper.PropertyHelper; /** This class provides a uno component which implements the interface * org.openoffice.da.writer2xhtml.XBatchConverter */ public class BatchConverter implements XBatchConverter, XServiceName, XServiceInfo, XTypeProvider { /** The component will be registered under this name. */ public static final String __serviceName = "org.openoffice.da.writer2xhtml.BatchConverter"; public static final String __implementationName = "org.openoffice.da.comp.writer2xhtml.BatchConverter"; private XComponentContext xComponentContext = null; private XSimpleFileAccess2 sfa2 = null; private writer2latex.api.BatchConverter batchConverter = null; private XBatchHandler handler; // Based on convert arguments private boolean bRecurse = true; private String sWriterFilterName = "org.openoffice.da.writer2xhtml"; private Object writerFilterData = null; private String sCalcFilterName = "org.openoffice.da.calc2xhtml"; private Object calcFilterData = null; private boolean bIncludePdf = true; private boolean bIncludeOriginal = false; private boolean bUseTitle = true; private boolean bUseDescription = true; private String sUplink = ""; private String sDirectoryIcon = ""; private String sDocumentIcon = ""; private String sTemplateURL = null; public BatchConverter(XComponentContext xComponentContext) { this.xComponentContext = xComponentContext; // Get the SimpleFileAccess service try { Object sfaObject = xComponentContext.getServiceManager().createInstanceWithContext( "com.sun.star.ucb.SimpleFileAccess", xComponentContext); sfa2 = (XSimpleFileAccess2) UnoRuntime.queryInterface(XSimpleFileAccess2.class, sfaObject); } catch (com.sun.star.uno.Exception e) { // failed to get SimpleFileAccess service (should not happen) } } // Helper: Get a string from an any private String getValue(Object any) { if (AnyConverter.isString(any)) { try { return AnyConverter.toString(any); } catch (com.sun.star.lang.IllegalArgumentException e) { return ""; } } else { return ""; } } // Implementation of XBatchConverter: public void convert(String sSourceURL, String sTargetURL, PropertyValue[] lArguments, XBatchHandler handler) { // Create batch converter (currently we don't need to set a converter) batchConverter = ConverterFactory.createBatchConverter(MIMETypes.XHTML); this.handler = handler; // Read the arguments int nSize = lArguments.length; for (int i=0; i<nSize; i++) { String sName = lArguments[i].Name; Object value = lArguments[i].Value; if ("Recurse".equals(sName)) { bRecurse = !"false".equals(getValue(value)); } else if ("IncludePdf".equals(sName)) { bIncludePdf = !"false".equals(getValue(value)); } else if ("IncludeOriginal".equals(sName)) { bIncludeOriginal = "true".equals(getValue(value)); } else if ("UseTitle".equals(sName)) { bUseTitle = !"false".equals(getValue(value)); } else if ("UseDescription".equals(sName)) { bUseDescription = !"false".equals(getValue(value)); } else if ("Uplink".equals(sName)) { sUplink = getValue(value); } else if ("DirectoryIcon".equals(sName)) { sDirectoryIcon = getValue(value); } else if ("DocumentIcon".equals(sName)) { sDocumentIcon = getValue(value); } else if ("TemplateURL".equals(sName)) { sTemplateURL = getValue(value); } else if ("WriterFilterName".equals(sName)) { sWriterFilterName = getValue(value); } else if ("WriterFilterData".equals(sName)) { writerFilterData = lArguments[i].Value; } else if ("CalcFilterName".equals(sName)) { sCalcFilterName = getValue(value); } else if ("CalcFilterData".equals(sName)) { calcFilterData = lArguments[i].Value; } } // Set arguments on batch converter batchConverter.getConfig().setOption("uplink", sUplink); batchConverter.getConfig().setOption("directory_icon", sDirectoryIcon); batchConverter.getConfig().setOption("document_icon", sDocumentIcon); if (sTemplateURL!=null) { try { XInputStream xis = sfa2.openFileRead(sTemplateURL); XInputStreamToInputStreamAdapter isa = new XInputStreamToInputStreamAdapter(xis); batchConverter.readTemplate(isa); } catch (IOException e) { // The batchconverter failed to read the template } catch (CommandAbortedException e) { // The sfa could not execute the command } catch (com.sun.star.uno.Exception e) { // Unspecified uno exception } } // Convert the directory handler.startConversion(); convertDirectory(sSourceURL, sTargetURL, getName(sSourceURL)); handler.endConversion(); } // Convert a directory - return true if not cancelled private boolean convertDirectory(String sSourceURL, String sTargetURL, String sHeading) { handler.startDirectory(sSourceURL); // Step 1: Get the directory String[] contents; try { contents = sfa2.getFolderContents(sSourceURL, true); } catch (CommandAbortedException e) { handler.endDirectory(sSourceURL,false); return true; } catch (com.sun.star.uno.Exception e) { handler.endDirectory(sSourceURL,false); return true; } int nLen = contents.length; IndexPageEntry[] entries = new IndexPageEntry[nLen]; // Step 2: Traverse subdirectories, if allowed if (bRecurse) { String sUplink = batchConverter.getConfig().getOption("uplink"); for (int i=0; i<nLen; i++) { boolean bIsDirectory = false; try { bIsDirectory = sfa2.isFolder(contents[i]); } catch (CommandAbortedException e) { // Considered non critical, ignore } catch (com.sun.star.uno.Exception e) { // Considered non critical, ignore } if (bIsDirectory) { batchConverter.getConfig().setOption("uplink","../index.html"); String sNewTargetURL = ensureSlash(sTargetURL) + getName(contents[i]); String sNewHeading = sHeading + " - " + decodeURL(getName(contents[i])); boolean bResult = convertDirectory(contents[i],sNewTargetURL,sNewHeading); batchConverter.getConfig().setOption("uplink", sUplink); if (!bResult) { return false; } // Create entry for this subdirectory IndexPageEntry entry = new IndexPageEntry(ensureSlash(sNewTargetURL)+"index.html",true); entry.setDisplayName(decodeURL(getName(contents[i]))); entries[i]=entry; } } } // Step 3: Traverse documents for (int i=0; i<nLen; i++) { boolean bIsFile = false; try { bIsFile = sfa2.exists(contents[i]) && !sfa2.isFolder(contents[i]); } catch (CommandAbortedException e) { // Considered non critical, ignore } catch (com.sun.star.uno.Exception e) { // Considered non critical, ignore } if (bIsFile) { IndexPageEntry entry = convertFile(contents[i],sTargetURL); if (entry!=null) { entries[i]=entry; } if (handler.cancel()) { return false; } } } // Step 4: Create and write out the index file OutputFile indexFile = batchConverter.createIndexFile(sHeading, entries); try { if (!sfa2.exists(sTargetURL)) { sfa2.createFolder(sTargetURL); } } catch (CommandAbortedException e) { handler.endDirectory(sSourceURL,false); return true; } catch (com.sun.star.uno.Exception e) { handler.endDirectory(sSourceURL,false); return true; } try { // writeFile demands an InputStream, so we need a pipe Object xPipeObj=xComponentContext.getServiceManager().createInstanceWithContext( "com.sun.star.io.Pipe",xComponentContext); XInputStream xInStream = (XInputStream) UnoRuntime.queryInterface(XInputStream.class, xPipeObj ); XOutputStream xOutStream = (XOutputStream) UnoRuntime.queryInterface(XOutputStream.class, xPipeObj ); OutputStream outStream = new XOutputStreamToOutputStreamAdapter(xOutStream); // Feed the pipe with content... indexFile.write(outStream); outStream.flush(); outStream.close(); xOutStream.closeOutput(); // ...and then write the content to the url sfa2.writeFile(ensureSlash(sTargetURL)+"index.html",xInStream); } catch (IOException e) { handler.endDirectory(sSourceURL,false); return true; } catch (NotConnectedException e) { handler.endDirectory(sSourceURL,false); return true; } catch (com.sun.star.uno.Exception e) { handler.endDirectory(sSourceURL,false); return true; } handler.endDirectory(sSourceURL, true); return !handler.cancel(); } private IndexPageEntry convertFile(String sSourceFileURL, String sTargetURL) { handler.startFile(sSourceFileURL); String sTargetFileURL = ensureSlash(sTargetURL) + getBaseName(sSourceFileURL) + ".html"; IndexPageEntry entry = new IndexPageEntry(getName(sTargetFileURL),false); entry.setDisplayName(decodeURL(getBaseName(sTargetFileURL))); // Load component XComponent xDocument; try { Object desktop = xComponentContext.getServiceManager().createInstanceWithContext( "com.sun.star.frame.Desktop", xComponentContext); XComponentLoader xComponentLoader = (XComponentLoader) UnoRuntime.queryInterface(XComponentLoader.class, desktop); PropertyValue[] fileProps = new PropertyValue[1]; fileProps[0] = new PropertyValue(); fileProps[0].Name = "Hidden"; fileProps[0].Value = new Boolean(true); xDocument = xComponentLoader.loadComponentFromURL(sSourceFileURL, "_blank", 0, fileProps); } catch (com.sun.star.io.IOException e) { handler.endFile(sSourceFileURL,false); return null; } catch (com.sun.star.uno.Exception e) { handler.endFile(sSourceFileURL,false); return null; } // Get the title and the description of the document XDocumentInfoSupplier docInfo = (XDocumentInfoSupplier) UnoRuntime.queryInterface(XDocumentInfoSupplier.class, xDocument); XPropertySet infoProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, docInfo.getDocumentInfo()); if (infoProps!=null) { try { Object loadedTitle = infoProps.getPropertyValue("Title"); if (AnyConverter.isString(loadedTitle)) { String sLoadedTitle = AnyConverter.toString(loadedTitle); if (bUseTitle && sLoadedTitle.length()>0) { entry.setDisplayName(sLoadedTitle); } } Object loadedDescription = infoProps.getPropertyValue("Description"); if (AnyConverter.isString(loadedDescription)) { String sLoadedDescription = AnyConverter.toString(loadedDescription); if (bUseDescription && sLoadedDescription.length()>0) { entry.setDescription(sLoadedDescription); } } } catch (UnknownPropertyException e) { } catch (WrappedTargetException e) { } catch (com.sun.star.lang.IllegalArgumentException e) { } } // Determine the type of the component boolean bText = false; boolean bSpreadsheet = false; if (UnoRuntime.queryInterface(XTextDocument.class, xDocument)!=null) { bText=true; } else if (UnoRuntime.queryInterface(XSpreadsheetDocument.class, xDocument)!=null) { bSpreadsheet=true; } if (!bText && !bSpreadsheet) { handler.endFile(sSourceFileURL,false); xDocument.dispose(); return null; } // Convert using requested filter boolean bHtmlSuccess = true; PropertyHelper exportProps = new PropertyHelper(); exportProps.put("FilterName", bText ? sWriterFilterName : sCalcFilterName); exportProps.put("Overwrite", new Boolean(true)); if (bText && writerFilterData!=null) { exportProps.put("FilterData", writerFilterData); } if (bSpreadsheet && calcFilterData!=null) { exportProps.put("FilterData", calcFilterData); } try { XStorable xStore = (XStorable) UnoRuntime.queryInterface (XStorable.class, xDocument); xStore.storeToURL (sTargetFileURL, exportProps.toArray()); } catch (com.sun.star.io.IOException e) { // Failed to convert; continue anyway, but don't link to the file name entry.setFile(null); bHtmlSuccess = false; } // Convet to pdf if requested boolean bPdfSuccess = true; if (bIncludePdf) { PropertyValue[] pdfProps = new PropertyValue[2]; pdfProps[0] = new PropertyValue(); pdfProps[0].Name = "FilterName"; pdfProps[0].Value = bText ? "writer_pdf_Export" : "calc_pdf_Export"; pdfProps[1] = new PropertyValue(); pdfProps[1].Name = "Overwrite"; pdfProps[1].Value = new Boolean(true); String sPdfFileURL = ensureSlash(sTargetURL) + getBaseName(sSourceFileURL) + ".pdf"; try { XStorable xStore = (XStorable) UnoRuntime.queryInterface (XStorable.class, xDocument); xStore.storeToURL (sPdfFileURL, pdfProps); entry.setPdfFile(sPdfFileURL); } catch (com.sun.star.io.IOException e) { // Not critical, continue without pdf bPdfSuccess = false; } } xDocument.dispose(); // Include original document if required if (bIncludeOriginal) { // TODO } // Report a failure to the user if either of the exports failed handler.endFile(sSourceFileURL,bHtmlSuccess && bPdfSuccess); // But return the index entry even if only one succeded if (bHtmlSuccess || bPdfSuccess) { return entry; } else { return null; } } private String getName(String sURL) { int n = sURL.lastIndexOf("/"); return n>-1 ? sURL.substring(n+1) : sURL; } private String getBaseName(String sURL) { String sName = getName(sURL); int n = sName.lastIndexOf("."); return n>-1 ? sName.substring(0,n) : sName; } private String ensureSlash(String sURL) { return sURL.endsWith("/") ? sURL : sURL+"/"; } private String decodeURL(String sURL) { try { return new URI(sURL).getPath(); } catch (URISyntaxException e) { return sURL; } } // Implement methods from interface XTypeProvider public com.sun.star.uno.Type[] getTypes() { Type[] typeReturn = {}; try { typeReturn = new Type[] { new Type( XBatchConverter.class ), new Type( XTypeProvider.class ), new Type( XServiceName.class ), new Type( XServiceInfo.class ) }; } catch( Exception exception ) { } return( typeReturn ); } public byte[] getImplementationId() { byte[] byteReturn = {}; byteReturn = new String( "" + this.hashCode() ).getBytes(); return( byteReturn ); } // Implement method from interface XServiceName public String getServiceName() { return( __serviceName ); } // Implement methods from interface XServiceInfo public boolean supportsService(String stringServiceName) { return( stringServiceName.equals( __serviceName ) ); } public String getImplementationName() { return( __implementationName ); } public String[] getSupportedServiceNames() { String[] stringSupportedServiceNames = { __serviceName }; return( stringSupportedServiceNames ); } }