From a50dad69f435084ae55778f1d8c4127332e8834d Mon Sep 17 00:00:00 2001 From: henrikjust Date: Fri, 10 Oct 2014 13:51:02 +0000 Subject: [PATCH] First draft of w2l toolbar git-svn-id: svn://svn.code.sf.net/p/writer2latex/code/trunk@184 f0f2a975-2e09-46c8-9428-3b39399b9f3c --- source/distro/changelog.txt | 125 +----- .../w2lcommon/filter/ExportFilterBase.java | 220 +---------- .../comp/w2lcommon/filter/UNOConverter.java | 255 +++++++++++++ .../da/comp/writer2latex/W2LExportFilter.java | 5 +- .../da/comp/writer2xhtml/W2XExportFilter.java | 5 +- .../da/comp/writer2xhtml/W2XRegistration.java | 12 +- .../da/comp/writer2xhtml/Writer2xhtml.java | 358 ++++++++++++++++++ source/java/writer2latex/util/Misc.java | 9 +- source/oxt/writer2xhtml/Addons.xcu | 47 +++ source/oxt/writer2xhtml/META-INF/manifest.xml | 12 + .../Office/UI/WriterWindowState.xcu | 15 + source/oxt/writer2xhtml/ProtocolHandler.xcu | 12 + source/oxt/writer2xhtml/icons/epub_16.bmp | Bin 0 -> 890 bytes source/oxt/writer2xhtml/icons/epub_16h.bmp | Bin 0 -> 890 bytes source/oxt/writer2xhtml/icons/epub_26.bmp | Bin 0 -> 2202 bytes source/oxt/writer2xhtml/icons/epub_26h.bmp | Bin 0 -> 2202 bytes source/oxt/writer2xhtml/icons/html5_16.bmp | Bin 0 -> 890 bytes source/oxt/writer2xhtml/icons/html5_16h.bmp | Bin 0 -> 890 bytes source/oxt/writer2xhtml/icons/html5_26.bmp | Bin 0 -> 2202 bytes source/oxt/writer2xhtml/icons/html5_26h.bmp | Bin 0 -> 2202 bytes 20 files changed, 738 insertions(+), 337 deletions(-) create mode 100644 source/java/org/openoffice/da/comp/w2lcommon/filter/UNOConverter.java create mode 100644 source/java/org/openoffice/da/comp/writer2xhtml/Writer2xhtml.java create mode 100644 source/oxt/writer2xhtml/Addons.xcu create mode 100644 source/oxt/writer2xhtml/Office/UI/WriterWindowState.xcu create mode 100644 source/oxt/writer2xhtml/ProtocolHandler.xcu create mode 100644 source/oxt/writer2xhtml/icons/epub_16.bmp create mode 100644 source/oxt/writer2xhtml/icons/epub_16h.bmp create mode 100644 source/oxt/writer2xhtml/icons/epub_26.bmp create mode 100644 source/oxt/writer2xhtml/icons/epub_26h.bmp create mode 100644 source/oxt/writer2xhtml/icons/html5_16.bmp create mode 100644 source/oxt/writer2xhtml/icons/html5_16h.bmp create mode 100644 source/oxt/writer2xhtml/icons/html5_26.bmp create mode 100644 source/oxt/writer2xhtml/icons/html5_26h.bmp diff --git a/source/distro/changelog.txt b/source/distro/changelog.txt index de4e73a..3e4a1c7 100644 --- a/source/distro/changelog.txt +++ b/source/distro/changelog.txt @@ -1,124 +1,7 @@ -Changelog for Writer2LaTeX version 1.2 -> 1.4 +Changelog for Writer2LaTeX version 1.4 -> 1.6 ----------- version 1.4 beta ---------- +---------- version 1.5.1 ---------- -[w4l] Zotero BibTeX exporter is updated to the latest version +[w2x] Added toolbar with two buttons to publish directly to XHTML/EPUB. -[all] Build file is now set up to cross compile for java 6 - -[w2x] If the export dialogs are loaded with a setting for scaling or column_scaling of 1% or less, the value - is reset to 100%. This is a workaround for an obscure bug in the extension manager, which in some cases sets - the value to 1% if the export is used right after installation. - -[w2x] Bugfix: The help button on the EPUB export dialog now works - -[w2x] Bugfix: Avoid null pointer exception in HTML5 export if embed_svg is true and an image is used more than once - -[all] An image that is used more than once in the source document is now only exported once. This was already the - case for the package format (since 1.3.2), but now also for flat XML. - -[w2x] The The option inline_svg has been renamed (again) to embed_svg, and the default is changed to false - -[w2x] The experimental option zen_hack has been removed - -[w2x] For templates it is no longer required that the footer, header and panel are contained in a div element. - This allows for HTML5 code like
. The default header and footer - are now created with header+nav and footer+nav elements if the target format is HTML5. - ----------- version 1.3.2 alpha ---------- - -[w2l] Two or more span elements in a row which generates identical formatting in LaTeX are now merged. - This avoids constructs like \textbf{this is }\textbf{bold}. - -[w2l] Optimization: The SimpleDomBuilder now merges text nodes - -[w2l] Replace usage of StringBuffer with StringBuilder everywhere (marginal optimization) - -[w2l] The standard configurations pdfprint.xml and pdfscreen.xml no longer requires ooomath.sty - -[w2l] A bookmark in a heading no longer results in an optional argument to \section commands - -[w2l] New option display_hidden_text (default false) to toggle whether or not hidden text should be included in - the export. In the export filter, this option can be toggled in the export options dialog. - -[w2l] Bugfix (StarMath conversion): The five colors red, green, blue, magenta and yellow is now exported to the - correct dark colors rather than the previous bright colors (the colors white, black and yellow are unchanged) - -[w2x] If a border has a width which is equivalent to less that 1px, it is now exported with the width 1px. - This fixes an issue with some browsers, that would render the border invisible. - -[w2x] Two or more span elements in a row with identical attributes are now merged - -[all] Filters: Appended [Writer2LaTeX] or [Writer2xhtml] to all filter UI names to make them more visible - -[w2l] Bugfix: Avoid null pointer exception caused by list styles in some cases - -[w2x] Bugfix: EPUB export filter works again (was broken in 1.3.1) - -[w2x] Bugfix: Text boxes are no longer lost if within a paragraph - -[w2x] SVG support in HTML5 is now finished: Images in SVG format are kept in the original format. - Other vector images are converted to SVG (filter only). This only works with recent versions of the office - (LO 4.2 and AOO 4.1 are known to work). The option use_svg has been renamed to inline_svg. If set to - true (default) inline SVG is used, if set to false, external SVG-files (img-elements) are used. - In the UI, this setting can be found on the options page Writer2xhtml - Content. - -[all] If an image image cannot be converted to an acceptable format, the optional alternative image will now be tried - -[all] Bugfix: Avoid null pointer exception if a table has no defined table width - -[w2l] Bugfix (StarMath conversion): Protect the character [ after \\ in gather and matrix environments - -[w2l] Bugfix: Protect the character [ after \\ in tables - -[w2l] Bugfix (StarMath conversion): Usage of \multiscripts and \mathoverstrike now loads the required calc.sty - -[w2l] Bugfix (StarMath conversion): Do not create display equations in table cells - -[w2l] Bugfix (StarMath conversion): Set the counter MaxMatrixCols if there are matrices with more than 10 columns - -[w2l] Bugfix (StarMath conversion): Add braces if the argument to a command is a space, e.g. \text{ } - -[all] Refactored and optimized memory usage of image conversion - -[all] Refactored and rearranged some code; in particular the last remaining bits of the old xmerge framework has been removed - -[all] Optimized reading of package format: The settings.xml files are not parsed and the unused parts of the ZIP file are disposed - ----------- version 1.3.1 alpha ---------- - -[w2x] Starting with version 4.2, LibreOffice exports display="math" on display equations. This attribute is now - removed if a display equation is used inline in the source document. - -[w2x] Support for the obsolete output format XHTML+MahtML+XSL has been removed (replaced by MathJax). As a consequence - the option xslt_path has been removed. Also the vacant spot in the export dialog is now used for the option use_mathjax - (only active for XHTML+MathML and HTML5) - -[all] Added support for TexMaths equations in LaTeX, XHTML+MathML and HTML5 (the last two only if use_mathjax=true) - -[all] The command line application now gives an explanation if the source file is not in ODF format - -[all] Bugfix: Fixed typo that caused writer2latex.office.MIMETypes.getMagicMIMEType() to fail in some cases - -[w2x] The option ignore_table_dimensions has been replaced by a new option table_size with values none (do not export table - dimensions), relative (always use relative width) and auto (use the formatting of the source document): - If set to true, all tables are exported with relative width, even if they have an absolute width in the source document - -[w2x] New boolean option use_mathjax (default false): If set to true and export format is XHTML+MATHML or HTML5, - documents will load the MathJax JavaScript library for rendering of formulas (otherwise the document will rely - on native MathML support in the browser) - -[w2x] New boolean option use_svg (default false): If set to true and export format is HTML5, vector graphics are exported as - inline SVG, if possible - -[w2x] Added support for HTML5 as export type (the ConverterFactory understands the pseudo-MIME type text/html5). - The converter creates polyglot HTML5 documents, i.e. documents will be conforming to HTML5 as well as XML standards. - -[all] Optimized the parsing of the source document saving some time and space (several intermediate steps and large byte arrays - are now avoided) - -[all] API change: The converters can now convert directly from a DOM tree - -[all] Removed unused code in writer2latex.xmerge - -[w2x] Moved localized strings to .properties files \ No newline at end of file +[all] Filter: Refactored filter code, the actual conversion has been separated from the XExportFilter implementation \ No newline at end of file diff --git a/source/java/org/openoffice/da/comp/w2lcommon/filter/ExportFilterBase.java b/source/java/org/openoffice/da/comp/w2lcommon/filter/ExportFilterBase.java index a67726f..07dd69a 100644 --- a/source/java/org/openoffice/da/comp/w2lcommon/filter/ExportFilterBase.java +++ b/source/java/org/openoffice/da/comp/w2lcommon/filter/ExportFilterBase.java @@ -20,38 +20,24 @@ * * All Rights Reserved. * - * Version 1.4 (2014-08-28) + * Version 1.6 (2014-10-06) * */ package org.openoffice.da.comp.w2lcommon.filter; -import com.sun.star.lib.uno.adapter.XOutputStreamToOutputStreamAdapter; - -import com.sun.star.io.XInputStream; -import com.sun.star.io.XOutputStream; -import com.sun.star.lang.XMultiServiceFactory; import com.sun.star.lang.XServiceInfo; import com.sun.star.lang.XServiceName; import com.sun.star.lang.XTypeProvider; -import com.sun.star.uno.AnyConverter; -import com.sun.star.ucb.XSimpleFileAccess2; import com.sun.star.uno.Type; -import com.sun.star.uno.UnoRuntime; import com.sun.star.uno.XComponentContext; import com.sun.star.xml.sax.XDocumentHandler; import com.sun.star.xml.XExportFilter; import org.openoffice.da.comp.w2lcommon.helper.MessageBox; -import writer2latex.api.Converter; -import writer2latex.api.ConverterFactory; -import writer2latex.api.OutputFile; -import writer2latex.util.Misc; import writer2latex.util.SimpleDOMBuilder; import java.io.IOException; -import java.io.OutputStream; -import java.util.Iterator; /** This class provides an abstract UNO component which implements an XExportFilter. @@ -74,96 +60,29 @@ XTypeProvider { /** Filter name to include in error messages */ public String __displayName = ""; - private static XComponentContext xComponentContext = null; - protected static XMultiServiceFactory xMSF; + private XComponentContext xComponentContext = null; private SimpleDOMBuilder domBuilder = new SimpleDOMBuilder(); - private static XOutputStream xos = null; - private static String sdMime=null; - private static String sURL=""; + private UNOConverter converter = null; - private Object filterData; - private XSimpleFileAccess2 sfa2; - - /** We need to get the Service Manager from the Component context to - * instantiate certain services, hence this constructor. - * The subclass must override this to set xMSF properly from the registration class + /** Construct a new ExportFilterBase from a given component context + * + * @param xComponentContext the component context used to instantiate new UNO services */ - public ExportFilterBase(XComponentContext xComponentContext1) { - xComponentContext = xComponentContext1; - xMSF = null; + public ExportFilterBase(XComponentContext xComponentContext) { + this.xComponentContext = xComponentContext; } - // Utility method: - - String getFileName(String origName) { - String name=null; - if (origName !=null) { - if(origName.equalsIgnoreCase("")) - name = "OutFile"; - else { - if (origName.lastIndexOf("/")>=0) { - origName=origName.substring(origName.lastIndexOf("/")+1,origName.length()); - } - if (origName.lastIndexOf(".")>=0) { - name = origName.substring(0,(origName.lastIndexOf("."))); - } - else { - name=origName; - } - } - } - else{ - name = "OutFile"; - } - - return name; - } - + // --------------------------------------------------------------------------- // Implementation of XExportFilter: public boolean exporter(com.sun.star.beans.PropertyValue[] aSourceData, - java.lang.String[] msUserData) throws com.sun.star.uno.RuntimeException{ - sURL=null; - filterData = null; - - // Get user data from configuration (type detection) - //String udConvertClass=msUserData[0]; - //String udImport =msUserData[2]; - //String udExport =msUserData[3]; - sdMime = msUserData[5]; - - // Get source data (only the OutputStream and the URL are actually used) - com.sun.star.beans.PropertyValue[] pValue = aSourceData; - for (int i = 0 ; i < pValue.length; i++) { - try{ - if (pValue[i].Name.compareTo("OutputStream")==0){ - xos=(com.sun.star.io.XOutputStream)AnyConverter.toObject(new Type(com.sun.star.io.XOutputStream.class), pValue[i].Value); - } - //if (pValue[i].Name.compareTo("FileName")==0){ - // sFileName=(String)AnyConverter.toObject(new Type(java.lang.String.class), pValue[i].Value); - //} - if (pValue[i].Name.compareTo("URL")==0){ - sURL=(String)AnyConverter.toObject(new Type(java.lang.String.class), pValue[i].Value); - } - //if (pValue[i].Name.compareTo("Title")==0){ - // title=(String)AnyConverter.toObject(new Type(java.lang.String.class), pValue[i].Value); - //} - if (pValue[i].Name.compareTo("FilterData")==0) { - filterData = pValue[i].Value; - } - } - catch(com.sun.star.lang.IllegalArgumentException AnyExec){ - System.err.println("\nIllegalArgumentException "+AnyExec); - } - } - - if (sURL==null){ - sURL=""; - } - + java.lang.String[] msUserData) { + // Create a suitable converter + converter = new UNOConverter(aSourceData, xComponentContext); return true; } + // --------------------------------------------------------------------------- // Implementation of XDocumentHandler: // A flat XML DOM tree is created by the SAX events and finally converted @@ -173,7 +92,7 @@ XTypeProvider { public void endDocument()throws com.sun.star.uno.RuntimeException { try{ - convert(domBuilder.getDOM(),xos); + converter.convert(domBuilder.getDOM()); } catch (IOException e){ MessageBox msgBox = new MessageBox(xComponentContext); @@ -189,8 +108,6 @@ XTypeProvider { } } - - public void startElement (String sTagName, com.sun.star.xml.sax.XAttributeList xAttribs) { domBuilder.startElement(sTagName); int nLen = xAttribs.getLength(); @@ -216,112 +133,8 @@ XTypeProvider { public void setDocumentLocator(com.sun.star.xml.sax.XLocator xLocator){ } - - // This is the actual conversion method, using Writer2LaTeX to convert - // the flat XML from the DOM, and writing the result - // to the XOutputStream. The XMLExporter does not support export to - // compound documents with multiple output files; hence the main file - // is written to the XOutStream and other files are written using UCB. - - public void convert (org.w3c.dom.Document dom,com.sun.star.io.XOutputStream exportStream) - throws com.sun.star.uno.RuntimeException, IOException { - // Create converter and supply it with filter data and a suitable graphic converter - Converter converter = ConverterFactory.createConverter(sdMime); - if (converter==null) { - throw new com.sun.star.uno.RuntimeException("Failed to create converter to "+sdMime); - } - if (filterData!=null) { - FilterDataParser fdp = new FilterDataParser(xComponentContext); - fdp.applyFilterData(filterData,converter); - } - converter.setGraphicConverter(new GraphicConverterImpl(xComponentContext)); - - // Do conversion. The base name is take from the URL provided by the office - Iterator docEnum = converter.convert(dom,Misc.makeFileName(getFileName(sURL)),true).iterator(); - - if (docEnum.hasNext()) { - // The master document is written to the XOutStream supplied by the XMLFilterAdaptor - XOutputStreamToOutputStreamAdapter newxos =new XOutputStreamToOutputStreamAdapter(exportStream); - docEnum.next().write(newxos); - newxos.flush(); - newxos.close(); - - if (docEnum.hasNext() && sURL.startsWith("file:")) { - // Additional files are written directly using UCB - // Initialize the file access (used to write all additional output files) - sfa2 = null; - 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) - } - - if (sfa2!=null) { - // Remove the file name part of the URL - String sNewURL = null; - if (sURL.lastIndexOf("/")>-1) { - // Take the URL up to and including the last slash - sNewURL = sURL.substring(0,sURL.lastIndexOf("/")+1); - } - else { - // The URL does not include a path; this should not really happen, - // but in this case we will write to the current default directory - sNewURL = ""; - } - - while (docEnum.hasNext()) { - OutputFile docOut = docEnum.next(); - // Get the file name and the (optional) directory name - String sFullFileName = Misc.makeHref(docOut.getFileName()); - String sDirName = ""; - String sFileName = sFullFileName; - int nSlash = sFileName.indexOf("/"); - if (nSlash>-1) { - sDirName = sFileName.substring(0,nSlash); - sFileName = sFileName.substring(nSlash+1); - } - - try{ - // Create subdirectory if required - if (sDirName.length()>0 && !sfa2.exists(sNewURL+sDirName)) { - sfa2.createFolder(sNewURL+sDirName); - } - - // writeFile demands an InputStream, so we need a pipe - Object xPipeObj=xMSF.createInstance("com.sun.star.io.Pipe"); - 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... - docOut.write(outStream); - outStream.flush(); - outStream.close(); - xOutStream.closeOutput(); - // ...and then write the content to the URL - sfa2.writeFile(sNewURL+sFullFileName,xInStream); - } - catch (Throwable e){ - MessageBox msgBox = new MessageBox(xComponentContext); - msgBox.showMessage(__displayName+": Error writing files", - e.toString()+" at "+e.getStackTrace()[0].toString()); - } - } - } - } - } - else { - // The converter did not produce any files (should not happen) - MessageBox msgBox = new MessageBox(xComponentContext); - msgBox.showMessage(__displayName+": Conversion failed","Internal error"); - } - } - - + // --------------------------------------------------------------------------- // Implement methods from interface XTypeProvider - // Implementation of XTypeProvider public com.sun.star.uno.Type[] getTypes() { Type[] typeReturn = {}; @@ -349,11 +162,13 @@ XTypeProvider { 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 ) ); @@ -368,5 +183,4 @@ XTypeProvider { return( stringSupportedServiceNames ); } - } diff --git a/source/java/org/openoffice/da/comp/w2lcommon/filter/UNOConverter.java b/source/java/org/openoffice/da/comp/w2lcommon/filter/UNOConverter.java new file mode 100644 index 0000000..c5c6c66 --- /dev/null +++ b/source/java/org/openoffice/da/comp/w2lcommon/filter/UNOConverter.java @@ -0,0 +1,255 @@ +/************************************************************************ + * + * UNOConverter.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-2014 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.6 (2014-10-07) + * + */ +package org.openoffice.da.comp.w2lcommon.filter; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Iterator; + +import org.w3c.dom.Document; + +import writer2latex.api.Converter; +import writer2latex.api.ConverterFactory; +import writer2latex.api.ConverterResult; +import writer2latex.api.OutputFile; +import writer2latex.util.Misc; + +import com.sun.star.beans.PropertyValue; +import com.sun.star.io.XInputStream; +import com.sun.star.io.XOutputStream; +import com.sun.star.lib.uno.adapter.XInputStreamToInputStreamAdapter; +import com.sun.star.lib.uno.adapter.XOutputStreamToOutputStreamAdapter; +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; + +/** This class provides conversion using UNO: + * Graphics conversion is done using appropriate UNO services. + * Files are written to an URL using UCB. + * The document source document can be provided as an XInputStream or as a DOM tree + */ +public class UNOConverter { + private XComponentContext xComponentContext; + private Converter converter; + private String sTargetFormat = null; + private XOutputStream xos = null; + private String sURL = null; + + /** Construct a new UNODocumentConverter from an array of arguments + * + * @param xComponentContext the component context used to instantiate new UNO services + * @param lArguments arguments providing FilterName, URL, OutputStream (optional) and FilterData (optional) + */ + public UNOConverter(PropertyValue[] lArguments, XComponentContext xComponentContext) { + this.xComponentContext = xComponentContext; + + // Create mapping from filter names to target media types + HashMap filterNames = new HashMap(); + filterNames.put("org.openoffice.da.writer2latex","application/x-latex"); + filterNames.put("org.openoffice.da.writer2bibtex","application/x-bibtex"); + filterNames.put("org.openoffice.da.writer2xhtml","text/html"); + filterNames.put("org.openoffice.da.writer2xhtml11","application/xhtml11"); + filterNames.put("org.openoffice.da.writer2xhtml5","text/html5"); + filterNames.put("org.openoffice.da.writer2xhtml.mathml","application/xhtml+xml"); + filterNames.put("org.openoffice.da.writer2xhtml.epub","application/epub+zip"); + filterNames.put("org.openoffice.da.calc2xhtml","text/html"); + filterNames.put("org.openoffice.da.calc2xhtml11","application/xhtml11"); + filterNames.put("org.openoffice.da.calc2xhtml5","text/html5"); + + // Get the arguments + Object filterData = null; + PropertyValue[] pValue = lArguments; + for (int i = 0 ; i < pValue.length; i++) { + try { + if (pValue[i].Name.compareTo("FilterName")==0) { + String sFilterName = (String)AnyConverter.toObject(new Type(String.class), pValue[i].Value); + if (filterNames.containsKey(sFilterName)) { + sTargetFormat = filterNames.get(sFilterName); + } + else { + sTargetFormat = sFilterName; + } + } + if (pValue[i].Name.compareTo("OutputStream")==0){ + xos = (XOutputStream)AnyConverter.toObject(new Type(XOutputStream.class), pValue[i].Value); + } + if (pValue[i].Name.compareTo("URL")==0){ + sURL = (String)AnyConverter.toObject(new Type(String.class), pValue[i].Value); + } + if (pValue[i].Name.compareTo("FilterData")==0) { + filterData = pValue[i].Value; + } + } + catch(com.sun.star.lang.IllegalArgumentException AnyExec){ + System.err.println("\nIllegalArgumentException "+AnyExec); + } + } + if (sURL==null){ + sURL=""; + } + + // Create converter and supply it with filter data and a suitable graphic converter + converter = ConverterFactory.createConverter(sTargetFormat); + if (converter==null) { + throw new com.sun.star.uno.RuntimeException("Failed to create converter to "+sTargetFormat); + } + if (filterData!=null) { + FilterDataParser fdp = new FilterDataParser(xComponentContext); + fdp.applyFilterData(filterData,converter); + } + converter.setGraphicConverter(new GraphicConverterImpl(xComponentContext)); + + } + + /** Convert a document given by a DOM tree + * + * @param dom the DOMsource + * @throws IOException + */ + public void convert(Document dom) throws IOException { + writeFiles(converter.convert(dom, Misc.makeFileName(getFileName(sURL)),true)); + } + + /** Convert a document given by an XInputStream + * + * @param xis the input stream + * @throws IOException + */ + public void convert(XInputStream xis) throws IOException { + InputStream is = new XInputStreamToInputStreamAdapter(xis); + writeFiles(converter.convert(is, Misc.makeFileName(getFileName(sURL)))); + } + + private void writeFiles(ConverterResult result) throws IOException { + Iterator docEnum = result.iterator(); + if (docEnum.hasNext()) { + // The master document is written to the supplied XOutputStream, if any + if (xos!=null) { + XOutputStreamToOutputStreamAdapter newxos =new XOutputStreamToOutputStreamAdapter(xos); + docEnum.next().write(newxos); + newxos.flush(); + newxos.close(); + } + // Additional files are written directly using UCB + if (docEnum.hasNext() && sURL.startsWith("file:")) { + // Initialize the file access (used to write all additional output files) + XSimpleFileAccess2 sfa2 = null; + 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) + } + + if (sfa2!=null) { + // Remove the file name part of the URL + String sNewURL = null; + if (sURL.lastIndexOf("/")>-1) { + // Take the URL up to and including the last slash + sNewURL = sURL.substring(0,sURL.lastIndexOf("/")+1); + } + else { + // The URL does not include a path; this should not really happen, + // but in this case we will write to the current default directory + sNewURL = ""; + } + + while (docEnum.hasNext()) { + OutputFile docOut = docEnum.next(); + // Get the file name and the (optional) directory name + String sFullFileName = Misc.makeHref(docOut.getFileName()); + String sDirName = ""; + String sFileName = sFullFileName; + int nSlash = sFileName.indexOf("/"); + if (nSlash>-1) { + sDirName = sFileName.substring(0,nSlash); + sFileName = sFileName.substring(nSlash+1); + } + + try { + // Create subdirectory if required + if (sDirName.length()>0 && !sfa2.exists(sNewURL+sDirName)) { + sfa2.createFolder(sNewURL+sDirName); + } + + // writeFile demands an InputStream, so we use a Pipe for the transport + 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... + docOut.write(outStream); + outStream.flush(); + outStream.close(); + xOutStream.closeOutput(); + // ...and then write the content to the URL + sfa2.writeFile(sNewURL+sFullFileName,xInStream); + } + catch (Throwable e){ + throw new IOException("Error writing file "+sFileName+" "+e.getMessage()); + } + } + } + } + } + else { + // The converter did not produce any files (should not happen) + throw new IOException("Conversion failed: Internal error"); + } + } + + private String getFileName(String origName) { + String name=null; + if (origName !=null) { + if(origName.equalsIgnoreCase("")) + name = "OutFile"; + else { + if (origName.lastIndexOf("/")>=0) { + origName=origName.substring(origName.lastIndexOf("/")+1,origName.length()); + } + if (origName.lastIndexOf(".")>=0) { + name = origName.substring(0,(origName.lastIndexOf("."))); + } + else { + name=origName; + } + } + } + else{ + name = "OutFile"; + } + + return name; + } + +} \ No newline at end of file diff --git a/source/java/org/openoffice/da/comp/writer2latex/W2LExportFilter.java b/source/java/org/openoffice/da/comp/writer2latex/W2LExportFilter.java index 8d4adc0..3d5a9f8 100644 --- a/source/java/org/openoffice/da/comp/writer2latex/W2LExportFilter.java +++ b/source/java/org/openoffice/da/comp/writer2latex/W2LExportFilter.java @@ -16,11 +16,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * - * Copyright: 2002-2009 by Henrik Just + * Copyright: 2002-2014 by Henrik Just * * All Rights Reserved. * - * Version 1.2 (2009-09-06) + * Version 1.6 (2014-10-06) * */ @@ -46,7 +46,6 @@ public class W2LExportFilter extends ExportFilterBase { public W2LExportFilter(XComponentContext xComponentContext1) { super(xComponentContext1); - xMSF = W2LRegistration.xMultiServiceFactory; } diff --git a/source/java/org/openoffice/da/comp/writer2xhtml/W2XExportFilter.java b/source/java/org/openoffice/da/comp/writer2xhtml/W2XExportFilter.java index 1f59f07..ae2c1ca 100644 --- a/source/java/org/openoffice/da/comp/writer2xhtml/W2XExportFilter.java +++ b/source/java/org/openoffice/da/comp/writer2xhtml/W2XExportFilter.java @@ -16,11 +16,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * - * Copyright: 2002-2009 by Henrik Just + * Copyright: 2002-2014 by Henrik Just * * All Rights Reserved. * - * Version 1.2 (2009-09-06) + * Version 1.6 (2014-10-06) * */ @@ -46,7 +46,6 @@ public class W2XExportFilter extends ExportFilterBase { public W2XExportFilter(XComponentContext xComponentContext1) { super(xComponentContext1); - xMSF = W2XRegistration.xMultiServiceFactory; } diff --git a/source/java/org/openoffice/da/comp/writer2xhtml/W2XRegistration.java b/source/java/org/openoffice/da/comp/writer2xhtml/W2XRegistration.java index de9274b..cbc4ce6 100644 --- a/source/java/org/openoffice/da/comp/writer2xhtml/W2XRegistration.java +++ b/source/java/org/openoffice/da/comp/writer2xhtml/W2XRegistration.java @@ -20,7 +20,7 @@ * * All Rights Reserved. * - * Version 1.4 (2014-08-18) + * Version 1.6 (2014-10-06) * */ @@ -60,7 +60,13 @@ public class W2XRegistration { XMultiServiceFactory multiFactory, XRegistryKey regKey) { xMultiServiceFactory = multiFactory; XSingleServiceFactory xSingleServiceFactory = null; - if (implName.equals(W2XExportFilter.class.getName()) ) { + if (implName.equals(Writer2xhtml.__implementationName) ) { + xSingleServiceFactory = FactoryHelper.getServiceFactory(Writer2xhtml.class, + Writer2xhtml.__serviceName, + multiFactory, + regKey); + } + else if (implName.equals(W2XExportFilter.class.getName()) ) { xSingleServiceFactory = FactoryHelper.getServiceFactory(W2XExportFilter.class, W2XExportFilter.__serviceName, multiFactory, @@ -124,6 +130,8 @@ public class W2XRegistration { return FactoryHelper.writeRegistryServiceInfo(BatchConverter.__implementationName, BatchConverter.__serviceName, regKey) & + FactoryHelper.writeRegistryServiceInfo(Writer2xhtml.__implementationName, + Writer2xhtml.__serviceName, regKey) & FactoryHelper.writeRegistryServiceInfo(W2XExportFilter.__implementationName, W2XExportFilter.__serviceName, regKey) & FactoryHelper.writeRegistryServiceInfo(XhtmlOptionsDialog.__implementationName, diff --git a/source/java/org/openoffice/da/comp/writer2xhtml/Writer2xhtml.java b/source/java/org/openoffice/da/comp/writer2xhtml/Writer2xhtml.java new file mode 100644 index 0000000..7467b29 --- /dev/null +++ b/source/java/org/openoffice/da/comp/writer2xhtml/Writer2xhtml.java @@ -0,0 +1,358 @@ +/************************************************************************ + * + * Writer2xhtml.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-2014 by Henrik Just + * + * All Rights Reserved. + * + * Version 1.6 (2014-10-09) + * + */ + +package org.openoffice.da.comp.writer2xhtml; + +// TODO: Create common base for dispatcher classes + +import java.awt.Desktop; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import com.sun.star.beans.PropertyValue; +import com.sun.star.beans.XPropertyAccess; +import com.sun.star.frame.XController; +import com.sun.star.frame.XFrame; +import com.sun.star.frame.XModel; +import com.sun.star.frame.XStorable; +import com.sun.star.io.XInputStream; +import com.sun.star.lib.uno.helper.WeakBase; +import com.sun.star.task.XStatusIndicator; +import com.sun.star.task.XStatusIndicatorFactory; +import com.sun.star.ucb.XSimpleFileAccess2; +import com.sun.star.ui.dialogs.ExecutableDialogResults; +import com.sun.star.ui.dialogs.XExecutableDialog; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; +import com.sun.star.util.XModifiable; + +import org.openoffice.da.comp.w2lcommon.filter.UNOConverter; +import org.openoffice.da.comp.w2lcommon.helper.MessageBox; + +import writer2latex.util.Misc; + +/** This class implements the ui (dispatch) commands provided by Writer2xhtml. + */ +public final class Writer2xhtml extends WeakBase + implements com.sun.star.lang.XServiceInfo, + com.sun.star.frame.XDispatchProvider, + com.sun.star.lang.XInitialization, + com.sun.star.frame.XDispatch { + + private static final String PROTOCOL = "org.openoffice.da.writer2xhtml:"; + + private enum TargetFormat { xhtml, xhtml11, xhtml_mathml, html5, epub }; + + // From constructor+initialization + private final XComponentContext m_xContext; + private XFrame m_xFrame; + private XModel xModel = null; + + // Global data + private PropertyValue[] mediaProps = null; + + public static final String __implementationName = Writer2xhtml.class.getName(); + public static final String __serviceName = "com.sun.star.frame.ProtocolHandler"; + private static final String[] m_serviceNames = { __serviceName }; + + // TODO: These should be configurable + private TargetFormat xhtmlFormat = TargetFormat.xhtml_mathml; + private TargetFormat epubFormat = TargetFormat.epub; + + private String getTargetExtension(TargetFormat format) { + switch (format) { + case xhtml: return ".html"; + case xhtml11: return ".xhtml"; + case xhtml_mathml: return ".xhtml"; + case html5: return ".html"; + case epub: return ".epub"; + default: return ""; + } + } + + private String getDialogName(TargetFormat format) { + switch (format) { + case xhtml: return "org.openoffice.da.comp.writer2xhtml.XhtmlOptionsDialog"; + case xhtml11: return "org.openoffice.da.comp.writer2xhtml.XhtmlOptionsDialog"; + case xhtml_mathml: return "org.openoffice.da.comp.writer2xhtml.XhtmlOptionsDialogMath"; + case html5: return "org.openoffice.da.comp.writer2xhtml.XhtmlOptionsDialogMath"; + case epub: return "org.openoffice.da.comp.writer2xhtml.EpubOptionsDialog"; + default: return ""; + } + } + + private String getFilterName(TargetFormat format) { + switch (format) { + case xhtml: return "org.openoffice.da.writer2xhtml"; + case xhtml11: return "org.openoffice.da.writer2xhtml11"; + case xhtml_mathml: return "org.openoffice.da.writer2xhtml.mathml"; + case html5: return "org.openoffice.da.writer2xhtml5"; + case epub: return "org.openoffice.da.writer2xhtml.epub"; + default: return ""; + } + } + + public Writer2xhtml(XComponentContext xContext) { + m_xContext = xContext; + } + + // com.sun.star.lang.XInitialization: + public void initialize( Object[] object ) + throws com.sun.star.uno.Exception { + if ( object.length > 0 ) { + // The first item is the current frame + m_xFrame = (com.sun.star.frame.XFrame) UnoRuntime.queryInterface( + com.sun.star.frame.XFrame.class, object[0]); + // Get the model for the document from the frame + XController xController = m_xFrame.getController(); + if (xController!=null) { + xModel = xController.getModel(); + } + } + } + + // com.sun.star.lang.XServiceInfo: + public String getImplementationName() { + return __implementationName; + } + + public boolean supportsService( String sService ) { + int len = m_serviceNames.length; + + for( int i=0; i < len; i++) { + if (sService.equals(m_serviceNames[i])) + return true; + } + return false; + } + + public String[] getSupportedServiceNames() { + return m_serviceNames; + } + + + // com.sun.star.frame.XDispatchProvider: + public com.sun.star.frame.XDispatch queryDispatch( com.sun.star.util.URL aURL, + String sTargetFrameName, int iSearchFlags ) { + if ( aURL.Protocol.compareTo(PROTOCOL) == 0 ) { + if ( aURL.Path.compareTo("PublishAsXHTML") == 0 ) + return this; + else if ( aURL.Path.compareTo("PublishAsEPUB") == 0 ) + return this; + } + return null; + } + + public com.sun.star.frame.XDispatch[] queryDispatches( + com.sun.star.frame.DispatchDescriptor[] seqDescriptors ) { + int nCount = seqDescriptors.length; + com.sun.star.frame.XDispatch[] seqDispatcher = + new com.sun.star.frame.XDispatch[seqDescriptors.length]; + + for( int i=0; i < nCount; ++i ) { + seqDispatcher[i] = queryDispatch(seqDescriptors[i].FeatureURL, + seqDescriptors[i].FrameName, + seqDescriptors[i].SearchFlags ); + } + return seqDispatcher; + } + + + // com.sun.star.frame.XDispatch: + public void dispatch( com.sun.star.util.URL aURL, + com.sun.star.beans.PropertyValue[] aArguments ) { + if ( aURL.Protocol.compareTo(PROTOCOL) == 0 ) { + System.out.println(aURL.Protocol+" "+aURL.Path); + if ( aURL.Path.compareTo("PublishAsXHTML") == 0 ) { + publish(xhtmlFormat); + return; + } + else if ( aURL.Path.compareTo("PublishAsEPUB") == 0 ) { + publish(epubFormat); + return; + } + } + } + + public void addStatusListener( com.sun.star.frame.XStatusListener xControl, + com.sun.star.util.URL aURL ) { + } + + public void removeStatusListener( com.sun.star.frame.XStatusListener xControl, + com.sun.star.util.URL aURL ) { + } + + // The actual commands... + + private void publish(TargetFormat format) { + if (saveDocument() && updateMediaProperties(xhtmlFormat)) { + // Create a (somewhat coarse grained) status indicator/progress bar + XStatusIndicatorFactory xFactory = (com.sun.star.task.XStatusIndicatorFactory) + UnoRuntime.queryInterface(com.sun.star.task.XStatusIndicatorFactory.class, m_xFrame); + XStatusIndicator xStatus = xFactory.createStatusIndicator(); + xStatus.start("Writer2xhtml",10); + xStatus.setValue(1); // At least we have started, that's 10% :-) + + System.out.println("Document location "+xModel.getURL()); + + try { + // Convert to desired format + UNOConverter converter = new UNOConverter(mediaProps, m_xContext); + // Initialize the file access (to read the office document) + XSimpleFileAccess2 sfa2 = null; + try { + Object sfaObject = m_xContext.getServiceManager().createInstanceWithContext( + "com.sun.star.ucb.SimpleFileAccess", m_xContext); + sfa2 = (XSimpleFileAccess2) UnoRuntime.queryInterface(XSimpleFileAccess2.class, sfaObject); + } + catch (com.sun.star.uno.Exception e) { + // failed to get SimpleFileAccess service (should not happen) + } + XInputStream xis = sfa2.openFileRead(xModel.getURL()); + converter.convert(xis); + xis.closeInput(); + } + catch (IOException | com.sun.star.uno.Exception e) { + xStatus.end(); + MessageBox msgBox = new MessageBox(m_xContext, m_xFrame); + msgBox.showMessage("Writer2xhtml Error","Failed to export document"); + return; + } + xStatus.setValue(6); // Export is finished, that's more than half :-) + + if (xModel.getURL().startsWith("file:")) { + File file = urlToFile(getTargetURL(format)); + if (file.exists()) { + // Open the file in the default application on this system (if any) + if (Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + try { + desktop.open(file); + } catch (IOException e) { + System.err.println(e.getMessage()); + } + } + } + else { + MessageBox msgBox = new MessageBox(m_xContext, m_xFrame); + msgBox.showMessage("Writer2xhtml Error","Failed to open exported document"); + } + } + else { + MessageBox msgBox = new MessageBox(m_xContext, m_xFrame); + msgBox.showMessage("Writer2xhtml Error","Cannot open document on the location "+getTargetURL(format)); + } + + xStatus.setValue(10); // The user will usually not see this... + + xStatus.end(); + } + } + + private boolean saveDocument() { + String sDocumentUrl = xModel.getURL(); + if (sDocumentUrl.length()!=0) { // The document has a location + XModifiable xModifiable = (XModifiable) UnoRuntime.queryInterface(XModifiable.class, xModel); + if (xModifiable.isModified()) { // It is modified and need to be saved + XStorable xStorable = (XStorable) UnoRuntime.queryInterface(XStorable.class, xModel); + try { + xStorable.store(); + } catch (com.sun.star.io.IOException e) { + return false; + } + } + } + else { // No location, ask the user to save the document + MessageBox msgBox = new MessageBox(m_xContext, m_xFrame); + msgBox.showMessage("Document not saved!","Please save the document before publishing the file"); + return false; + } + return true; + } + + // Some utility methods + private String getTargetURL(TargetFormat format) { + return Misc.removeExtension(xModel.getURL())+getTargetExtension(format); + } + + private void prepareMediaProperties(TargetFormat format) { + // Create inital media properties + mediaProps = new PropertyValue[2]; + mediaProps[0] = new PropertyValue(); + mediaProps[0].Name = "FilterName"; + mediaProps[0].Value = getFilterName(format); + mediaProps[1] = new PropertyValue(); + mediaProps[1].Name = "URL"; + mediaProps[1].Value = getTargetURL(format); + } + + private boolean updateMediaProperties(TargetFormat format) { + prepareMediaProperties(format); + + try { + // Display options dialog + Object dialog = m_xContext.getServiceManager() + .createInstanceWithContext(getDialogName(format), m_xContext); + + XPropertyAccess xPropertyAccess = (XPropertyAccess) + UnoRuntime.queryInterface(XPropertyAccess.class, dialog); + xPropertyAccess.setPropertyValues(mediaProps); + + XExecutableDialog xDialog = (XExecutableDialog) + UnoRuntime.queryInterface(XExecutableDialog.class, dialog); + if (xDialog.execute()==ExecutableDialogResults.OK) { + mediaProps = xPropertyAccess.getPropertyValues(); + return true; + } + else { + mediaProps = null; + return false; + } + } + catch (com.sun.star.beans.UnknownPropertyException e) { + // setPropertyValues will not fail.. + mediaProps = null; + return false; + } + catch (com.sun.star.uno.Exception e) { + // getServiceManager will not fail.. + mediaProps = null; + return false; + } + } + + private File urlToFile(String sUrl) { + try { + return new File(new URI(sUrl)); + } + catch (URISyntaxException e) { + return new File("."); + } + } + + +} \ No newline at end of file diff --git a/source/java/writer2latex/util/Misc.java b/source/java/writer2latex/util/Misc.java index 6417dfe..a45f6b4 100644 --- a/source/java/writer2latex/util/Misc.java +++ b/source/java/writer2latex/util/Misc.java @@ -20,7 +20,7 @@ * * All Rights Reserved. * - * Version 1.4 (2014-09-16) + * Version 1.4 (2014-10-10) * */ @@ -329,10 +329,9 @@ public class Misc{ } } - public static final String removeExtension(String sName) { - int n = sName.lastIndexOf("."); - if (n<0) { return sName; } - return sName.substring(0,n); + public static final String removeExtension(String sURL) { + String sExt = getFileExtension(sURL); + return sURL.substring(0, sURL.length()-sExt.length()); } /* diff --git a/source/oxt/writer2xhtml/Addons.xcu b/source/oxt/writer2xhtml/Addons.xcu new file mode 100644 index 0000000..41bfb93 --- /dev/null +++ b/source/oxt/writer2xhtml/Addons.xcu @@ -0,0 +1,47 @@ + + + + + + + + + com.sun.star.text.TextDocument + + + Publish as EPUB + Publicer som EPUB + + + _self + + + org.openoffice.da.writer2xhtml:PublishAsEPUB + + + %origin%/icons/epub + + + + + com.sun.star.text.TextDocument + + + Publish as XHTML + Publicer som XHTML + + + _self + + + org.openoffice.da.writer2xhtml:PublishAsXHTML + + + %origin%/icons/html5 + + + + + + + \ No newline at end of file diff --git a/source/oxt/writer2xhtml/META-INF/manifest.xml b/source/oxt/writer2xhtml/META-INF/manifest.xml index aedff71..7bd4478 100644 --- a/source/oxt/writer2xhtml/META-INF/manifest.xml +++ b/source/oxt/writer2xhtml/META-INF/manifest.xml @@ -1,6 +1,18 @@ + + + + + + diff --git a/source/oxt/writer2xhtml/Office/UI/WriterWindowState.xcu b/source/oxt/writer2xhtml/Office/UI/WriterWindowState.xcu new file mode 100644 index 0000000..676fa85 --- /dev/null +++ b/source/oxt/writer2xhtml/Office/UI/WriterWindowState.xcu @@ -0,0 +1,15 @@ + + + + + + + Writer2xhtml + + + + + \ No newline at end of file diff --git a/source/oxt/writer2xhtml/ProtocolHandler.xcu b/source/oxt/writer2xhtml/ProtocolHandler.xcu new file mode 100644 index 0000000..8a1ee4b --- /dev/null +++ b/source/oxt/writer2xhtml/ProtocolHandler.xcu @@ -0,0 +1,12 @@ + + + + + + + + org.openoffice.da.writer2xhtml:* + + + + \ No newline at end of file diff --git a/source/oxt/writer2xhtml/icons/epub_16.bmp b/source/oxt/writer2xhtml/icons/epub_16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0446323b4872e3b00b287d2fd7e06b200e1d9000 GIT binary patch literal 890 zcmZ?rtzu>XgDN1I1H=MQ%*Y@C7H0s;3v)v-M1X<8$vvnT#wM0#LR0vk;XfLBB=*60 z!DJu;GSH+jxu3Xx=q{Tmy1fO6fD9lPQw?0?neZpQ#S=w$w218lAs_?D1q#9yATvI5 z{xF$8MQleaP}wrqi$Ej_)U~}8Cz&+$7AVcSoi1(E&1 z`df8%55zBfP3}Mh7kL1+w9fTC4dm9P?S{xkHm`ulzUTP{cjN}Us}R9GFug!-d;9@l z1Oat9PMQ6W;U7@s57S?@)xAIwAUdRfAEE`BY)IY%aaeT2N{Dz=;|hpKRr*e3m2h@> z_70!|AoA{A07MW+R%GpfE5KwlC+>x~0iv-baUZ4{G?DC*jSy$#6mLY6!o{5taAHQ_ HNvyH}&!NM< literal 0 HcmV?d00001 diff --git a/source/oxt/writer2xhtml/icons/epub_16h.bmp b/source/oxt/writer2xhtml/icons/epub_16h.bmp new file mode 100644 index 0000000000000000000000000000000000000000..da608c3928d52d1f209381ed3ceefce9a8f10d3a GIT binary patch literal 890 zcmZ?rtzu>XgDN1I1H=MQ%*Y@C7H0s;3v)v-M1X<8$vvnT#wM0#LR0vk;XfLBApb$} z-b^3@GSH+jxgYs{NIjjw_^%6yfD9lPQw?0?iS#F#$I}@8cfk>m3lxMaKxTa6{i$?! zCgZPkr1-LknF*EHV&?7)8paP&WpvZfH?{W{PL(EwceGQ^`P4JC1!8ajnpdiD4ki9@< zK*jzWHh>j(%}9ruyxHe2L}YmcR6ER;UZCR1Ip-jT>s_1=G4KcbZ=tu7AZBj&xCarO zm3k2uAdbwL uycbyw8oQ$XAjAz2jg@VO(G*~E;}&j(I3s?+R!mu}BK-xY`wPxsl>z`dbl4yO literal 0 HcmV?d00001 diff --git a/source/oxt/writer2xhtml/icons/epub_26.bmp b/source/oxt/writer2xhtml/icons/epub_26.bmp new file mode 100644 index 0000000000000000000000000000000000000000..06f1ffacbdfd14770aab9d6308098d77876b154b GIT binary patch literal 2202 zcma)+dq`7J9LG;jgZi%~B3bLD(%Qhs zdaQ?}t39gK9T-7H%cP$j~gKMc|H3^U`WH`%^uquJ){n=-})9X)6)bG^#=dd zqFZj!M5k}>XjWu4o`3f{j!C$YrNThx#QZ6gwf9|U@=nzLJ?}G-8N7SNA1Q40gO1-h zlROW>nqY@;i3JRne9|D(d7*8e6Vvk|OXi^SSIz{@Kyy{dnRKaKBBW3O;YGKMrNKgu z@r6leGy|RHu!AC_o5zGe&&NT|}dC^xfXo}eZ zn`YCLQQI7;X$sRG2v$VeP5gM2g#!WsWAXLhgfqYj9=6jw#MR9q2rwZ6%}~LkHnDJM zfMTpd8W6m^Xsafp{?y}?b=iLWOpprTaygLd5dy{7ozf4vvD7;#47g|p;u6m_dhJe} zO>_BY!QcF7YvK~gcA%8~>$Qzg*b@*s33!f zj!VaeDYDq(qZbG9c29qD4a!aFs(h(I5`TQ8u`Zg(P~ZKo?i)12=DbZUHq=MyDB=tr z`l?TdOv=v`2bXpFc~Y6{rkDqUnvCnH!$bFx3jvBe&~_Ik1(PKR_#~P-n?Ei&)G{cJ zTN6~Z3~4Z;sn3I?>f%u9c#@C6ZU94yArIq+DN?rUEpvAMxC)GfOTf-&-!lP2@IQZC N>$8rc&^*1Ev3~&qqQd|H literal 0 HcmV?d00001 diff --git a/source/oxt/writer2xhtml/icons/epub_26h.bmp b/source/oxt/writer2xhtml/icons/epub_26h.bmp new file mode 100644 index 0000000000000000000000000000000000000000..fe561d657ccd01261cbf3a2f90cadfe87774ea83 GIT binary patch literal 2202 zcma)+Ur19?9LLWJYi&hnFA{-1_f`?~U=UJB57qJ|Df2~GL4$-vLefk4V5iN^G;$`C zPFYd9{vnnRNzy-4%l<$Vq2NPLN|rnwws;Y>;I+0(&K@48xAs z()dQgz!OL;?e(_2fPb98a>#)Htqsze7iyS5LnfY}h8ir97QA-fBw&t=;9)MC?JAq? z)R#!M`=$zZS%??$zE>DI2a6Xv{;W%56fd+nGNL~0y4_mRRj{|qNwDdj_e zCFzp))O|7_^Le+AeF01jG_h$hwB*jgln+ZJRew^(VWCLEi+jFN*v4O>PU?@bnv?lL*QNtrHazJ$`GIg0X==#l}7TO9+)9T?n<;}92v@}jSkgDAJYs3 zu0$(ofdc{oW6$@_(X=xerar_c`W{IEM_?#9lex`S1c72z!}oOF+H|YIQQ!T9wq6r^ zNCoI}{qGf|K(X%n55y5HnZHUMh<8my)$XggCYJZblg__IsershT%g47LHKOmt5y2r zngO|cyidD!=!T!{%|p(YEF%dBT-y0wIfvhomAAEg=7tH`t91z(KYe|K3g)&gs-?!m z>e9s*Iuh3HpKnqJwra-|MFtyNMybHWL*o49QHtC-8KoCTB5$d~Q@u7fy)+<6f2wk- z69<}m<6+wKDoP#up4}neI_QlI(<)*U54q$0;=<_%P%#!$ri!tC4JPi0`8rzgkUlyX zr^x*ycQGiedLXX;iD53(pOPGYFaTu1apeA>0i!Rid62-TACCs+HZWLhd8m8h6v?p< hdMgEk|M6gwdnxX))t*uCDtM50oOy>qeO57J{{SVu*vbF^ literal 0 HcmV?d00001 diff --git a/source/oxt/writer2xhtml/icons/html5_16.bmp b/source/oxt/writer2xhtml/icons/html5_16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ad2b2f66255e75054b00b6860b3282e4845aceff GIT binary patch literal 890 zcma))L1@!Z7{{ZslL&%LJao3&u8CVc?bv}@EoECbn03w-YuoAO4m&7QgdRkkpdjKr zC_M;*mz`8Zp~rQ4aOz_)bqX`v3dgxecr`RkM=&3pbA{$4{nDc*I*S zWxlmwjyC(VRz1)yIr~#J`BUwEJa=J*J(Iz2yPprZGXR<}I^A9o808&)zRmmF79s2< za%7xvQH33n+@}OHPsu|)eBi1u^E|WoUHX-+JWUiw?&^-H%0=>6aT^c#?VO}4GDMVY zwecjsl^kKk%;#Im$Zz%W?>F0q_{(Wl!yuG((e(;JIydjQU7orc>gZFe*uWXbn zZ6Vb;AONHM3yV(ul#4ak0q>O)j24>v=~PkcWB_dhEuvGfBYg%$J2M>;-lAp zW?mJc$8U`N?bs8?pI#`zWzTR4QBqt^gS2C%baU58H5p z{U+w6L^8ARqx@m11btpE1*TWob6H@NKkLqdpSmv=*W|U;y0m}%$DXZoL3zk6Q6AL= zo`nV)^7EY&TE{psG)A~k?wCiUd}p6gIhaL-^XD$A+^Djp&`L+IQ4&qe+`$x7rdfz0 F|6gM7*X95K literal 0 HcmV?d00001 diff --git a/source/oxt/writer2xhtml/icons/html5_16h.bmp b/source/oxt/writer2xhtml/icons/html5_16h.bmp new file mode 100644 index 0000000000000000000000000000000000000000..04491b2bd9bc6005d5dbf929b9a787f9fb362d7a GIT binary patch literal 890 zcma)4Peg-Z82`28J4Bi>6WzuRV@6^|ril)Tj6|1RI}}-xO`=QJE-~@xwqthLWk%PS z?-G-kk&&I#Wg@?x_x--t`<0nJp7)RE`MuBc{C?izZfzdgYO){8S`OA65;_ja#}@tN z2Y}*s>CD_`JtO~t3q*tfu}W+(U176N-@0U>L7Wr&M4l)RX$_9?s>N}Dnta@ih#exM zE9WO;{zY*@WEI{i*-Zb3xhfGQO5AJNxZIX*h;@Ze9@)4e;=4?nBN8^1aWxAtTM2?A zYOp9EPc}8dl*LOs#ahIPD`gb@lqoKF8CBRN_-$UCdO`honXbqCE?sd?-=Enb+vHDSOSZM7ZDmB)anqrIzNv*|NqNLUkJCB{mE;GXdy9?~%H#0lSE>Pp-n>%;! z%=g=K=bn4UTyZWkLOZ(A9>y6PI5$N+sf{P#e$2!AsSThp7grxK`v3R3dCh|>5i9HE zkMMgo`;{%ei70PhiflI93!k_5k@D>*F9vZ753F}#BmxTKF_BBZM0+kIxL)7sc(#a6 zE~iWtT3f}K$|?MOu88T#b_~b6Zbp09$fY&*5Z5v-hVc4HS&v4C!Gw-3^iy6|QrZ==O(ty;*&-1QB2i;E zm8+qjAmxpCZ)ZAJ0ov4bJW)xLl~nqxN@@_Pr_qQ$O?q?DF(`8gc7jth~aERiK z-}vY}3M2R*yse~G`LR0bZ~HQMPQ};MKWDNju;do9_a6!*qQU$9QSYuIHSOST?q+XI z3RCxl%ir;_g<3uv`4ZPC-@Lm7-t2-O;UIi^m!GQJ2NX8rEqLXu4(tSpSMhx4w)&LiK!ODv;mJDL7L zuJ1h84-Km7`_z8+s`t#d-holiooRKxe*elxm)uFM3Q@~tme8<=^M(>!sikVNJXK1a z7_=izu)eBh0xcLJhq@%EMm;L8o`(_kaNdAPA+&vp-Eih2hlCRZ0WI=HR|qW7y>Q)& zEkeF1z&Mbsg!7K4OZv-8uckjAPi;>&BM z$8YgYhdSTWBlb_e;GnaY>?32|k?X6vIOaY1r90oF^fkfOEg*MpaQ#oaDU8Fd?We(SQq`)Auyu(*^RVgU2Zi|)A)&9By%AlT>k zSAL-Js_3$OJ0J#c>XF60W_9yozG+q(A)@ky%50-cdR!&P!c=_JmGPQdv`tn9c0df? zM3e`g9`JM|O4eGHQAC@91zjVuP2<&aumfW7#$()R7VRTud@yu&utnS?vZGbnP(&S< vT1Ek4@P2&44F?nitm&w?tn33-#oz%z4Bppqa{&AYPrr)?9wa;fh{pRDTnN_l literal 0 HcmV?d00001 diff --git a/source/oxt/writer2xhtml/icons/html5_26h.bmp b/source/oxt/writer2xhtml/icons/html5_26h.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1a93e055d4913ff386e1315197a1187bc74fad1d GIT binary patch literal 2202 zcma)-Pe@cz6voeeGozU?WD}y26kpJ#ulbGK% zj_3KW$^Mm8ne|=VPn6rgS>VuhBzeirH+uC#H$qToe+54UUj;J?S3J~3v0GtK;kD9> z+~N&|UR)7c-p*&ibHP0iClt0RhzE(8vCNDf5(+03?t6Hlu$1qc&wDB8i=Z`%%~8jQ zK`CvT+6uJ?Y6m24LVaT3m_LR zm1CX+sl0sr5+rlUt#>pYhaJTB1CHHB4G$Q!PF>RE(VY;6(CA~!?aA?4eBSsXrkAx% zEnyLP#t@HwhnzMgL-&a8+m5#^IFRFQ?B%r&l>t-ao_7D@^F9dt=F;oy`|qsurs0*L zNr4cj@2y~GP9NJj1I>;ZG_J5K4CWgf;ZehjYj;8%@0FNO4})$?#)dUC5>IN#xY()R zPky-walC0kiEXA9SvayTNeUKAa9)KH1wtI}84pVjThfIvE1Gdw%gm>g5XXDWqgkh- PFuQ0UxYig0A%^!4i9C-+ literal 0 HcmV?d00001