diff --git a/source/distro/changelog.txt b/source/distro/changelog.txt index edaa205..0835c1c 100644 --- a/source/distro/changelog.txt +++ b/source/distro/changelog.txt @@ -2,6 +2,14 @@ Changelog for Writer2LaTeX version 1.0 -> 1.2 ---------- version 1.1.8 ---------- +[w2x] The EPUB export now supports additional resource files (e.g. images, fonts) to the custom style sheet + - using the readResource method of the converter API + - using the -resource method of the command line application + - using the ResourceURL or Resources property of the filter API + - by specifying the resource files in a custom configuration + +[all] API change: Added the method readResource to the Converter interface (only used by EPUB export currently) + [w2x] Crossed out headings are ignored in EPUB export, but retained in the external toc [all] Added Farsi translation from Mostafa Barmshory diff --git a/source/distro/doc/user-manual.odt b/source/distro/doc/user-manual.odt index 0883b81..0620ee4 100644 Binary files a/source/distro/doc/user-manual.odt and b/source/distro/doc/user-manual.odt differ diff --git a/source/java/org/openoffice/da/comp/w2lcommon/filter/ConfigurationDialogBase.java b/source/java/org/openoffice/da/comp/w2lcommon/filter/ConfigurationDialogBase.java index 447aafd..1824c77 100644 --- a/source/java/org/openoffice/da/comp/w2lcommon/filter/ConfigurationDialogBase.java +++ b/source/java/org/openoffice/da/comp/w2lcommon/filter/ConfigurationDialogBase.java @@ -16,11 +16,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * -* Copyright: 2002-2010 by Henrik Just +* Copyright: 2002-2011 by Henrik Just * * All Rights Reserved. * -* Version 1.2 (2010-12-09) +* Version 1.2 (2011-06-06) * */ @@ -79,13 +79,13 @@ public abstract class ConfigurationDialogBase extends WeakBase implements XConta protected XComponentContext xContext; // File picker wrapper - private FilePicker filePicker = null; + protected FilePicker filePicker = null; // UNO simple file access service protected XSimpleFileAccess2 sfa2 = null; // UNO path substitution - private XStringSubstitution xPathSub = null; + protected XStringSubstitution xPathSub = null; // The configuration implementation protected Config config; @@ -287,6 +287,38 @@ public abstract class ConfigurationDialogBase extends WeakBase implements XConta config.setOption(sConfigName, sConfigValues[dlg.getListBoxSelectedItem(sListBoxName)]); } + // Method to get a named dialog + protected XDialog getDialog(String sDialogName) { + XMultiComponentFactory xMCF = xContext.getServiceManager(); + try { + Object provider = xMCF.createInstanceWithContext( + "com.sun.star.awt.DialogProvider2", xContext); + XDialogProvider2 xDialogProvider = (XDialogProvider2) + UnoRuntime.queryInterface(XDialogProvider2.class, provider); + String sDialogUrl = "vnd.sun.star.script:"+sDialogName+"?location=application"; + return xDialogProvider.createDialog(sDialogUrl); + } + catch (Exception e) { + return null; + } + } + + // Method to display delete dialog + protected boolean deleteItem(String sName) { + XDialog xDialog=getDialog(getDialogLibraryName()+".DeleteDialog"); + if (xDialog!=null) { + DialogAccess ddlg = new DialogAccess(xDialog); + String sLabel = ddlg.getLabelText("DeleteLabel"); + sLabel = sLabel.replaceAll("%s", sName); + ddlg.setLabelText("DeleteLabel", sLabel); + boolean bDelete = xDialog.execute()==ExecutableDialogResults.OK; + xDialog.endExecute(); + return bDelete; + } + return false; + } + + } protected abstract class CustomFileHandler extends PageHandler { @@ -373,7 +405,7 @@ public abstract class ConfigurationDialogBase extends WeakBase implements XConta // Helpers for sfa2 // Checks that the file exists - private boolean fileExists(String sFileName) { + protected boolean fileExists(String sFileName) { try { return sfa2!=null && sfa2.exists(sFileName); } @@ -385,7 +417,7 @@ public abstract class ConfigurationDialogBase extends WeakBase implements XConta } // Delete a file if it exists, return true on success - private boolean killFile(String sFileName) { + protected boolean killFile(String sFileName) { try { if (sfa2!=null && sfa2.exists(sFileName)) { sfa2.kill(sFileName); @@ -453,35 +485,6 @@ public abstract class ConfigurationDialogBase extends WeakBase implements XConta protected abstract class UserListPageHandler extends PageHandler { // Methods to handle user controlled lists - protected XDialog getDialog(String sDialogName) { - XMultiComponentFactory xMCF = xContext.getServiceManager(); - try { - Object provider = xMCF.createInstanceWithContext( - "com.sun.star.awt.DialogProvider2", xContext); - XDialogProvider2 xDialogProvider = (XDialogProvider2) - UnoRuntime.queryInterface(XDialogProvider2.class, provider); - String sDialogUrl = "vnd.sun.star.script:"+sDialogName+"?location=application"; - return xDialogProvider.createDialog(sDialogUrl); - } - catch (Exception e) { - return null; - } - } - - private boolean deleteItem(String sName) { - XDialog xDialog=getDialog(getDialogLibraryName()+".DeleteDialog"); - if (xDialog!=null) { - DialogAccess ddlg = new DialogAccess(xDialog); - String sLabel = ddlg.getLabelText("DeleteLabel"); - sLabel = sLabel.replaceAll("%s", sName); - ddlg.setLabelText("DeleteLabel", sLabel); - boolean bDelete = xDialog.execute()==ExecutableDialogResults.OK; - xDialog.endExecute(); - return bDelete; - } - return false; - } - protected boolean deleteCurrentItem(DialogAccess dlg, String sListName) { String[] sItems = dlg.getListBoxStringItemList(sListName); short nSelected = dlg.getListBoxSelectedItem(sListName); diff --git a/source/java/org/openoffice/da/comp/w2lcommon/filter/FilterDataParser.java b/source/java/org/openoffice/da/comp/w2lcommon/filter/FilterDataParser.java index 1e3f09a..94140aa 100644 --- a/source/java/org/openoffice/da/comp/w2lcommon/filter/FilterDataParser.java +++ b/source/java/org/openoffice/da/comp/w2lcommon/filter/FilterDataParser.java @@ -20,7 +20,7 @@ * * All Rights Reserved. * - * Version 1.2 (2011-01-15) + * Version 1.2 (2011-06-07) * */ @@ -38,6 +38,7 @@ import com.sun.star.io.XOutputStream; import com.sun.star.ucb.CommandAbortedException; import com.sun.star.ucb.XSimpleFileAccess2; import com.sun.star.uno.AnyConverter; +import com.sun.star.uno.Exception; import com.sun.star.uno.UnoRuntime; import com.sun.star.uno.XComponentContext; import com.sun.star.util.XStringSubstitution; @@ -109,7 +110,7 @@ public class FilterDataParser { PropertyHelper props = new PropertyHelper(filterData); - // Get the special properties TemplateURL, StyleSheetURL, Resources, ConfigURL and AutoCreate + // Get the special properties TemplateURL, StyleSheetURL, ResourceURL, Resources, ConfigURL and AutoCreate Object tpl = props.get("TemplateURL"); String sTemplate = null; if (tpl!=null && AnyConverter.isString(tpl)) { @@ -132,7 +133,19 @@ public class FilterDataParser { } } - // This property accepts a semicolon separated list of !! (not very elegant) + // This property accepts an URL pointing to a folder containing the resources to include + Object resourcedir = props.get("ResourceURL"); + String sResourceURL = null; + if (resourcedir!=null && AnyConverter.isString(resourcedir)) { + try { + sResourceURL = substituteVariables(AnyConverter.toString(resourcedir)); + } + catch (com.sun.star.lang.IllegalArgumentException e) { + // Failed to convert to String; should not happen - ignore + } + } + + // This property accepts a semicolon separated list of [[::]::] Object resources = props.get("Resources"); String[] sResources = null; if (resources!=null && AnyConverter.isString(resources)) { @@ -218,33 +231,70 @@ public class FilterDataParser { } } + // Load the resource from the specified folder URL, if any + if (sfa2!=null && sResourceURL!=null && sResourceURL.length()>0) { + String[] sURLs; + try { + sURLs = sfa2.getFolderContents(sResourceURL, false); // do not include folders + for (String sURL : sURLs) { + XInputStream xIs = sfa2.openFileRead(sURL); + if (xIs!=null) { + String sFileName = sURL.substring(sURL.lastIndexOf('/')+1); + InputStream is = new XInputStreamToInputStreamAdapter(xIs); + converter.readResource(is,sFileName,null); + is.close(); + xIs.closeInput(); + } + } + } catch (IOException e) { + // ignore + } catch (CommandAbortedException e1) { + // ignore + } catch (Exception e1) { + // ignore + } + } + // Load the resources from the specified URLs, if any if (sfa2!=null && sResources!=null) { for (String sResource : sResources) { - try { - String[] sParts = sResource.split("!"); + // Format is [[::]::] + String[] sParts = sResource.split("::"); + if (sParts.length>0) { + String sURL=sParts[0]; + String sFileName; + String sMediaType=null; if (sParts.length==3) { - // Format is !! - XInputStream xIs = sfa2.openFileRead(sParts[2]); + sFileName = sParts[1]; + sMediaType = sParts[2]; + } + else { + sFileName = sURL.substring(sURL.lastIndexOf('/')+1); + if (sParts.length==2) { + sMediaType = sParts[1]; + } + } + try { + XInputStream xIs = sfa2.openFileRead(sURL); if (xIs!=null) { InputStream is = new XInputStreamToInputStreamAdapter(xIs); - converter.readResource(is, sParts[1], sParts[0]); + converter.readResource(is, sFileName, sMediaType); is.close(); xIs.closeInput(); - } - } // otherwise wrong format, ignore - } - catch (IOException e) { - // ignore - } - catch (NotConnectedException e) { - // ignore - } - catch (CommandAbortedException e) { - // ignore - } - catch (com.sun.star.uno.Exception e) { - // ignore + } // otherwise wrong format, ignore + } + catch (IOException e) { + // ignore + } + catch (NotConnectedException e) { + // ignore + } + catch (CommandAbortedException e) { + // ignore + } + catch (com.sun.star.uno.Exception e) { + // ignore + } } } } diff --git a/source/java/org/openoffice/da/comp/w2lcommon/filter/OptionsDialogBase.java b/source/java/org/openoffice/da/comp/w2lcommon/filter/OptionsDialogBase.java index 57199a8..c222932 100644 --- a/source/java/org/openoffice/da/comp/w2lcommon/filter/OptionsDialogBase.java +++ b/source/java/org/openoffice/da/comp/w2lcommon/filter/OptionsDialogBase.java @@ -20,7 +20,7 @@ * * All Rights Reserved. * - * Version 1.2 (2011-02-23) + * Version 1.2 (2011-06-07) * */ @@ -393,21 +393,39 @@ public abstract class OptionsDialogBase extends DialogBase implements short nConfig = getListBoxSelectedItem("Config"); int nStdConfigs = getListBoxStringItemList("Config").length - sConfigNames.length; if (nConfig>=nStdConfigs) { // only handle registry configurations - int i = nConfig-nStdConfigs; - try { - Object config = xNameAccess.getByName(sConfigNames[i]); - XPropertySet xCfgProps = (XPropertySet) - UnoRuntime.queryInterface(XPropertySet.class,config); - MacroExpander expander = new MacroExpander(xContext); - filterData.put("ConfigURL",expander.expandMacros(XPropertySetHelper.getPropertyValueAsString(xCfgProps,"ConfigURL"))); - filterData.put("TemplateURL",expander.expandMacros(XPropertySetHelper.getPropertyValueAsString(xCfgProps,"TargetTemplateURL"))); - filterData.put("StyleSheetURL",expander.expandMacros(XPropertySetHelper.getPropertyValueAsString(xCfgProps,"StyleSheetURL"))); - // TODO: Resources... - XPropertySetHelper.setPropertyValue(xProps,"ConfigName",sConfigNames[i]); - bFound = true; - } - catch (Exception e) { - } + int i = nConfig-nStdConfigs; + try { + Object config = xNameAccess.getByName(sConfigNames[i]); + XPropertySet xCfgProps = (XPropertySet) + UnoRuntime.queryInterface(XPropertySet.class,config); + MacroExpander expander = new MacroExpander(xContext); + filterData.put("ConfigURL",expander.expandMacros(XPropertySetHelper.getPropertyValueAsString(xCfgProps,"ConfigURL"))); + filterData.put("TemplateURL",expander.expandMacros(XPropertySetHelper.getPropertyValueAsString(xCfgProps,"TargetTemplateURL"))); + filterData.put("StyleSheetURL",expander.expandMacros(XPropertySetHelper.getPropertyValueAsString(xCfgProps,"StyleSheetURL"))); + + // The resources are provided as a set + Object resources = XPropertySetHelper.getPropertyValue(xCfgProps,"Resources"); + XNameAccess xResourceNameAccess = (XNameAccess) UnoRuntime.queryInterface(XNameAccess.class,resources); + if (xResourceNameAccess!=null) { + StringBuffer buf = new StringBuffer(); + String[] sResourceNames = xResourceNameAccess.getElementNames(); + for (String sName : sResourceNames) { + Object resource = xResourceNameAccess.getByName(sName); + XPropertySet xResourceProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class,resource); + String sURL = expander.expandMacros(XPropertySetHelper.getPropertyValueAsString(xResourceProps,"URL")); + String sFileName = expander.expandMacros(XPropertySetHelper.getPropertyValueAsString(xResourceProps,"FileName")); + String sMediaType = expander.expandMacros(XPropertySetHelper.getPropertyValueAsString(xResourceProps,"MediaType")); + if (buf.length()>0) { buf.append(';'); } + buf.append(sURL).append("::").append(sFileName).append("::").append(sMediaType); + } + filterData.put("Resources",buf.toString()); + + XPropertySetHelper.setPropertyValue(xProps,"ConfigName",sConfigNames[i]); + bFound = true; + } + } + catch (Exception e) { + } } XPropertySetHelper.setPropertyValue(xProps,"Config",nConfig); if (!bFound) { XPropertySetHelper.setPropertyValue(xProps,"ConfigName",""); } diff --git a/source/java/org/openoffice/da/comp/writer2xhtml/ConfigurationDialog.java b/source/java/org/openoffice/da/comp/writer2xhtml/ConfigurationDialog.java index 8efea47..e7aa123 100644 --- a/source/java/org/openoffice/da/comp/writer2xhtml/ConfigurationDialog.java +++ b/source/java/org/openoffice/da/comp/writer2xhtml/ConfigurationDialog.java @@ -20,7 +20,7 @@ * * All Rights Reserved. * -* Version 1.2 (2011-03-08) +* Version 1.2 (2011-06-06) * */ @@ -30,11 +30,16 @@ import java.util.Map; import org.openoffice.da.comp.w2lcommon.filter.ConfigurationDialogBase; import org.openoffice.da.comp.w2lcommon.helper.DialogAccess; +import org.openoffice.da.comp.w2lcommon.helper.FilePicker; +import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.XServiceInfo; +import com.sun.star.ucb.CommandAbortedException; +import com.sun.star.uno.Exception; import com.sun.star.uno.XComponentContext; public class ConfigurationDialog extends ConfigurationDialogBase implements XServiceInfo { + private String sResourceDirName; // Implement the interface XServiceInfo @@ -70,6 +75,14 @@ public class ConfigurationDialog extends ConfigurationDialogBase implements XSer public ConfigurationDialog(XComponentContext xContext) { super(xContext); + // Create the resource dir name + try { + sResourceDirName = xPathSub.substituteVariables("$(user)/writer2xhtml-resources", false); + } + catch (NoSuchElementException e) { + sResourceDirName = "writer2xhtml-resources"; + } + pageHandlers.put("General", new GeneralHandler()); pageHandlers.put("Template", new TemplateHandler()); pageHandlers.put("Stylesheets", new StylesheetsHandler()); @@ -84,7 +97,8 @@ public class ConfigurationDialog extends ConfigurationDialogBase implements XSer public String[] getSupportedMethodNames() { String[] sNames = { "EncodingChange", // General "CustomTemplateChange", "LoadTemplateClick", // Template - "UseCustomStylesheetChange", "IncludeCustomStylesheetClick", "LoadStylesheetClick", // Stylesheet + "UseCustomStylesheetChange", "IncludeCustomStylesheetClick", "LoadStylesheetClick", + "NewResourceClick", "DeleteResourceClick", // Stylesheet "StyleFamilyChange", "StyleNameChange", "NewStyleClick", "DeleteStyleClick", "LoadDefaultsClick" // Styles1 }; return sNames; @@ -198,6 +212,11 @@ public class ConfigurationDialog extends ConfigurationDialogBase implements XSer } protected void useCustomInner(DialogAccess dlg, boolean bEnable) { + dlg.setControlEnabled("ResourceLabel", bEnable); + dlg.setControlEnabled("Resources", bEnable); + dlg.setControlEnabled("NewResourceButton", bEnable); + dlg.setControlEnabled("DeleteResourceButton", bEnable); + updateResources(dlg); } @@ -207,6 +226,8 @@ public class ConfigurationDialog extends ConfigurationDialogBase implements XSer textFieldFromConfig(dlg, "CustomStylesheetURL", "custom_stylesheet"); linkCustomStylesheetChange(dlg); + + updateResources(dlg); } @Override protected void getControls(DialogAccess dlg) { @@ -227,15 +248,80 @@ public class ConfigurationDialog extends ConfigurationDialogBase implements XSer linkCustomStylesheetChange(dlg); return true; } + else if (sMethod.equals("NewResourceClick")) { + newResourceClick(dlg); + return true; + } + else if (sMethod.equals("DeleteResourceClick")) { + deleteResourceClick(dlg); + return true; + } return false; } - private void linkCustomStylesheetChange(DialogAccess dlg) { + private void linkCustomStylesheetChange(DialogAccess dlg) { boolean bLinkCustomStylesheet = dlg.getCheckBoxStateAsBoolean("LinkCustomStylesheet"); dlg.setControlEnabled("CustomStylesheetURLLabel", bLinkCustomStylesheet); dlg.setControlEnabled("CustomStylesheetURL", bLinkCustomStylesheet); } + private void newResourceClick(DialogAccess dlg) { + FilePicker filePicker = new FilePicker(xContext); + String sFileName=filePicker.getPath(); + if (sFileName!=null) { + createResourceDir(); + String sBaseFileName = sFileName.substring(sFileName.lastIndexOf('/')); + try { + String sTargetFileName = sResourceDirName+"/"+sBaseFileName; + if (fileExists(sTargetFileName)) { killFile(sTargetFileName); } + sfa2.copy(sFileName, sTargetFileName); + } catch (CommandAbortedException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + updateResources(dlg); + } + } + + private void deleteResourceClick(DialogAccess dlg) { + int nItem = dlg.getListBoxSelectedItem("Resources"); + if (nItem>=0) { + String sFileName = dlg.getListBoxStringItemList("Resources")[nItem]; + if (deleteItem(sFileName)) { + killFile(sResourceDirName+"/"+sFileName); + updateResources(dlg); + } + } + } + + private void createResourceDir() { + try { + if (!sfa2.isFolder(sResourceDirName)) { + sfa2.createFolder(sResourceDirName); + } + } catch (CommandAbortedException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void updateResources(DialogAccess dlg) { + try { + String[] sFiles = sfa2.getFolderContents(sResourceDirName, false); // do not include folders + int nCount = sFiles.length; + for (int i=0; i-config[=]filename *
  • -template[=]filename *
  • -stylesheet[=]filename + *
  • -resource[=]filename[::media type] *
  • -option[=]value * *

    where option can be any simple option known to Writer2LaTeX @@ -72,6 +75,7 @@ public final class Application { private Vector configFileNames = new Vector(); private String sTemplateFileName = null; private String sStyleSheetFileName = null; + private Set resources = new HashSet(); private Hashtable options = new Hashtable(); private String sSource = null; private String sTarget = null; @@ -194,6 +198,30 @@ public final class Application { System.out.println(" "+e.getMessage()); } } + + // Step 5c: Read style resources + for (String sResource : resources) { + String sMediaType; + String sFileName; + int nSeparator = sResource.indexOf("::"); + if (nSeparator>-1) { + sFileName = sResource.substring(0,nSeparator); + sMediaType = sResource.substring(nSeparator+2); + } + else { + sFileName = sResource; + sMediaType = null; + } + System.out.println("Reading resource file "+sFileName); + try { + byte [] resourceBytes = Misc.inputStreamToByteArray(new FileInputStream(sFileName)); + converter.readResource(new ByteArrayInputStream(resourceBytes),sFileName,sMediaType); + } catch (IOException e) { + System.out.println("--> Failed to read the resource file!"); + System.out.println(" "+e.getMessage()); + } + + } // Step 6: Read config for (int i=0; i"); System.out.println(" -stylesheet[=]