bug 427395: Improve OPSPublication API https://bugs.eclipse.org/bugs/show_bug.cgi?id=427395 Change-Id: I81f308e6cef7536ba99ffc3f7b17022836dfbd61
diff --git a/org.eclipse.mylyn.docs.epub-feature/feature.xml b/org.eclipse.mylyn.docs.epub-feature/feature.xml index f15c184..5dd8cfc 100644 --- a/org.eclipse.mylyn.docs.epub-feature/feature.xml +++ b/org.eclipse.mylyn.docs.epub-feature/feature.xml
@@ -2,7 +2,7 @@ <feature id="org.eclipse.mylyn.docs.epub" label="%featureName" - version="1.3.0.qualifier" + version="2.0.0.qualifier" provider-name="%providerName" plugin="org.eclipse.mylyn.docs.epub.core">
diff --git a/org.eclipse.mylyn.docs.epub-feature/pom.xml b/org.eclipse.mylyn.docs.epub-feature/pom.xml index 76a063d..8995d3a 100644 --- a/org.eclipse.mylyn.docs.epub-feature/pom.xml +++ b/org.eclipse.mylyn.docs.epub-feature/pom.xml
@@ -8,7 +8,7 @@ <version>2.0.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.mylyn.docs.epub</artifactId> - <version>1.3.0-SNAPSHOT</version> + <version>2.0.0-SNAPSHOT</version> <packaging>eclipse-feature</packaging> <groupId>org.eclipse.mylyn.docs.epub</groupId> </project>
diff --git a/org.eclipse.mylyn.docs.epub.ant.core/src/org/eclipse/mylyn/docs/epub/ant/core/EpubTask.java b/org.eclipse.mylyn.docs.epub.ant.core/src/org/eclipse/mylyn/docs/epub/ant/core/EpubTask.java index e3f8019..45df468 100644 --- a/org.eclipse.mylyn.docs.epub.ant.core/src/org/eclipse/mylyn/docs/epub/ant/core/EpubTask.java +++ b/org.eclipse.mylyn.docs.epub.ant.core/src/org/eclipse/mylyn/docs/epub/ant/core/EpubTask.java
@@ -19,8 +19,8 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.eclipse.mylyn.docs.epub.core.EPUB; -import org.eclipse.mylyn.docs.epub.core.OPS2Publication; import org.eclipse.mylyn.docs.epub.core.OPSPublication; +import org.eclipse.mylyn.docs.epub.core.Publication; import org.eclipse.mylyn.docs.epub.opf.Role; /** @@ -31,7 +31,7 @@ */ public class EpubTask extends Task { - private OPSPublication oebps = null; + private Publication oebps = null; private ArrayList<FileSetType> filesets = null; @@ -47,7 +47,7 @@ super(); try { logger = new AntLogger(this); - oebps = new OPS2Publication(logger); + oebps = new OPSPublication(logger); filesets = new ArrayList<FileSetType>(); } catch (Exception e) { e.printStackTrace();
diff --git a/org.eclipse.mylyn.docs.epub.core/META-INF/MANIFEST.MF b/org.eclipse.mylyn.docs.epub.core/META-INF/MANIFEST.MF index 1b65eaf..5aab78e 100644 --- a/org.eclipse.mylyn.docs.epub.core/META-INF/MANIFEST.MF +++ b/org.eclipse.mylyn.docs.epub.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.mylyn.docs.epub.core;singleton:=true -Bundle-Version: 1.3.0.qualifier +Bundle-Version: 2.0.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Require-Bundle: org.eclipse.emf.ecore;bundle-version="2.5.0",
diff --git a/org.eclipse.mylyn.docs.epub.core/pom.xml b/org.eclipse.mylyn.docs.epub.core/pom.xml index 1b32176..3e796bf 100644 --- a/org.eclipse.mylyn.docs.epub.core/pom.xml +++ b/org.eclipse.mylyn.docs.epub.core/pom.xml
@@ -8,7 +8,7 @@ <version>2.0.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.mylyn.docs.epub.core</artifactId> - <version>1.3.0-SNAPSHOT</version> + <version>2.0.0-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> <properties> <target-version>${alt-target-version}</target-version>
diff --git a/org.eclipse.mylyn.docs.epub.core/src-gen/org/eclipse/mylyn/docs/epub/opf/Item.java b/org.eclipse.mylyn.docs.epub.core/src-gen/org/eclipse/mylyn/docs/epub/opf/Item.java index 691217b..e0441a0 100644 --- a/org.eclipse.mylyn.docs.epub.core/src-gen/org/eclipse/mylyn/docs/epub/opf/Item.java +++ b/org.eclipse.mylyn.docs.epub.core/src-gen/org/eclipse/mylyn/docs/epub/opf/Item.java
@@ -316,6 +316,7 @@ /** * Sets the value of the '{@link org.eclipse.mylyn.docs.epub.opf.Item#isGenerated <em>Generated</em>}' attribute. * <!-- begin-user-doc --> + * Indicates that the item has been generated by the EPUB tools. This applies for instance to the cover page HTML code. * <!-- end-user-doc --> * @param value the new value of the '<em>Generated</em>' attribute. * @see #isGenerated()
diff --git a/org.eclipse.mylyn.docs.epub.core/src-gen/org/eclipse/mylyn/docs/epub/opf/impl/ReferenceImpl.java b/org.eclipse.mylyn.docs.epub.core/src-gen/org/eclipse/mylyn/docs/epub/opf/impl/ReferenceImpl.java index f93bc21..ee63635 100644 --- a/org.eclipse.mylyn.docs.epub.core/src-gen/org/eclipse/mylyn/docs/epub/opf/impl/ReferenceImpl.java +++ b/org.eclipse.mylyn.docs.epub.core/src-gen/org/eclipse/mylyn/docs/epub/opf/impl/ReferenceImpl.java
@@ -15,7 +15,6 @@ import org.eclipse.mylyn.docs.epub.opf.OPFPackage; import org.eclipse.mylyn.docs.epub.opf.Reference; -import org.eclipse.mylyn.docs.epub.opf.Type; /** * <!-- begin-user-doc -->
diff --git a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/EPUB.java b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/EPUB.java index dc710aa..1f2517e 100644 --- a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/EPUB.java +++ b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/EPUB.java
@@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright (c) 2011,2012 Torkild U. Resheim. - * + * Copyright (c) 2011-2014 Torkild U. Resheim. + * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: + * + * Contributors: * Torkild U. Resheim - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.docs.epub.core; @@ -54,7 +54,7 @@ * <p> * The simplest usage of this API may look like the following: * </p> - * + * * <pre> * EPUB epub = new EPUB(); * OPSPublication oebps = new OPS2Publication(); @@ -66,7 +66,7 @@ * This will create a new EPUB instance and an OPS (which is the typical content of an EPUB) with one chapter. The OPS * will have one chapter with contents from <b>chapter.xhtml</b> and the final result is an EPUB named <b>book.epub</b>. * </p> - * + * * @author Torkild U. Resheim * @see http://www.idpf.org/doc_library/epub/OPS_2.0.1_draft.htm */ @@ -108,7 +108,7 @@ private Container ocfContainer; /** - * Creates a new <b>empty</b> instance of an EPUB. Use {@link #add(OPSPublication)} and {@link #pack(File)} to add + * Creates a new <b>empty</b> instance of an EPUB. Use {@link #add(Publication)} and {@link #pack(File)} to add * publications and ready the EPUB for distribution. */ public EPUB() { @@ -125,19 +125,26 @@ } /** - * Adds a new publication (or root file) to the EPUB. Use {@link #add(OPSPublication)} when adding an OEBPS + * Adds a new publication (or root file) to the EPUB. Use {@link #add(Publication)} when adding an OEBPS * publication. - * + * <p> + * Note that while an {@link EPUB} can technically contain multiple instances of an {@link Publication}, in + * practice reading systems does not support this. + * </p> + * * @param file * the publication to add * @param type * the MIME type of the publication - * @see #add(OPSPublication) + * @see #add(Publication) */ public void add(File file, String type) { String name = type.substring(type.lastIndexOf('/') + 1, type.length()).toUpperCase(); RootFiles rootFiles = ocfContainer.getRootfiles(); int count = rootFiles.getRootfiles().size(); + if (count >= 1) { + log("Multiple root files is unsupported by most reading systems!", Severity.WARNING); //$NON-NLS-1$ + } String rootFileName = count > 0 ? name + "_" + count : name; //$NON-NLS-1$ rootFileName += File.separator + file.getName(); RootFile rootFile = OCFFactory.eINSTANCE.createRootFile(); @@ -151,13 +158,20 @@ /** * Adds a new OEBPS publication to the EPUB. Use {@link #add(File, String)} to add other types of content. - * + * <p> + * Note that while an {@link EPUB} can technically contain multiple instances of an {@link Publication}, in + * practice reading systems does not support this. + * </p> + * * @param oebps * the publication to add. */ - public void add(OPSPublication oebps) { + public void add(Publication oebps) { RootFiles rootFiles = ocfContainer.getRootfiles(); int count = rootFiles.getRootfiles().size(); + if (count >= 1) { + log("Multiple root files is unsupported by most reading systems!", Severity.WARNING); //$NON-NLS-1$ + } String rootFileName = count > 0 ? "OEBPS_" + count : "OEBPS"; //$NON-NLS-1$ //$NON-NLS-2$ rootFileName += "/content.opf"; //$NON-NLS-1$ RootFile rootFile = OCFFactory.eINSTANCE.createRootFile(); @@ -171,7 +185,7 @@ /** * Utility method for deleting a folder recursively. - * + * * @param folder * the folder to delete */ @@ -187,7 +201,7 @@ /** * Returns the container instance of the EPUB. - * + * * @return the container instance */ public Container getContainer() { @@ -198,18 +212,18 @@ * Returns a list of all <i>OPS publications</i> contained within the EPUB. Publications in unsupported versions * will not be returned. However their existence can still be determined by looking at the * {@link Container#getRootfiles()} result. - * + * * @return a list of all OPS publications * @see {@link #getContainer()} for obtaining the root file container */ - public List<OPSPublication> getOPSPublications() { - ArrayList<OPSPublication> publications = new ArrayList<OPSPublication>(); + public List<Publication> getOPSPublications() { + ArrayList<Publication> publications = new ArrayList<Publication>(); EList<RootFile> rootFiles = ocfContainer.getRootfiles().getRootfiles(); for (RootFile rootFile : rootFiles) { if (rootFile.getMediaType().equals(MIMETYPE_OEBPS)) { // May be null if the publications is in an unsupported format. if (rootFile.getPublication() != null) { - publications.add((OPSPublication) rootFile.getPublication()); + publications.add((Publication) rootFile.getPublication()); } } } @@ -220,7 +234,7 @@ * Use to check whether or not the specified file is in a supported format and can be opened as an EPUB. If it's not * an EPUB <code>false</code> will be returned. Note that this methods does not test the contents of the EPUB which * may or may not contain unsupported root files. - * + * * @param epubFile * the target EPUB file * @return <code>true</code> if the file can be opened @@ -240,7 +254,7 @@ * Used to verify that the given {@link InputStream} contents is an EPUB. As per specification the first entry in * the file must be named "mimetype" and contain the string <i>application/epub+zip</i>. Further verification is not * done at this stage. - * + * * @param inputStream * the EPUB input stream * @return <code>true</code> if the file is an EPUB file @@ -273,7 +287,7 @@ /** * Tests whether or not the OEBPS is in a version that is supported by this tooling. - * + * * @param rootFile * the root file * @return <code>true</code> if the OEBPS can be read @@ -311,7 +325,7 @@ /** * Assembles the EPUB file using a temporary working folder. The folder will be deleted as soon as the assembly has * completed. - * + * * @param epubFile * the target EPUB file * @throws Exception @@ -329,7 +343,7 @@ * Assembles the EPUB file using the specified working folder. The contents of the working folder will <b>not</b> be * removed when the operation has completed. If the temporary data is not interesting, use {@link #pack(File)} * instead. - * + * * @param epubFile * the target EPUB file * @param rootFolder @@ -349,8 +363,8 @@ for (RootFile rootFile : publications) { Object publication = rootFile.getPublication(); File root = new File(rootFolder.getAbsolutePath() + File.separator + rootFile.getFullPath()); - if (publication instanceof OPSPublication) { - ((OPSPublication) publication).pack(root); + if (publication instanceof Publication) { + ((Publication) publication).pack(root); } else { if (rootFile.getPublication() instanceof File) { EPUBFileUtil.copy((File) rootFile.getPublication(), root); @@ -370,7 +384,7 @@ /** * Reads the <i>Open Container Format (OCF)</i> formatted list of contents of this EPUB. The result of this * operation is placed in the {@link #ocfContainer} instance. - * + * * @param rootFolder * the folder where the EPUB was unpacked * @throws IOException @@ -405,35 +419,35 @@ Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(OCF_FILE_SUFFIX, new XMLResourceFactoryImpl() { - @Override - public Resource createResource(URI uri) { - OCFResourceImpl xmiResource = new OCFResourceImpl(uri); - Map<Object, Object> loadOptions = xmiResource.getDefaultLoadOptions(); - Map<Object, Object> saveOptions = xmiResource.getDefaultSaveOptions(); - // We use extended metadata - saveOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); - loadOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); - // Required in order to correctly read in attributes - loadOptions.put(XMLResource.OPTION_LAX_FEATURE_PROCESSING, Boolean.TRUE); - // Treat "href" attributes as features - loadOptions.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE); - // UTF-8 encoding is required per specification - saveOptions.put(XMLResource.OPTION_ENCODING, OCF_FILE_ENCODING); - // Do not download any external DTDs. - Map<String, Object> parserFeatures = new HashMap<String, Object>(); - parserFeatures.put("http://xml.org/sax/features/validation", Boolean.FALSE); //$NON-NLS-1$ - parserFeatures.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", //$NON-NLS-1$ - Boolean.FALSE); - loadOptions.put(XMLResource.OPTION_PARSER_FEATURES, parserFeatures); - return xmiResource; - } + @Override + public Resource createResource(URI uri) { + OCFResourceImpl xmiResource = new OCFResourceImpl(uri); + Map<Object, Object> loadOptions = xmiResource.getDefaultLoadOptions(); + Map<Object, Object> saveOptions = xmiResource.getDefaultSaveOptions(); + // We use extended metadata + saveOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); + loadOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); + // Required in order to correctly read in attributes + loadOptions.put(XMLResource.OPTION_LAX_FEATURE_PROCESSING, Boolean.TRUE); + // Treat "href" attributes as features + loadOptions.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE); + // UTF-8 encoding is required per specification + saveOptions.put(XMLResource.OPTION_ENCODING, OCF_FILE_ENCODING); + // Do not download any external DTDs. + Map<String, Object> parserFeatures = new HashMap<String, Object>(); + parserFeatures.put("http://xml.org/sax/features/validation", Boolean.FALSE); //$NON-NLS-1$ + parserFeatures.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", //$NON-NLS-1$ + Boolean.FALSE); + loadOptions.put(XMLResource.OPTION_PARSER_FEATURES, parserFeatures); + return xmiResource; + } - }); + }); } /** * Unpacks the EPUB file to a temporary location and populates the data model with the content. - * + * * @param epubFile * the EPUB file to unpack * @return the location when the EPUB is unpacked @@ -460,10 +474,10 @@ * </p> * <p> * Multiple OPS root files in the publication will populate the OCF container instance with one - * {@link OPSPublication} for each as expected. The contents of the data model starting with the OCF container will + * {@link Publication} for each as expected. The contents of the data model starting with the OCF container will * be replaced. If the publication is in an unsupported version it will not be added to the data model. * </p> - * + * * @param epubFile * the EPUB file to unpack * @param rootFolder @@ -486,7 +500,7 @@ if (rootFile.getMediaType().equals(MIMETYPE_OEBPS)) { File root = new File(rootFolder.getAbsolutePath() + File.separator + rootFile.getFullPath()); if (isSupportedOEBPS(root)) { - OPSPublication ops = OPSPublication.getVersion2Instance(); + Publication ops = Publication.getVersion2Instance(); ops.unpack(root); rootFile.setPublication(ops); } else { @@ -500,7 +514,7 @@ /** * Creates a new folder named META-INF and writes the required (as per the OPS specification) <b>container.xml</b> * in that folder. This is part of the packing procedure. - * + * * @param rootFolder * the root folder * @see <a href="http://idpf.org/epub/30/spec/epub30-ocf.html">EPUB3 OCF specification</a>
diff --git a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/OPS2Publication.java b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/OPS2Publication.java deleted file mode 100644 index 5fc98a2..0000000 --- a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/OPS2Publication.java +++ /dev/null
@@ -1,352 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011,2012 Torkild U. Resheim. - * - * All rights reserved. This program and the accompanying materials are made - * available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Torkild U. Resheim - initial API and implementation - *******************************************************************************/ -package org.eclipse.mylyn.docs.epub.core; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileReader; -import java.io.IOException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.xml.parsers.ParserConfigurationException; - -import org.eclipse.emf.common.util.EList; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import org.eclipse.emf.ecore.util.FeatureMapUtil; -import org.eclipse.emf.ecore.xmi.XMLHelper; -import org.eclipse.emf.ecore.xmi.XMLResource; -import org.eclipse.mylyn.docs.epub.core.ILogger.Severity; -import org.eclipse.mylyn.docs.epub.ncx.DocTitle; -import org.eclipse.mylyn.docs.epub.ncx.Head; -import org.eclipse.mylyn.docs.epub.ncx.Meta; -import org.eclipse.mylyn.docs.epub.ncx.NCXFactory; -import org.eclipse.mylyn.docs.epub.ncx.NCXPackage; -import org.eclipse.mylyn.docs.epub.ncx.NavMap; -import org.eclipse.mylyn.docs.epub.ncx.Ncx; -import org.eclipse.mylyn.docs.epub.ncx.Text; -import org.eclipse.mylyn.docs.epub.ncx.util.NCXResourceFactoryImpl; -import org.eclipse.mylyn.docs.epub.ncx.util.NCXResourceImpl; -import org.eclipse.mylyn.docs.epub.opf.Guide; -import org.eclipse.mylyn.docs.epub.opf.Item; -import org.eclipse.mylyn.docs.epub.opf.Itemref; -import org.eclipse.mylyn.docs.epub.opf.Manifest; -import org.eclipse.mylyn.docs.epub.opf.Metadata; -import org.eclipse.mylyn.docs.epub.opf.OPFFactory; -import org.eclipse.mylyn.docs.epub.opf.Spine; -import org.eclipse.mylyn.internal.docs.epub.core.EPUBXMLHelperImp; -import org.eclipse.mylyn.internal.docs.epub.core.OPS2Validator; -import org.eclipse.mylyn.internal.docs.epub.core.TOCGenerator; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -/** - * This type represents one EPUB revision 2.0.1 formatted publication. It maintains a data structure representing the - * entire publication and API for building it. - * <p> - * <b>Please note that this API is provisional and should not yet be used to build applications.</b> - * </p> - * - * @author Torkild U. Resheim - * @see http://www.niso.org/workrooms/daisy/Z39-86-2005.html - */ -public class OPS2Publication extends OPSPublication { - - /** MIME type for NCX documents */ - private static final String MIMETYPE_NCX = "application/x-dtbncx+xml"; //$NON-NLS-1$ - - private static final String NCX_FILE_SUFFIX = "ncx"; //$NON-NLS-1$ - - /** Identifier of the table of contents file */ - private static final String TABLE_OF_CONTENTS_ID = "ncx"; //$NON-NLS-1$ - - /** Default name for the table of contents */ - private static final String TOCFILE_NAME = "toc.ncx"; //$NON-NLS-1$ - - /** List of core media types as specified in http://idpf.org/epub/20/spec/OPS_2.0.1_draft.htm#Section1.3.7 */ - private static final String[] CORE_MEDIA_TYPES = new String[] { "image/gif", "image/jpeg", "image/png", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - "image/svg+xml", "application/xhtml+xml", "application/x-dtbook+xml", "text/css", "application/xml", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ - "text/x-oeb1-document", "text/x-oeb1-css", "application/x-dtbncx+xml" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - - /** The table of contents */ - private Ncx ncxTOC; - - /** - * Creates a new EPUB. - */ - public OPS2Publication() { - super(); - setup(); - } - - /** - * Creates a new EPUB logging all event to the specified logger. - */ - public OPS2Publication(ILogger logger) { - super(logger); - setup(); - } - - /** - * This mechanism will traverse the spine of the publication (which is representing the reading order) and parse - * each file for information that can be used to assemble a table of contents. Only XHTML type of files will be - * taken into consideration. - * - * @throws SAXException - * @throws IOException - * @throws ParserConfigurationException - */ - @Override - protected void generateTableOfContents() throws ParserConfigurationException, SAXException, IOException { - log(Messages.getString("OPS2Publication.0"), Severity.INFO, indent++); //$NON-NLS-1$ - Meta meta = NCXFactory.eINSTANCE.createMeta(); - meta.setName("dtb:uid"); //$NON-NLS-1$ - meta.setContent(getIdentifier().getMixed().getValue(0).toString()); - ncxTOC.getHead().getMetas().add(meta); - int playOrder = 0; - // Iterate over the spine - EList<Itemref> spineItems = getSpine().getSpineItems(); - EList<Item> manifestItems = opfPackage.getManifest().getItems(); - for (Itemref itemref : spineItems) { - Item referencedItem = null; - String id = itemref.getIdref(); - // Find the manifest item that is referenced - for (Item item : manifestItems) { - if (item.getId().equals(id)) { - referencedItem = item; - break; - } - } - if (referencedItem != null && !referencedItem.isNoToc() - && referencedItem.getMedia_type().equals(MIMETYPE_XHTML)) { - File file = new File(referencedItem.getFile()); - FileInputStream fis = new FileInputStream(file); - log(MessageFormat.format(Messages.getString("OPS2Publication.1"), referencedItem.getHref()), Severity.VERBOSE, indent); //$NON-NLS-1$ - playOrder = TOCGenerator.parse(new InputSource(fis), referencedItem.getHref(), ncxTOC, playOrder); - } - } - indent--; - } - - @Override - public Object getTableOfContents() { - return ncxTOC; - } - - @Override - protected String getVersion() { - return "2.0"; //$NON-NLS-1$ - } - - @Override - protected void readTableOfContents(File tocFile) throws IOException { - ResourceSet resourceSet = new ResourceSetImpl(); - URI fileURI = URI.createFileURI(tocFile.getAbsolutePath()); - Resource resource = resourceSet.createResource(fileURI); - resource.load(null); - ncxTOC = (Ncx) resource.getContents().get(0); - } - - /** - * Registers a new resource factory for NCX data structures. This is normally done through Eclipse extension points - * but we also need to be able to create this factory without the Eclipse runtime. - */ - private void registerNCXResourceFactory() { - // Register package so that it is available even without the Eclipse runtime - @SuppressWarnings("unused") - NCXPackage packageInstance = NCXPackage.eINSTANCE; - - Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(NCX_FILE_SUFFIX, - new NCXResourceFactoryImpl() { - @Override - public Resource createResource(URI uri) { - NCXResourceImpl xmiResource = new NCXResourceImpl(uri) { - - @Override - protected XMLHelper createXMLHelper() { - EPUBXMLHelperImp xmlHelper = new EPUBXMLHelperImp(); - return xmlHelper; - } - - }; - Map<Object, Object> loadOptions = xmiResource.getDefaultLoadOptions(); - Map<Object, Object> saveOptions = xmiResource.getDefaultSaveOptions(); - // We use extended metadata - saveOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); - loadOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); - // Required in order to correctly read in attributes - loadOptions.put(XMLResource.OPTION_LAX_FEATURE_PROCESSING, Boolean.TRUE); - // Treat "href" attributes as features - loadOptions.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE); - // UTF-8 encoding is required per specification - saveOptions.put(XMLResource.OPTION_ENCODING, XML_ENCODING); - // Do not download any external DTDs. - Map<String, Object> parserFeatures = new HashMap<String, Object>(); - parserFeatures.put("http://xml.org/sax/features/validation", Boolean.FALSE); //$NON-NLS-1$ - parserFeatures.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", //$NON-NLS-1$ - Boolean.FALSE); - loadOptions.put(XMLResource.OPTION_PARSER_FEATURES, parserFeatures); - return xmiResource; - } - - }); - } - - @Override - public void setTableOfContents(File ncxFile) { - // Add the file to the publication and make sure we use the table of - // contents identifier. - Item item = addItem(opfPackage.getSpine().getToc(), null, ncxFile, null, MIMETYPE_NCX, false, false, false); - // The table of contents file must be first. - opfPackage.getManifest().getItems().move(0, item); - log(MessageFormat.format("Using table of contents file {0} for OPS", new Object[] { ncxFile.getName() }), //$NON-NLS-1$ - Severity.VERBOSE, indent); - } - - private void setup() { - opfPackage.setVersion(getVersion()); - ncxTOC = NCXFactory.eINSTANCE.createNcx(); - // Set the required version attribute - ncxTOC.setVersion("2005-1"); //$NON-NLS-1$ - // Create the required head element - Head head = NCXFactory.eINSTANCE.createHead(); - ncxTOC.setHead(head); - // Create the required title element - DocTitle docTitle = NCXFactory.eINSTANCE.createDocTitle(); - Text text = NCXFactory.eINSTANCE.createText(); - FeatureMapUtil.addText(text.getMixed(), "Table of contents"); //$NON-NLS-1$ - docTitle.setText(text); - ncxTOC.setDocTitle(docTitle); - // Create the required navigation map element - NavMap navMap = NCXFactory.eINSTANCE.createNavMap(); - ncxTOC.setNavMap(navMap); - // Create the required metadata element - Metadata opfMetadata = OPFFactory.eINSTANCE.createMetadata(); - opfPackage.setMetadata(opfMetadata); - Guide opfGuide = OPFFactory.eINSTANCE.createGuide(); - opfPackage.setGuide(opfGuide); - Manifest opfManifest = OPFFactory.eINSTANCE.createManifest(); - opfPackage.setManifest(opfManifest); - // Create the spine and set a reference to the table of contents - // item which will be added to the manifest on a later stage. - Spine opfSpine = OPFFactory.eINSTANCE.createSpine(); - opfSpine.setToc(TABLE_OF_CONTENTS_ID); - opfPackage.setSpine(opfSpine); - - registerNCXResourceFactory(); - opfPackage.setGenerateTableOfContents(true); - } - - /** - * Validates all XHTML items in the manifest. The following rules are observed: - * <ul> - * <li>The item must be a core media type. If not it must have a fallback item which must exist and be of a core - * media type. Otherwise an error is added to the list of messages</li> - * <li>XHTML file content must be in the preferred vocabulary. Warnings are added when this is not the case.</li> - * </ul> - * - * @throws IOException - * @throws SAXException - * @throws ParserConfigurationException - */ - @Override - protected List<ValidationMessage> validateContents() throws ParserConfigurationException, SAXException, IOException { - EList<Item> manifestItems = opfPackage.getManifest().getItems(); - ArrayList<ValidationMessage> messages = new ArrayList<ValidationMessage>(); - for (Item item : manifestItems) { - if (!isLegalType(item)) { - Item fallback = getItemById(item.getFallback()); - if (fallback == null) { - messages.add(new ValidationMessage(ValidationMessage.Severity.WARNING, MessageFormat.format( - Messages.getString("OPS2Publication.13"), //$NON-NLS-1$ - item.getHref()))); - } else if (!isLegalType(fallback)) { - messages.add(new ValidationMessage(ValidationMessage.Severity.WARNING, MessageFormat.format( - Messages.getString("OPS2Publication.14"), //$NON-NLS-1$ - item.getHref()))); - } else { - messages.add(new ValidationMessage(ValidationMessage.Severity.WARNING, MessageFormat.format( - Messages.getString("OPS2Publication.15"), //$NON-NLS-1$ - item.getHref()))); - } - } - // Validate the XHTML items to see if they contain illegal attributes and elements - if (item.getMedia_type().equals(MIMETYPE_XHTML)) { - File file = new File(item.getFile()); - FileReader fr = new FileReader(file); - messages.addAll(OPS2Validator.validate(new InputSource(fr), item.getHref())); - } - } - return messages; - } - - private boolean isLegalType(Item item) { - boolean legal = false; - for (String type : CORE_MEDIA_TYPES) { - if (item.getMedia_type().equals(type)) { - legal = true; - } - } - return legal; - } - - /** - * Writes the table of contents file in the specified folder using the NCX format. If a table of contents file has - * not been specified an empty one will be created (since it is required to have one). If in addition it has been - * specified that the table of contents should be created, the content files will be parsed and a TOC will be - * generated. - * - * @param oepbsFolder - * the folder to create the NCX file in - * @throws IOException - * @throws SAXException - * @throws ParserConfigurationException - * @see {@link #setTableOfContents(File)} - */ - @Override - protected void writeTableOfContents(File oepbsFolder) throws IOException, ParserConfigurationException, - SAXException { - // If a table of contents file has not been specified we must create - // one. If it has been specified it will be copied. - if (getItemById(opfPackage.getSpine().getToc()) == null) { - File ncxFile = new File(oepbsFolder.getAbsolutePath() + File.separator + TOCFILE_NAME); - ResourceSet resourceSet = new ResourceSetImpl(); - // Register the packages to make it available during loading. - resourceSet.getPackageRegistry().put(NCXPackage.eNS_URI, NCXPackage.eINSTANCE); - URI fileURI = URI.createFileURI(ncxFile.getAbsolutePath()); - Resource resource = resourceSet.createResource(fileURI); - // We've been asked to generate a table of contents using pages - // contained in the spine. - if (opfPackage.isGenerateTableOfContents()) { - generateTableOfContents(); - } - resource.getContents().add(ncxTOC); - Map<String, Object> options = new HashMap<String, Object>(); - // NCX requires that we encode using UTF-8 - options.put(XMLResource.OPTION_ENCODING, XML_ENCODING); - options.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); - resource.save(options); - // Make sure the table of contents file is in the manifest and - // referenced in the spine. We also want it to be the first element - // in the manifest. - Item item = addItem(opfPackage.getSpine().getToc(), null, ncxFile, null, MIMETYPE_NCX, false, false, false); - opfPackage.getManifest().getItems().move(0, item); - } - } - -}
diff --git a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/OPSPublication.java b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/OPSPublication.java index aa8370c..53f6534 100644 --- a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/OPSPublication.java +++ b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/OPSPublication.java
@@ -1,1283 +1,347 @@ /******************************************************************************* - * Copyright (c) 2011,2012 Torkild U. Resheim. - * + * Copyright (c) 2011-2014 Torkild U. Resheim. + * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: + * + * Contributors: * Torkild U. Resheim - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.docs.epub.core; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileWriter; +import java.io.FileInputStream; +import java.io.FileReader; import java.io.IOException; import java.text.MessageFormat; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; -import java.util.TimeZone; -import java.util.UUID; import javax.xml.parsers.ParserConfigurationException; -import org.eclipse.emf.common.util.BasicDiagnostic; -import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EValidator; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import org.eclipse.emf.ecore.util.Diagnostician; import org.eclipse.emf.ecore.util.FeatureMapUtil; import org.eclipse.emf.ecore.xmi.XMLHelper; import org.eclipse.emf.ecore.xmi.XMLResource; -import org.eclipse.emf.ecore.xmi.impl.XMLResourceFactoryImpl; import org.eclipse.mylyn.docs.epub.core.ILogger.Severity; -import org.eclipse.mylyn.docs.epub.dc.Contributor; -import org.eclipse.mylyn.docs.epub.dc.Coverage; -import org.eclipse.mylyn.docs.epub.dc.Creator; -import org.eclipse.mylyn.docs.epub.dc.DCFactory; -import org.eclipse.mylyn.docs.epub.dc.DCType; -import org.eclipse.mylyn.docs.epub.dc.Date; -import org.eclipse.mylyn.docs.epub.dc.Description; -import org.eclipse.mylyn.docs.epub.dc.Format; -import org.eclipse.mylyn.docs.epub.dc.Identifier; -import org.eclipse.mylyn.docs.epub.dc.Language; -import org.eclipse.mylyn.docs.epub.dc.LocalizedDCType; -import org.eclipse.mylyn.docs.epub.dc.Publisher; -import org.eclipse.mylyn.docs.epub.dc.Relation; -import org.eclipse.mylyn.docs.epub.dc.Rights; -import org.eclipse.mylyn.docs.epub.dc.Source; -import org.eclipse.mylyn.docs.epub.dc.Subject; -import org.eclipse.mylyn.docs.epub.dc.Title; +import org.eclipse.mylyn.docs.epub.ncx.DocTitle; +import org.eclipse.mylyn.docs.epub.ncx.Head; +import org.eclipse.mylyn.docs.epub.ncx.Meta; +import org.eclipse.mylyn.docs.epub.ncx.NCXFactory; +import org.eclipse.mylyn.docs.epub.ncx.NCXPackage; +import org.eclipse.mylyn.docs.epub.ncx.NavMap; +import org.eclipse.mylyn.docs.epub.ncx.Ncx; +import org.eclipse.mylyn.docs.epub.ncx.Text; +import org.eclipse.mylyn.docs.epub.ncx.util.NCXResourceFactoryImpl; +import org.eclipse.mylyn.docs.epub.ncx.util.NCXResourceImpl; +import org.eclipse.mylyn.docs.epub.opf.Guide; import org.eclipse.mylyn.docs.epub.opf.Item; import org.eclipse.mylyn.docs.epub.opf.Itemref; +import org.eclipse.mylyn.docs.epub.opf.Manifest; +import org.eclipse.mylyn.docs.epub.opf.Metadata; import org.eclipse.mylyn.docs.epub.opf.OPFFactory; -import org.eclipse.mylyn.docs.epub.opf.OPFPackage; -import org.eclipse.mylyn.docs.epub.opf.Package; -import org.eclipse.mylyn.docs.epub.opf.Reference; -import org.eclipse.mylyn.docs.epub.opf.Role; import org.eclipse.mylyn.docs.epub.opf.Spine; -import org.eclipse.mylyn.docs.epub.opf.Type; -import org.eclipse.mylyn.docs.epub.opf.util.OPFResourceImpl; -import org.eclipse.mylyn.docs.epub.opf.util.OPFValidator; -import org.eclipse.mylyn.internal.docs.epub.core.EPUBFileUtil; import org.eclipse.mylyn.internal.docs.epub.core.EPUBXMLHelperImp; -import org.eclipse.mylyn.internal.docs.epub.core.ReferenceScanner; +import org.eclipse.mylyn.internal.docs.epub.core.OPSValidator; +import org.eclipse.mylyn.internal.docs.epub.core.TOCGenerator; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** - * This type represents one <i>OPS publication</i>. This includes the <i>OPF package document</i> and <i>OPS content - * documents</i>, commonly known as <i>Open eBook Publication Structure</i> or OEBPS. It maintains a data structure - * representing the entire publication and API for building it. - * <p> - * Please note that this API is provisional and should not yet be used to build applications. - * </p> - * + * This type represents one EPUB revision 2.0.1 formatted publication. + * * @author Torkild U. Resheim */ -public abstract class OPSPublication { - // Rules of engagement: - // * Keep all data in the model, use "transient" for temporary properties - // * Do not actually do anything before the final assemble +public class OPSPublication extends Publication { - /** Default identifier for the cover page */ - private static final String COVER_ID = "cover"; //$NON-NLS-1$ + /** MIME type for NCX documents */ + private static final String MIMETYPE_NCX = "application/x-dtbncx+xml"; //$NON-NLS-1$ - /** Publication identifier for the cover image item */ - public static final String COVER_IMAGE_ID = "cover-image"; //$NON-NLS-1$ + private static final String NCX_FILE_SUFFIX = "ncx"; //$NON-NLS-1$ - protected static final String CREATION_DATE_ID = "creation"; //$NON-NLS-1$ + /** Identifier of the table of contents file */ + private static final String TABLE_OF_CONTENTS_ID = "ncx"; //$NON-NLS-1$ - private static final String EMPTY_STRING = ""; //$NON-NLS-1$ + /** Default name for the table of contents */ + private static final String TOCFILE_NAME = "toc.ncx"; //$NON-NLS-1$ - public final static String MIMETYPE_CSS = "text/css"; //$NON-NLS-1$ + /** List of core media types as specified in http://idpf.org/epub/20/spec/OPS_2.0.1_draft.htm#Section1.3.7 */ + private static final String[] CORE_MEDIA_TYPES = new String[] { "image/gif", "image/jpeg", "image/png", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + "image/svg+xml", "application/xhtml+xml", "application/x-dtbook+xml", "text/css", "application/xml", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + "text/x-oeb1-document", "text/x-oeb1-css", "application/x-dtbncx+xml" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - public static final String MIMETYPE_XHTML = "application/xhtml+xml"; //$NON-NLS-1$ - - private static final String OPF_FILE_SUFFIX = "opf"; //$NON-NLS-1$ - - protected static final String UUID_SCHEME = "uuid"; //$NON-NLS-1$ - - /** The encoding to use in XML files */ - protected static final String XML_ENCODING = "UTF-8"; //$NON-NLS-1$ + /** The table of contents */ + private Ncx ncxTOC; /** - * Returns an EPUB version 2.0.1 instance. - * - * @return an EPUB instance + * Creates a new EPUB. */ - public static OPSPublication getVersion2Instance() { - return new OPS2Publication(); - } - - public static OPSPublication getVersion2Instance(ILogger logger) { - return new OPS2Publication(logger); - } - - /** Indentation level used when logging */ - protected int indent = 0; - - protected ILogger logger; - - /** List of validation messages */ - protected List<ValidationMessage> messages; - - /** The root model element */ - protected Package opfPackage; - - /** The root folder TODO: Move to opfPackage */ - private File rootFolder; - - protected OPSPublication() { - opfPackage = OPFFactory.eINSTANCE.createPackage(); - registerOPFResourceFactory(); - } - - protected OPSPublication(ILogger logger) { - this(); - this.logger = logger; - log(MessageFormat.format(Messages.getString("OPSPublication.0"), getVersion()), Severity.INFO, indent++); //$NON-NLS-1$ + public OPSPublication() { + super(); + setup(); } /** - * Adds data to the publication that we always want to be present. - * <ul> - * <li>The creation date.</li> - * <li><i>Eclipse Mylyn Docs project</i> as contributor redactor role.</li> - * <li>A unique identifier if none has been specified.</li> - * <li>A empty description if none has been specified.</li> - * <li>Language "English" if none has been specified.</li> - * <li>A dummy title if none has been specified.</li> - * <li>The publication format if none has been specified.</li> - * </ul> + * Creates a new EPUB logging all event to the specified logger. */ - private void addCompulsoryData() { - log(Messages.getString("OPSPublication.1"), Severity.VERBOSE, indent++); //$NON-NLS-1$ - // Creation date is always when we build - addDate(null, new java.util.Date(System.currentTimeMillis()), CREATION_DATE_ID); - // Make it clear where the tooling comes from - addContributor(null, null, "Eclipse Mylyn Docs project", Role.REDACTOR, null); //$NON-NLS-1$ - // Generate an unique identifier - if (getIdentifier() == null) { - addIdentifier(UUID_SCHEME, "uuid", "urn:uuid" + UUID.randomUUID().toString()); //$NON-NLS-1$ //$NON-NLS-2$ - setIdentifierId(UUID_SCHEME); - } - // Add empty subject - if (opfPackage.getMetadata().getSubjects().isEmpty()) { - addSubject(null, null, EMPTY_STRING); - } - // Add English language - if (opfPackage.getMetadata().getLanguages().isEmpty()) { - addLanguage(null, Locale.ENGLISH.toString()); - } - // Add dummy title - if (opfPackage.getMetadata().getTitles().isEmpty()) { - addTitle(null, null, "No title specified"); //$NON-NLS-1$ - } - // Set the publication format - if (opfPackage.getMetadata().getFormats().isEmpty()) { - addFormat(null, EPUB.MIMETYPE_EPUB); - } - indent--; + public OPSPublication(ILogger logger) { + super(logger); + setup(); } /** - * Specifies a new contributor for the publication. - * - * @param id - * an identifier or <code>null</code> - * @param name - * name of the creator - * @param role - * the role or <code>null</code> - * @param fileAs - * name to file the creator under or <code>null</code> - * @param lang - * the language code or <code>null</code> - * @return the new creator - */ - public Contributor addContributor(String id, Locale lang, String name, Role role, String fileAs) { - log(MessageFormat.format(Messages.getString("OPSPublication.2"), name, role, //$NON-NLS-1$ - lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ - Contributor dc = DCFactory.eINSTANCE.createContributor(); - setDcLocalized(dc, id, lang, name); - if (role != null) { - dc.setRole(role); - } - if (fileAs != null) { - dc.setFileAs(fileAs); - } - opfPackage.getMetadata().getContributors().add(dc); - return dc; - } - - /** - * Specifies a new "coverage" for the publication. - * - * @param id - * an identifier or <code>null</code> - * @param lang - * the language code or <code>null</code> - * @param value - * value of the item - * @return the new coverage - */ - public Coverage addCoverage(String id, Locale lang, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - Coverage dc = DCFactory.eINSTANCE.createCoverage(); - setDcLocalized(dc, id, lang, value); - opfPackage.getMetadata().getCoverages().add(dc); - return dc; - } - - /** - * Specifies a new creator for the publication. - * - * @param id - * a unique identifier or <code>null</code> - * @param lang - * the language code or <code>null</code> - * @param name - * name of the creator - * @param role - * the role or <code>null</code> - * @param fileAs - * name to file the creator under or <code>null</code> - * @return the new creator - */ - public Creator addCreator(String id, Locale lang, String name, Role role, String fileAs) { - log(MessageFormat.format(Messages.getString("OPSPublication.4"), name, role, lang == null //$NON-NLS-1$ - ? Messages.getString("OPSPublication.3") //$NON-NLS-1$ - : lang.getDisplayName()), Severity.VERBOSE, indent); - Creator dc = DCFactory.eINSTANCE.createCreator(); - setDcLocalized(dc, id, lang, name); - if (role != null) { - dc.setRole(role); - } - if (fileAs != null) { - dc.setFileAs(fileAs); - } - opfPackage.getMetadata().getCreators().add(dc); - return dc; - } - - /** - * Adds a new date to the publication. The given instance will be represented in a format defined by - * "Date and Time Formats" at http://www.w3.org/TR/NOTE-datetime and by ISO 8601 on which it is based. - * - * @param id - * optional identifier - * @param date - * the date - * @param event - * the event - * @return the new date - * @see #addDate(String, String, String) - */ - public Date addDate(String id, java.util.Date date, String event) { - SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$ - TimeZone tz = TimeZone.getTimeZone("UTC"); //$NON-NLS-1$ - df.setTimeZone(tz); - Date dc = DCFactory.eINSTANCE.createDate(); - setDcCommon(dc, id, df.format(date)); - if (event != null) { - dc.setEvent(event); - } - opfPackage.getMetadata().getDates().add(dc); - return dc; - } - - /** - * Date of publication, in the format defined by the W3C specification - * "<a href="http://www.w3.org/TR/NOTE-datetime">Date and Time Formats</a>" and by ISO 8601. In particular, dates - * without times must be represented in the form YYYY[-MM[-DD]]: a required 4-digit year, an optional 2-digit month, - * and if the month is given, an optional 2-digit day of month. The event attribute is optional, possible values may - * include: "creation", "publication", and "modification". - * - * @param value - * the date string - * @param event - * an optional event description - * @return the new date - */ - public Date addDate(String id, String value, String event) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - Date dc = DCFactory.eINSTANCE.createDate(); - setDcCommon(dc, id, value); - if (event != null) { - dc.setEvent(event); - } - opfPackage.getMetadata().getDates().add(dc); - return dc; - } - - /** - * Adds a new description to the publication. - * - * @param id - * identifier or <code>null</code> - * @param lang - * the language code or <code>null</code> - * @param value - * the description text - * @return the new description - */ - public Description addDescription(String id, Locale lang, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - log(MessageFormat.format( - Messages.getString("OPSPublication.6"), value, lang == null ? Messages.getString("OPSPublication.3") : lang), //$NON-NLS-1$ //$NON-NLS-2$ - Severity.VERBOSE, indent); - Description dc = DCFactory.eINSTANCE.createDescription(); - setDcLocalized(dc, id, lang, value); - opfPackage.getMetadata().getDescriptions().add(dc); - return dc; - } - - /** - * Adds an optional publication format. - * - * @param id - * identifier or <code>null</code> - * @param value - * the format to add - * @return the new format - */ - public Format addFormat(String id, String value) { - Format dc = DCFactory.eINSTANCE.createFormat(); - setDcCommon(dc, id, value); - opfPackage.getMetadata().getFormats().add(dc); - return dc; - } - - /** - * Adds a new identifier to the publication. - * - * @param id - * the identifier id - * @param scheme - * the scheme used for representing the identifier - * @param value - * the identifier value - * @return the new identifier - */ - public Identifier addIdentifier(String id, String scheme, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - Identifier dc = DCFactory.eINSTANCE.createIdentifier(); - dc.setId(id); - dc.setScheme(scheme); - FeatureMapUtil.addText(dc.getMixed(), value); - opfPackage.getMetadata().getIdentifiers().add(dc); - return dc; - } - - /** - * Adds a new item to the manifest using default values for properties not specified. Same as - * <code>addItem(null, null, file, null, null, true, false);</code>. - * - * @param file - * @return the new item - */ - public Item addItem(File file) { - return addItem(null, null, file, null, null, true, true, false); - } - - /** - * Adds a new item to the manifest. If an identifier is not specified it will automatically be assigned. - * <p> - * The <i>spine</i> defines the reading order, so the order items are added and whether or not <i>spine</i> is - * <code>true</code> does matter. Unless a table of contents file has been specified it will be generated. All files - * that have been added to the spine will be examined unless the <i>noToc</i> attribute has been set to - * <code>true</code>. - * </p> - * - * @param file - * the file to add - * @param dest - * the destination sub-folder or <code>null</code> - * @param id - * identifier or <code>null</code> - * @param type - * MIME file type - * @param spine - * whether or not to add the item to the spine - * @param linear - * whether or not the item is part of the reading order - * @param noToc - * whether or not to include in TOC when automatically generated - * @return the new item - */ - public Item addItem(String id, Locale lang, File file, String dest, String type, boolean spine, boolean linear, - boolean noToc) { - if (file == null) { - throw new IllegalArgumentException("\"file\" must be specified"); //$NON-NLS-1$ - } - if (!file.exists()) { - throw new IllegalArgumentException("\"file\" " + file.getAbsolutePath() + " must exist."); //$NON-NLS-1$ //$NON-NLS-2$ - } - if (file.isDirectory()) { - throw new IllegalArgumentException("\"file\" " + file.getAbsolutePath() + " must not be a directory."); //$NON-NLS-1$ //$NON-NLS-2$ - } - Item item = OPFFactory.eINSTANCE.createItem(); - if (type == null) { - type = EPUBFileUtil.getMimeType(file); - if (type == null) { - throw new IllegalArgumentException("Could not automatically determine MIME type for file " + file //$NON-NLS-1$ - + ". Please specify the correct value"); //$NON-NLS-1$ - } - } - if (id == null) { - String prefix = EMPTY_STRING; - if (!type.equals(MIMETYPE_XHTML)) { - prefix = (type.indexOf('/')) == -1 ? type : type.substring(0, type.indexOf('/')) + '-'; - } - id = prefix + file.getName().substring(0, file.getName().lastIndexOf('.')); - } - item.setId(id); - if (dest == null) { - item.setHref(file.getName()); - } else { - item.setHref(dest + '/' + file.getName()); - } - item.setNoToc(noToc); - item.setMedia_type(type); - item.setFile(file.getAbsolutePath()); - log(MessageFormat.format(Messages.getString("OPSPublication.8"), item.getHref(), item.getMedia_type()), //$NON-NLS-1$ - Severity.VERBOSE, indent); - opfPackage.getManifest().getItems().add(item); - if (spine) { - Itemref ref = OPFFactory.eINSTANCE.createItemref(); - if (!linear) { - ref.setLinear("no"); //$NON-NLS-1$ - } - ref.setIdref(id); - getSpine().getSpineItems().add(ref); - } - return item; - } - - /** - * Adds a new language specification to the publication. - * - * @param id - * identifier or <code>null</code> - * @param lang - * the language code or <code>null</code> - * @param lang - * the RFC-3066 format of the language code - * @return the language instance - */ - public Language addLanguage(String id, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - Language dc = DCFactory.eINSTANCE.createLanguage(); - setDcCommon(dc, id, value); - opfPackage.getMetadata().getLanguages().add(dc); - return dc; - } - - /** - * Adds a new meta item to the publication. - * - * @param name - * name of the item - * @param value - * content of the item - * @return the new meta - */ - public org.eclipse.mylyn.docs.epub.opf.Meta addMeta(String name, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - if (name == null) { - throw new IllegalArgumentException("A name must be specified"); //$NON-NLS-1$ - } - org.eclipse.mylyn.docs.epub.opf.Meta opf = OPFFactory.eINSTANCE.createMeta(); - opf.setName(name); - opf.setContent(value); - opfPackage.getMetadata().getMetas().add(opf); - return opf; - } - - /** - * Adds a new publisher to the publication. - * - * @param id - * identifier or <code>null</code> - * @param lang - * the language code or <code>null</code> - * @param value - * name of the publisher - * @return the new publisher - */ - public Publisher addPublisher(String id, Locale lang, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - log(MessageFormat.format(Messages.getString("OPSPublication.9"), value, //$NON-NLS-1$ - lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ - Publisher dc = DCFactory.eINSTANCE.createPublisher(); - setDcLocalized(dc, id, lang, value); - opfPackage.getMetadata().getPublishers().add(dc); - return dc; - } - - /** - * The structural components of the books are listed in reference elements contained within the guide element. These - * components could refer to the table of contents, list of illustrations, foreword, bibliography, and many other - * standard parts of the book. Reading systems are not required to use the guide element but it is a good idea to - * use it. - * - * @param href - * the item referenced - * @param title - * title of the reference (optional) - * @param value - * type of the reference - * @return the reference - */ - public Reference addReference(String href, String title, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - if (href == null) { - throw new IllegalArgumentException("A href must be specified"); //$NON-NLS-1$ - } - log(MessageFormat.format(Messages.getString("OPSPublication.11"), value, title, href), Severity.VERBOSE, //$NON-NLS-1$ - indent); - Reference reference = OPFFactory.eINSTANCE.createReference(); - reference.setHref(href); - reference.setTitle(title); - reference.setType(value); - opfPackage.getGuide().getGuideItems().add(reference); - return reference; - } - - /** - * Adds a optional <i>relation</i> specification to the publication. - * - * @param id - * identifier or <code>null</code> - * @param lang - * the language code or <code>null</code> - * @param value - * the value of the relation - * @return the new relation - */ - public Relation addRelation(String id, Locale lang, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - log(MessageFormat.format(Messages.getString("OPSPublication.12"), value, //$NON-NLS-1$ - lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ - Relation dc = DCFactory.eINSTANCE.createRelation(); - setDcLocalized(dc, id, lang, value); - opfPackage.getMetadata().getRelations().add(dc); - return dc; - } - - /** - * Adds a optional <i>rights</i> specification to the publication. - * - * @param id - * identifier or <code>null</code> - * @param lang - * the language code or <code>null</code> - * @param value - * the rights text - * @return the new rights element - */ - public Rights addRights(String id, Locale lang, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - log(MessageFormat.format(Messages.getString("OPSPublication.14"), value, //$NON-NLS-1$ - lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ - Rights dc = DCFactory.eINSTANCE.createRights(); - setDcLocalized(dc, id, lang, value); - opfPackage.getMetadata().getRights().add(dc); - return dc; - } - - /** - * Adds a optional <i>source</i> specification to the publication. - * - * @param id - * identifier or <code>null</code> - * @param lang - * the language code or <code>null</code> - * @param value - * the source text - * @return the new source element - */ - public Source addSource(String id, Locale lang, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - log(MessageFormat.format(Messages.getString("OPSPublication.16"), value, //$NON-NLS-1$ - lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ - Source dc = DCFactory.eINSTANCE.createSource(); - setDcLocalized(dc, id, lang, value); - opfPackage.getMetadata().getSources().add(dc); - return dc; - } - - /** - * Adds a required <i>subject</i> specification to the publication. - * - * @param id - * identifier or <code>null</code> - * @param lang - * the language code or <code>null</code> - * @param value - * the subject - */ - public Subject addSubject(String id, Locale lang, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - log(MessageFormat.format(Messages.getString("OPSPublication.18"), value, //$NON-NLS-1$ - lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ - Subject dc = DCFactory.eINSTANCE.createSubject(); - setDcLocalized(dc, id, lang, value); - opfPackage.getMetadata().getSubjects().add(dc); - return dc; - } - - /** - * Adds a required <i>title</i> specification to the publication. - * - * @param id - * identifier or <code>null</code> - * @param lang - * the language code or <code>null</code> - * @param value - * the new title - * @return the new title - */ - public Title addTitle(String id, Locale lang, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - log(MessageFormat.format(Messages.getString("OPSPublication.20"), value, //$NON-NLS-1$ - lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ - Title dc = DCFactory.eINSTANCE.createTitle(); - setDcLocalized(dc, id, lang, value); - opfPackage.getMetadata().getTitles().add(dc); - return dc; - } - - /** - * Adds a optional <i>type</i> specification to the publication. - * - * @param id - * identifier or <code>null</code> - * @param type - * the type to add - * @return the new type - */ - public org.eclipse.mylyn.docs.epub.dc.Type addType(String id, String value) { - if (value == null) { - throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ - } - org.eclipse.mylyn.docs.epub.dc.Type dc = DCFactory.eINSTANCE.createType(); - setDcCommon(dc, id, value); - opfPackage.getMetadata().getTypes().add(dc); - return dc; - } - - /** - * Implement to handle generation of table of contents from the items added to the <i>spine</i>. - * - * @throws Exception - */ - protected abstract void generateTableOfContents() throws Exception; - - /** - * Returns the main identifier of the publication or <code>null</code> if it could not be determined. - * - * @return the main identifier or <code>null</code> - */ - public Identifier getIdentifier() { - EList<Identifier> identifiers = opfPackage.getMetadata().getIdentifiers(); - for (Identifier identifier : identifiers) { - if (identifier.getId().equals(opfPackage.getUniqueIdentifier())) { - return identifier; - } - } - return null; - } - - /** - * Locates and returns an item from the manifest corresponding to the given identifier. - * - * @param id - * the identifier - * @return the item - */ - public Item getItemById(String id) { - EList<Item> items = opfPackage.getManifest().getItems(); - for (Item item : items) { - if (item.getId().equals(id)) { - return item; - } - } - return null; - } - - /** - * Returns a list of all manifest items that have the specified MIME type. - * - * @param mimetype - * the MIME type to search for - * @return a list of all items - */ - public List<Item> getItemsByMIMEType(String mimetype) { - ArrayList<Item> stylesheets = new ArrayList<Item>(); - EList<Item> items = opfPackage.getManifest().getItems(); - for (Item item : items) { - if (item.getMedia_type().equals(mimetype)) { - stylesheets.add(item); - } - } - return stylesheets; - } - - /** - * Returns the list of validation messages. - * - * @return the list of validation message - */ - public List<ValidationMessage> getMessages() { - return messages; - } - - public Package getOpfPackage() { - return opfPackage; - } - - /** - * Returns the root folder of the publication. This is the folder where the OPF file resides. Note that this - * property will only have a value if this instance has been populated using an existing publication, such as when - * unpacking an EPUB file. - * - * @return the root folder or <code>null</code> - */ - public File getRootFolder() { - return rootFolder; - } - - /** - * Returns the publication spine. - * - * @return the spine - */ - protected Spine getSpine() { - return opfPackage.getSpine(); - } - - /** - * Returns the table of contents for the publication. As the actual implementation may vary depending on - * - * @return the table of contents - */ - public abstract Object getTableOfContents(); - - /** - * Returns a list of validation messages. This list is only populated when {@link #pack(File)} has taken place. - * - * @return a list of validation messages - */ - public List<ValidationMessage> getValidationMessages() { - return messages; - } - - /** - * Returns the EPUB version number of the publication. - * - * @return the version number - */ - protected abstract String getVersion(); - - /** - * Iterates over all XHTML (non-generated) files in the manifest attempting to determine referenced resources such - * as image files and adds these to the manifest. This method is not recursive, so items added through this - * mechanism will not be searched for more content to add. - * - * @throws ParserConfigurationException + * This mechanism will traverse the spine of the publication (which is representing the reading order) and parse + * each file for information that can be used to assemble a table of contents. Only XHTML type of files will be + * taken into consideration. + * * @throws SAXException * @throws IOException + * @throws ParserConfigurationException */ - private void includeReferencedResources() throws ParserConfigurationException, SAXException, IOException { - log(Messages.getString("OPSPublication.23"), Severity.INFO, indent++); //$NON-NLS-1$ + @Override + protected void generateTableOfContents() throws ParserConfigurationException, SAXException, IOException { + log(Messages.getString("OPS2Publication.0"), Severity.INFO, indent++); //$NON-NLS-1$ + Meta meta = NCXFactory.eINSTANCE.createMeta(); + meta.setName("dtb:uid"); //$NON-NLS-1$ + meta.setContent(getIdentifier().getMixed().getValue(0).toString()); + ncxTOC.getHead().getMetas().add(meta); + int playOrder = 0; + // Iterate over the spine + EList<Itemref> spineItems = getSpine().getSpineItems(); EList<Item> manifestItems = opfPackage.getManifest().getItems(); - // Compose a list of file references - HashMap<File, List<File>> references = new HashMap<File, List<File>>(); - for (Item item : manifestItems) { - // Only parse XHTML-files and files that are not generated - if (item.getMedia_type().equals(MIMETYPE_XHTML) && !item.isGenerated()) { - File source = null; - if (item.getSourcePath() != null) { - source = new File(item.getSourcePath()); - log(MessageFormat.format(Messages.getString("OPSPublication.24"), source), Severity.VERBOSE, indent); //$NON-NLS-1$ - references.put(source, ReferenceScanner.parse(item)); - } else { - source = new File(item.getFile()); - log(MessageFormat.format(Messages.getString("OPSPublication.25"), source), Severity.VERBOSE, indent); //$NON-NLS-1$ + for (Itemref itemref : spineItems) { + Item referencedItem = null; + String id = itemref.getIdref(); + // Find the manifest item that is referenced + for (Item item : manifestItems) { + if (item.getId().equals(id)) { + referencedItem = item; + break; } - references.put(source, ReferenceScanner.parse(item)); - } else { - log(MessageFormat.format(Messages.getString("OPSPublication.26"), item.getFile()), Severity.DEBUG, indent); //$NON-NLS-1$ } - } - indent--; - // Add all referenced items to the manifest - for (File root : references.keySet()) { - List<File> files = references.get(root); - for (File file : files) { - // Determine a sub-folder to place the resource in. - File relativePath = new File(EPUBFileUtil.getRelativePath(root, file)); - // If "file" is not relative to "root" it will be placed it in - // same folder as "root". - if (relativePath.isAbsolute()) { - relativePath = new File(EMPTY_STRING); - } - // Add those files that does not already exist in the manifest - boolean add = true; - EList<Item> items = getOpfPackage().getManifest().getItems(); - for (Item item : items) { - if (item.getFile().equals(file.getAbsolutePath())) { - add = false; - } - } - if (add) { - try { - addItem(null, null, file, relativePath.getParent(), null, false, false, false); - } catch (Exception e) { - throw new RuntimeException(String.format("Could not add file referenced from \"%1$s\"", root), //$NON-NLS-1$ - e); - } - } + if (referencedItem != null && !referencedItem.isNoToc() + && referencedItem.getMedia_type().equals(MIMETYPE_XHTML)) { + File file = new File(referencedItem.getFile()); + FileInputStream fis = new FileInputStream(file); + log(MessageFormat.format(Messages.getString("OPS2Publication.1"), referencedItem.getHref()), Severity.VERBOSE, indent); //$NON-NLS-1$ + playOrder = TOCGenerator.parse(new InputSource(fis), referencedItem.getHref(), ncxTOC, playOrder); } } indent--; } - protected void log(String message, Severity severity, int indent) { - if (logger != null) { - if (indent == 0) { - logger.log(message, severity); - } else { - StringBuilder sb = new StringBuilder(message); - for (int i = 0; i < indent; i++) { - sb.insert(0, " "); //$NON-NLS-1$ - } - logger.log(sb.toString(), severity); - } - } + @Override + public Object getTableOfContents() { + return ncxTOC; } - /** - * Assembles the OPS publication in a location relative to the root file. Two levels of validation is performed. - * First the contents are validated. This may result in warning or error class of messages. An error will result in - * a {@link ValidationException} being thrown. - * - * @param rootFile - * the root file - * @throws ValidationException - * when the EPUB contains errors - * @throws SAXException - * when content cannot be read - * @throws ParserConfigurationException - * when the SAX parser cannot configured - */ - void pack(File rootFile) throws IOException, ValidationException, ParserConfigurationException, SAXException { - if (opfPackage.getSpine().getSpineItems().isEmpty()) { - throw new ValidationException("Spine does not contain any items"); //$NON-NLS-1$ - } - // Include items that have been referenced - if (opfPackage.isIncludeReferencedResources()) { - includeReferencedResources(); - } - // Make sure all data is in place in the OPF - addCompulsoryData(); - // Note that order is important here. Some of the steps for assembling - // the EPUB may insert data into the EPUB structure. Hence the OPF must - // be written last. - this.rootFolder = rootFile.getAbsoluteFile().getParentFile(); - if (rootFolder.isDirectory() || rootFolder.mkdirs()) { - // Validate contents. - messages = validateContents(); - log(Messages.getString("OPSPublication.5"), Severity.INFO, indent); //$NON-NLS-1$ - indent++; - for (ValidationMessage validation : messages) { - switch (validation.getSeverity()) { - case ERROR: - throw new ValidationException(validation.getMessage()); - case WARNING: - log(validation.getMessage(), Severity.WARNING, indent); - break; - default: - break; - } - } - indent--; - // Validate metadata. These are "hard" requirements, so any problem here is an exception - List<Diagnostic> problems = validateMetadata(); - if (problems.size() > 0) { - for (Diagnostic diagnostic : problems) { - throw new ValidationException(diagnostic.getMessage()); - } - } - // Validation OK -- Write content. - if (opfPackage.isGenerateCoverHTML()) { - writeCoverHTML(rootFolder); - } - writeContent(rootFolder); - writeTableOfContents(rootFolder); - writeOPF(rootFile); - } else { - throw new IOException("Could not create OEBPS folder in " + rootFolder.getAbsolutePath()); //$NON-NLS-1$ - } + @Override + protected String getVersion() { + return "2.0"; //$NON-NLS-1$ } - /** - * Reads the root file. - * - * @param rootFile - * the file to read - * @throws IOException - */ - protected void readOPF(File rootFile) throws IOException { + @Override + protected void readTableOfContents(File tocFile) throws IOException { ResourceSet resourceSet = new ResourceSetImpl(); - URI fileURI = URI.createFileURI(rootFile.getAbsolutePath()); + URI fileURI = URI.createFileURI(tocFile.getAbsolutePath()); Resource resource = resourceSet.createResource(fileURI); resource.load(null); - opfPackage = (Package) resource.getContents().get(0); + ncxTOC = (Ncx) resource.getContents().get(0); } /** - * Implement to read the table of contents for the particular OEPBS implementation. - * - * @param tocFile - * the table of contents file - * @throws IOException - */ - protected abstract void readTableOfContents(File tocFile) throws IOException; - - /** - * Registers a new resource factory for OPF data structures. This is normally done through Eclipse extension points + * Registers a new resource factory for NCX data structures. This is normally done through Eclipse extension points * but we also need to be able to create this factory without the Eclipse runtime. */ - private void registerOPFResourceFactory() { + private void registerNCXResourceFactory() { // Register package so that it is available even without the Eclipse runtime @SuppressWarnings("unused") - OPFPackage packageInstance = OPFPackage.eINSTANCE; + NCXPackage packageInstance = NCXPackage.eINSTANCE; - // Register the file suffix - Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(OPF_FILE_SUFFIX, - new XMLResourceFactoryImpl() { + Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(NCX_FILE_SUFFIX, + new NCXResourceFactoryImpl() { + @Override + public Resource createResource(URI uri) { + NCXResourceImpl xmiResource = new NCXResourceImpl(uri) { @Override - public Resource createResource(URI uri) { - OPFResourceImpl xmiResource = new OPFResourceImpl(uri) { - - @Override - protected XMLHelper createXMLHelper() { - EPUBXMLHelperImp xmlHelper = new EPUBXMLHelperImp(); - return xmlHelper; - } - - }; - Map<Object, Object> loadOptions = xmiResource.getDefaultLoadOptions(); - Map<Object, Object> saveOptions = xmiResource.getDefaultSaveOptions(); - // We use extended metadata - saveOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); - loadOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); - // Required in order to correctly read in attributes - loadOptions.put(XMLResource.OPTION_LAX_FEATURE_PROCESSING, Boolean.TRUE); - // Treat "href" attributes as features - loadOptions.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE); - // UTF-8 encoding is required per specification - saveOptions.put(XMLResource.OPTION_ENCODING, XML_ENCODING); - // Do not download any external DTDs. - Map<String, Object> parserFeatures = new HashMap<String, Object>(); - parserFeatures.put("http://xml.org/sax/features/validation", Boolean.FALSE); //$NON-NLS-1$ - parserFeatures.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", //$NON-NLS-1$ - Boolean.FALSE); - loadOptions.put(XMLResource.OPTION_PARSER_FEATURES, parserFeatures); - return xmiResource; + protected XMLHelper createXMLHelper() { + EPUBXMLHelperImp xmlHelper = new EPUBXMLHelperImp(); + return xmlHelper; } - }); + }; + Map<Object, Object> loadOptions = xmiResource.getDefaultLoadOptions(); + Map<Object, Object> saveOptions = xmiResource.getDefaultSaveOptions(); + // We use extended metadata + saveOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); + loadOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); + // Required in order to correctly read in attributes + loadOptions.put(XMLResource.OPTION_LAX_FEATURE_PROCESSING, Boolean.TRUE); + // Treat "href" attributes as features + loadOptions.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE); + // UTF-8 encoding is required per specification + saveOptions.put(XMLResource.OPTION_ENCODING, XML_ENCODING); + // Do not download any external DTDs. + Map<String, Object> parserFeatures = new HashMap<String, Object>(); + parserFeatures.put("http://xml.org/sax/features/validation", Boolean.FALSE); //$NON-NLS-1$ + parserFeatures.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", //$NON-NLS-1$ + Boolean.FALSE); + loadOptions.put(XMLResource.OPTION_PARSER_FEATURES, parserFeatures); + return xmiResource; + } + + }); + } + + @Override + public void setTableOfContents(File ncxFile) { + // Add the file to the publication and make sure we use the table of + // contents identifier. + Item item = addItem(opfPackage.getSpine().getToc(), null, ncxFile, null, MIMETYPE_NCX, false, false, false); + // The table of contents file must be first. + opfPackage.getManifest().getItems().move(0, item); + log(MessageFormat.format("Using table of contents file {0} for OPS", new Object[] { ncxFile.getName() }), //$NON-NLS-1$ + Severity.VERBOSE, indent); + } + + private void setup() { + opfPackage.setVersion(getVersion()); + ncxTOC = NCXFactory.eINSTANCE.createNcx(); + // Set the required version attribute + ncxTOC.setVersion("2005-1"); //$NON-NLS-1$ + // Create the required head element + Head head = NCXFactory.eINSTANCE.createHead(); + ncxTOC.setHead(head); + // Create the required title element + DocTitle docTitle = NCXFactory.eINSTANCE.createDocTitle(); + Text text = NCXFactory.eINSTANCE.createText(); + FeatureMapUtil.addText(text.getMixed(), "Table of contents"); //$NON-NLS-1$ + docTitle.setText(text); + ncxTOC.setDocTitle(docTitle); + // Create the required navigation map element + NavMap navMap = NCXFactory.eINSTANCE.createNavMap(); + ncxTOC.setNavMap(navMap); + // Create the required metadata element + Metadata opfMetadata = OPFFactory.eINSTANCE.createMetadata(); + opfPackage.setMetadata(opfMetadata); + Guide opfGuide = OPFFactory.eINSTANCE.createGuide(); + opfPackage.setGuide(opfGuide); + Manifest opfManifest = OPFFactory.eINSTANCE.createManifest(); + opfPackage.setManifest(opfManifest); + // Create the spine and set a reference to the table of contents + // item which will be added to the manifest on a later stage. + Spine opfSpine = OPFFactory.eINSTANCE.createSpine(); + opfSpine.setToc(TABLE_OF_CONTENTS_ID); + opfPackage.setSpine(opfSpine); + + registerNCXResourceFactory(); + opfPackage.setGenerateTableOfContents(true); } /** - * Convenience method for adding a cover to the publication. This method will make sure the required actions are - * taken to provide a cover page for all reading systems. - * - * @param image - * the cover image (jpeg, png, svg or gif) - * @param title - * title of the cover page - */ - public void setCover(File image, String title) { - // Add the cover image to the manifest - Item item = addItem(COVER_IMAGE_ID, null, image, null, null, false, false, true); - item.setTitle(title); - // Point to the cover using a meta tag - addMeta(COVER_ID, COVER_IMAGE_ID); - opfPackage.setGenerateCoverHTML(true); - - } - - /** - * Sets common properties for <i>Dublin Core</i> elements. - * - * @param dc - * the Dublin Core element - * @param id - * optional identifier - * @param value - * value of the element - */ - private void setDcCommon(DCType dc, String id, String value) { - FeatureMapUtil.addText(dc.getMixed(), value); - if (id != null) { - dc.setId(id); - } - } - - /** - * Sets common properties for localized <i>Dublin Core</i> elements. - * - * @param dc - * the Dublin Core element - * @param id - * optional identifier - * @param lang - * language code - * @param value - * value of the element - */ - private void setDcLocalized(LocalizedDCType dc, String id, Locale lang, String value) { - setDcCommon(dc, id, value); - if (lang != null) { - dc.setLang(lang.toString()); - } - } - - /** - * Specifies whether or not to automatically generate table of contents from the publication contents. The default - * is <code>true</code> - * - * @param generateToc - * whether or not to generate a table of contents - */ - public void setGenerateToc(boolean generateToc) { - opfPackage.setGenerateTableOfContents(generateToc); - } - - /** - * Specifies the id of the identifier used for the publication. - * - * @param identifier_id - * the identifier id - * @see #addIdentifier(String, String, String) - */ - public void setIdentifierId(String identifier_id) { - opfPackage.setUniqueIdentifier(identifier_id); - } - - /** - * Specifies whether or not to automatically include resources (files) that are referenced in the contents. The - * default is <code>false</code>. - * - * @param include - * whether or not automatically include resources - */ - public void setIncludeReferencedResources(boolean include) { - opfPackage.setIncludeReferencedResources(include); - } - - /** - * Specifies a target of contents file for the publication. This is an alternative to - * {@link #setGenerateToc(boolean)}. - * - * @param tocFile - * the table of contents file - */ - public abstract void setTableOfContents(File tocFile); - - /** - * Populates the data model with the content from an unpacked EPUB. - * - * @param opfFile - * the (OPS) root file - * @throws Exception - */ - void unpack(File opfFile) throws Exception { - readOPF(opfFile); - rootFolder = opfFile.getAbsoluteFile().getParentFile(); - String tocId = opfPackage.getSpine().getToc(); - Item tocItem = getItemById(tocId); - File tocFile = new File(rootFolder.getAbsolutePath() + File.separator + tocItem.getHref()); - readTableOfContents(tocFile); - } - - /** - * Implement to validate contents. - * - * @throws FileNotFoundException + * Validates all XHTML items in the manifest. The following rules are observed: + * <ul> + * <li>The item must be a core media type. If not it must have a fallback item which must exist and be of a core + * media type. Otherwise an error is added to the list of messages</li> + * <li>XHTML file content must be in the preferred vocabulary. Warnings are added when this is not the case.</li> + * </ul> + * * @throws IOException * @throws SAXException * @throws ParserConfigurationException */ - protected abstract List<ValidationMessage> validateContents() throws FileNotFoundException, IOException, - SAXException, ParserConfigurationException; - - /** - * Validates the data model contents. - * - * @return a list of EMF diagnostics - */ - public List<Diagnostic> validateMetadata() { - EValidator.Registry.INSTANCE.put(OPFPackage.eINSTANCE, new OPFValidator()); - BasicDiagnostic diagnostics = new BasicDiagnostic(); - for (EObject eo : opfPackage.eContents()) { - Map<Object, Object> context = new HashMap<Object, Object>(); - Diagnostician.INSTANCE.validate(eo, diagnostics, context); - } - return diagnostics.getChildren(); - } - - /** - * Copies all items part of the publication into the OEPBS folder unless the item in question will be generated. - * - * @param rootFolder - * the folder to copy into. - * @throws IOException - */ - private void writeContent(File rootFolder) throws IOException { - log(Messages.getString("OPSPublication.22"), Severity.INFO, indent); //$NON-NLS-1$ - EList<Item> items = opfPackage.getManifest().getItems(); - for (Item item : items) { - if (!item.isGenerated()) { - File source = new File(item.getFile()); - File destination = new File(rootFolder.getAbsolutePath() + File.separator + item.getHref()); - EPUBFileUtil.copy(source, destination); + @Override + protected List<ValidationMessage> validateContents() throws ParserConfigurationException, SAXException, IOException { + EList<Item> manifestItems = opfPackage.getManifest().getItems(); + ArrayList<ValidationMessage> messages = new ArrayList<ValidationMessage>(); + for (Item item : manifestItems) { + if (!isLegalType(item)) { + Item fallback = getItemById(item.getFallback()); + if (fallback == null) { + messages.add(new ValidationMessage(ValidationMessage.Severity.WARNING, MessageFormat.format( + Messages.getString("OPS2Publication.13"), //$NON-NLS-1$ + item.getHref()))); + } else if (!isLegalType(fallback)) { + messages.add(new ValidationMessage(ValidationMessage.Severity.WARNING, MessageFormat.format( + Messages.getString("OPS2Publication.14"), //$NON-NLS-1$ + item.getHref()))); + } else { + messages.add(new ValidationMessage(ValidationMessage.Severity.WARNING, MessageFormat.format( + Messages.getString("OPS2Publication.15"), //$NON-NLS-1$ + item.getHref()))); + } + } + // Validate the XHTML items to see if they contain illegal attributes and elements + if (item.getMedia_type().equals(MIMETYPE_XHTML)) { + File file = new File(item.getFile()); + FileReader fr = new FileReader(file); + messages.addAll(OPSValidator.validate(new InputSource(fr), item.getHref())); } } + return messages; } - /** - * Writes a XHTML-file for the cover image. This is added to the publication and all required references set. - * - * @param rootFolder - * the publication root folder - * @throws IOException - */ - private void writeCoverHTML(File rootFolder) throws IOException { - Item coverImage = getItemById(COVER_IMAGE_ID); - File coverFile = new File(rootFolder.getAbsolutePath() + File.separator + "cover-page.xhtml"); //$NON-NLS-1$ - if (!coverFile.exists()) { - try { - log(MessageFormat.format(Messages.getString("OPSPublication.28"), coverImage.getHref()), Severity.INFO, //$NON-NLS-1$ - indent); - FileWriter fw = new FileWriter(coverFile); - fw.append("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n"); //$NON-NLS-1$ - fw.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"); //$NON-NLS-1$ - fw.append("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"); //$NON-NLS-1$ - fw.append(" <head>\n"); //$NON-NLS-1$ - fw.append(" <title>" + coverImage.getTitle() + "</title>\n"); //$NON-NLS-1$ //$NON-NLS-2$ - fw.append(" <style type=\"text/css\">"); //$NON-NLS-1$ - fw.append(" #cover-body {\n"); //$NON-NLS-1$ - fw.append(" margin: 0px;\n"); //$NON-NLS-1$ - fw.append(" text-align: center;\n"); //$NON-NLS-1$ - fw.append(" background-color: #222222;\n"); //$NON-NLS-1$ - fw.append(" }\n"); //$NON-NLS-1$ - fw.append(" #cover-block {\n"); //$NON-NLS-1$ - fw.append(" height: 100%;\n"); //$NON-NLS-1$ - fw.append(" margin-top: 0;\n"); //$NON-NLS-1$ - fw.append(" }\n"); //$NON-NLS-1$ - fw.append(" #cover-image {\n"); //$NON-NLS-1$ - fw.append(" height: 100%;\n"); //$NON-NLS-1$ - fw.append(" text-align: center;\n"); //$NON-NLS-1$ - fw.append(" max-width: 100%;\n"); //$NON-NLS-1$ - fw.append(" }\n"); //$NON-NLS-1$ - fw.append(" </style>\n"); //$NON-NLS-1$ - fw.append(" </head>\n"); //$NON-NLS-1$ - fw.append(" <body id=\"cover-body\">\n"); //$NON-NLS-1$ - fw.append(" <div id=\"cover-block\">\n"); //$NON-NLS-1$ - fw.append(" <img id=\"cover-image\" src=\"" + coverImage.getHref() + "\" alt=\"" //$NON-NLS-1$ //$NON-NLS-2$ - + coverImage.getTitle() + "\"/>\n"); //$NON-NLS-1$ - fw.append(" </div>\n"); //$NON-NLS-1$ - fw.append(" </body>\n"); //$NON-NLS-1$ - fw.append("</html>\n"); //$NON-NLS-1$ - fw.close(); - } catch (IOException e) { - e.printStackTrace(); + private boolean isLegalType(Item item) { + boolean legal = false; + for (String type : CORE_MEDIA_TYPES) { + if (item.getMedia_type().equals(type)) { + legal = true; } } - // Add the cover page item - Item coverPage = addItem(COVER_ID, null, coverFile, null, MIMETYPE_XHTML, true, false, false); - coverPage.setGenerated(true); - addReference(coverPage.getHref(), coverImage.getTitle(), Type.COVER.getLiteral()); - // Move the cover page first in the spine. - EList<Itemref> spine = opfPackage.getSpine().getSpineItems(); - Itemref cover = null; - for (Itemref itemref : spine) { - if (itemref.getIdref().equals(COVER_ID)) { - cover = itemref; - } - } - if (cover != null) { - spine.move(0, cover); - } + return legal; } /** - * Writes the <b>content.opf</b> file. - * - * @param opfFile - * the location of the OPF file + * Writes the table of contents file in the specified folder using the NCX format. If a table of contents file has + * not been specified an empty one will be created (since it is required to have one). If in addition it has been + * specified that the table of contents should be created, the content files will be parsed and a TOC will be + * generated. + * + * @param oepbsFolder + * the folder to create the NCX file in * @throws IOException + * @throws SAXException + * @throws ParserConfigurationException + * @see {@link #setTableOfContents(File)} */ - private void writeOPF(File opfFile) throws IOException { - ResourceSet resourceSet = new ResourceSetImpl(); - // Register the packages to make it available during loading. - URI fileURI = URI.createFileURI(opfFile.getAbsolutePath()); - Resource resource = resourceSet.createResource(fileURI); - resource.getContents().add(opfPackage); - resource.save(null); + @Override + protected void writeTableOfContents(File oepbsFolder) throws IOException, ParserConfigurationException, + SAXException { + // If a table of contents file has not been specified we must create + // one. If it has been specified it will be copied. + if (getItemById(opfPackage.getSpine().getToc()) == null) { + File ncxFile = new File(oepbsFolder.getAbsolutePath() + File.separator + TOCFILE_NAME); + ResourceSet resourceSet = new ResourceSetImpl(); + // Register the packages to make it available during loading. + resourceSet.getPackageRegistry().put(NCXPackage.eNS_URI, NCXPackage.eINSTANCE); + URI fileURI = URI.createFileURI(ncxFile.getAbsolutePath()); + Resource resource = resourceSet.createResource(fileURI); + // We've been asked to generate a table of contents using pages + // contained in the spine. + if (opfPackage.isGenerateTableOfContents()) { + generateTableOfContents(); + } + resource.getContents().add(ncxTOC); + Map<String, Object> options = new HashMap<String, Object>(); + // NCX requires that we encode using UTF-8 + options.put(XMLResource.OPTION_ENCODING, XML_ENCODING); + options.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); + resource.save(options); + // Make sure the table of contents file is in the manifest and + // referenced in the spine. We also want it to be the first element + // in the manifest. + Item item = addItem(opfPackage.getSpine().getToc(), null, ncxFile, null, MIMETYPE_NCX, false, false, false); + opfPackage.getManifest().getItems().move(0, item); + } } - /** - * Implement to handle writing of the table of contents. Note that this method should do nothing if the table of - * contents has already been specified using {@link #setTableOfContents(File)}. - * - * @param rootFolder - * the folder to write in - * @throws Exception - */ - protected abstract void writeTableOfContents(File rootFolder) throws IOException, ParserConfigurationException, - SAXException; }
diff --git a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/Publication.java b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/Publication.java new file mode 100644 index 0000000..8b95b5d --- /dev/null +++ b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/Publication.java
@@ -0,0 +1,1480 @@ +/******************************************************************************* + * Copyright (c) 2011-2014 Torkild U. Resheim. + * + * All rights reserved. This program and the accompanying materials are made + * available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Torkild U. Resheim - initial API and implementation + *******************************************************************************/ +package org.eclipse.mylyn.docs.epub.core; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; +import java.util.UUID; + +import javax.xml.parsers.ParserConfigurationException; + +import org.eclipse.emf.common.util.BasicDiagnostic; +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EValidator; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.Diagnostician; +import org.eclipse.emf.ecore.util.FeatureMapUtil; +import org.eclipse.emf.ecore.xmi.XMLHelper; +import org.eclipse.emf.ecore.xmi.XMLResource; +import org.eclipse.emf.ecore.xmi.impl.XMLResourceFactoryImpl; +import org.eclipse.mylyn.docs.epub.core.ILogger.Severity; +import org.eclipse.mylyn.docs.epub.dc.Contributor; +import org.eclipse.mylyn.docs.epub.dc.Coverage; +import org.eclipse.mylyn.docs.epub.dc.Creator; +import org.eclipse.mylyn.docs.epub.dc.DCFactory; +import org.eclipse.mylyn.docs.epub.dc.DCType; +import org.eclipse.mylyn.docs.epub.dc.Date; +import org.eclipse.mylyn.docs.epub.dc.Description; +import org.eclipse.mylyn.docs.epub.dc.Format; +import org.eclipse.mylyn.docs.epub.dc.Identifier; +import org.eclipse.mylyn.docs.epub.dc.Language; +import org.eclipse.mylyn.docs.epub.dc.LocalizedDCType; +import org.eclipse.mylyn.docs.epub.dc.Publisher; +import org.eclipse.mylyn.docs.epub.dc.Relation; +import org.eclipse.mylyn.docs.epub.dc.Rights; +import org.eclipse.mylyn.docs.epub.dc.Source; +import org.eclipse.mylyn.docs.epub.dc.Subject; +import org.eclipse.mylyn.docs.epub.dc.Title; +import org.eclipse.mylyn.docs.epub.opf.Item; +import org.eclipse.mylyn.docs.epub.opf.Itemref; +import org.eclipse.mylyn.docs.epub.opf.OPFFactory; +import org.eclipse.mylyn.docs.epub.opf.OPFPackage; +import org.eclipse.mylyn.docs.epub.opf.Package; +import org.eclipse.mylyn.docs.epub.opf.Reference; +import org.eclipse.mylyn.docs.epub.opf.Role; +import org.eclipse.mylyn.docs.epub.opf.Spine; +import org.eclipse.mylyn.docs.epub.opf.Type; +import org.eclipse.mylyn.docs.epub.opf.util.OPFResourceImpl; +import org.eclipse.mylyn.docs.epub.opf.util.OPFValidator; +import org.eclipse.mylyn.internal.docs.epub.core.EPUBFileUtil; +import org.eclipse.mylyn.internal.docs.epub.core.EPUBXMLHelperImp; +import org.eclipse.mylyn.internal.docs.epub.core.ReferenceScanner; +import org.xml.sax.SAXException; + +/** + * This type represents an <i>EPUB Publication</i> which holds publication metadata along with references to content. In + * EPUB 2.0 terminology this is the <i>OPF package document</i> and <i>OPS content documents</i>. Together these are + * commonly known as <i>Open eBook Publication Structure</i> or OEBPS. In EPUB 3.0 terminology these are referred to as + * <i>Publications</i> and <i>Content Documents</i>. This type accommodates both versions. + * <p> + * The type maintains a data structure representing the entire publication and API for reading and writing the resulting + * files. + * </p> + * + * @author Torkild U. Resheim + * @see PublicationProxy + */ +public abstract class Publication { + // Rules of engagement: + // * Keep all data in the model, use "transient" for temporary properties + // * Do not actually do anything before the final assemble + + /** Default identifier for the cover page */ + private static final String COVER_ID = "cover"; //$NON-NLS-1$ + + /** Publication identifier for the cover image item */ + public static final String COVER_IMAGE_ID = "cover-image"; //$NON-NLS-1$ + + protected static final String CREATION_DATE_ID = "creation"; //$NON-NLS-1$ + + private static final String EMPTY_STRING = ""; //$NON-NLS-1$ + + public final static String MIMETYPE_CSS = "text/css"; //$NON-NLS-1$ + + public static final String MIMETYPE_XHTML = "application/xhtml+xml"; //$NON-NLS-1$ + + private static final String OPF_FILE_SUFFIX = "opf"; //$NON-NLS-1$ + + protected static final String UUID_SCHEME = "uuid"; //$NON-NLS-1$ + + /** The encoding to use in XML files */ + protected static final String XML_ENCODING = "UTF-8"; //$NON-NLS-1$ + + /** + * Returns an <i>EPUB version 2.0.1</i> instance. + * + * @return an EPUB instance + */ + public static Publication getVersion2Instance() { + return new OPSPublication(); + } + + /** Indentation level used when logging */ + protected int indent = 0; + + protected ILogger logger; + + /** List of validation messages */ + protected List<ValidationMessage> messages; + + /** The root model element */ + protected Package opfPackage; + + /** The root folder TODO: Move to opfPackage */ + private File rootFolder; + + protected Publication() { + opfPackage = OPFFactory.eINSTANCE.createPackage(); + registerOPFResourceFactory(); + } + + protected Publication(ILogger logger) { + this(); + this.logger = logger; + log(MessageFormat.format(Messages.getString("OPSPublication.0"), getVersion()), Severity.INFO, indent++); //$NON-NLS-1$ + } + + /** + * Adds data to the publication that we always want to be present. + * <ul> + * <li>The creation date.</li> + * <li><i>Eclipse Mylyn Docs project</i> as contributor redactor role.</li> + * <li>A unique identifier if none has been specified.</li> + * <li>A empty description if none has been specified.</li> + * <li>Language "English" if none has been specified.</li> + * <li>A dummy title if none has been specified.</li> + * <li>The publication format if none has been specified.</li> + * </ul> + */ + private void addCompulsoryData() { + log(Messages.getString("OPSPublication.1"), Severity.VERBOSE, indent++); //$NON-NLS-1$ + // Creation date is always when we build + addDate(null, new java.util.Date(System.currentTimeMillis()), CREATION_DATE_ID); + // Make it clear where the tooling comes from + addContributor(null, null, "Eclipse Mylyn Docs project", Role.REDACTOR, null); //$NON-NLS-1$ + // Generate an unique identifier + if (getIdentifier() == null) { + addIdentifier(UUID_SCHEME, "uuid", "urn:uuid" + UUID.randomUUID().toString()); //$NON-NLS-1$ //$NON-NLS-2$ + setIdentifierId(UUID_SCHEME); + } + // Add empty subject + if (opfPackage.getMetadata().getSubjects().isEmpty()) { + addSubject(null, null, EMPTY_STRING); + } + // Add English language + if (opfPackage.getMetadata().getLanguages().isEmpty()) { + addLanguage(null, Locale.ENGLISH.toString()); + } + // Add dummy title + if (opfPackage.getMetadata().getTitles().isEmpty()) { + addTitle(null, null, "No title specified"); //$NON-NLS-1$ + } + // Set the publication format + if (opfPackage.getMetadata().getFormats().isEmpty()) { + addFormat(null, EPUB.MIMETYPE_EPUB); + } + indent--; + } + + /** + * Specifies a new contributor for the publication. + * + * @param name + * name of the creator + * @return the new creator + */ + public Contributor addContributor(String name) { + return addContributor(null, null, name, null, null); + } + + /** + * Specifies a new contributor for the publication. + * + * @param id + * an identifier or <code>null</code> + * @param lang + * the language code or <code>null</code> + * @param name + * name of the creator + * @param role + * the role or <code>null</code> + * @param fileAs + * name to file the creator under or <code>null</code> + * @return the new creator + */ + public Contributor addContributor(String id, Locale lang, String name, Role role, String fileAs) { + log(MessageFormat.format(Messages.getString("OPSPublication.2"), name, role, //$NON-NLS-1$ + lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ + Contributor dc = DCFactory.eINSTANCE.createContributor(); + setDcLocalized(dc, id, lang, name); + if (role != null) { + dc.setRole(role); + } + if (fileAs != null) { + dc.setFileAs(fileAs); + } + opfPackage.getMetadata().getContributors().add(dc); + return dc; + } + + /** + * Specifies a new "coverage" for the publication. + * + * @param value + * value of the item + * @return the new coverage + */ + public Coverage addCoverage(String value) { + return addCoverage(null, null, value); + } + + /** + * Specifies a new "coverage" for the publication. + * + * @param id + * an identifier or <code>null</code> + * @param lang + * the language code or <code>null</code> + * @param value + * value of the item + * @return the new coverage + */ + public Coverage addCoverage(String id, Locale lang, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + Coverage dc = DCFactory.eINSTANCE.createCoverage(); + setDcLocalized(dc, id, lang, value); + opfPackage.getMetadata().getCoverages().add(dc); + return dc; + } + + /** + * Specifies a new creator for the publication. + * + * @param name + * name of the creator + * @return the new creator + */ + public Creator addCreator(String name) { + return addCreator(null, null, name, null, null); + } + + /** + * Specifies a new creator for the publication. + * + * @param id + * a unique identifier or <code>null</code> + * @param lang + * the language code or <code>null</code> + * @param name + * name of the creator + * @param role + * the role or <code>null</code> + * @param fileAs + * name to file the creator under or <code>null</code> + * @return the new creator + */ + public Creator addCreator(String id, Locale lang, String name, Role role, String fileAs) { + log(MessageFormat.format(Messages.getString("OPSPublication.4"), name, role, lang == null //$NON-NLS-1$ + ? Messages.getString("OPSPublication.3") //$NON-NLS-1$ + : lang.getDisplayName()), Severity.VERBOSE, indent); + Creator dc = DCFactory.eINSTANCE.createCreator(); + setDcLocalized(dc, id, lang, name); + if (role != null) { + dc.setRole(role); + } + if (fileAs != null) { + dc.setFileAs(fileAs); + } + opfPackage.getMetadata().getCreators().add(dc); + return dc; + } + + /** + * Adds a new date to the publication. The given instance will be represented in a format defined by + * "Date and Time Formats" at http://www.w3.org/TR/NOTE-datetime and by ISO 8601 on which it is based. + * + * @param date + * the date + * @return the new date + * @see #addDate(String, String, String) + */ + public Date addDate(java.util.Date date) { + return addDate(null, date, null); + } + + /** + * Date of publication, in the format defined by the W3C specification + * "<a href="http://www.w3.org/TR/NOTE-datetime">Date and Time Formats</a>" and by ISO 8601. In particular, dates + * without times must be represented in the form YYYY[-MM[-DD]]: a required 4-digit year, an optional 2-digit month, + * and if the month is given, an optional 2-digit day of month. + * + * @param value + * the date string + * @return the new date + */ + public Date addDate(String value) { + return addDate(null, value, null); + } + + /** + * Adds a new date to the publication. The given instance will be represented in a format defined by + * "Date and Time Formats" at http://www.w3.org/TR/NOTE-datetime and by ISO 8601 on which it is based. + * + * @param id + * optional identifier + * @param date + * the date + * @param event + * the event + * @return the new date + * @see #addDate(String, String, String) + */ + public Date addDate(String id, java.util.Date date, String event) { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$ + TimeZone tz = TimeZone.getTimeZone("UTC"); //$NON-NLS-1$ + df.setTimeZone(tz); + Date dc = DCFactory.eINSTANCE.createDate(); + setDcCommon(dc, id, df.format(date)); + if (event != null) { + dc.setEvent(event); + } + opfPackage.getMetadata().getDates().add(dc); + return dc; + } + + /** + * Date of publication, in the format defined by the W3C specification + * "<a href="http://www.w3.org/TR/NOTE-datetime">Date and Time Formats</a>" and by ISO 8601. In particular, dates + * without times must be represented in the form YYYY[-MM[-DD]]: a required 4-digit year, an optional 2-digit month, + * and if the month is given, an optional 2-digit day of month. The event attribute is optional, possible values may + * include: "creation", "publication", and "modification". + * + * @param id + * optional identifier + * @param value + * the date string + * @param event + * an optional event description + * @return the new date + */ + public Date addDate(String id, String value, String event) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + Date dc = DCFactory.eINSTANCE.createDate(); + setDcCommon(dc, id, value); + if (event != null) { + dc.setEvent(event); + } + opfPackage.getMetadata().getDates().add(dc); + return dc; + } + + /** + * Adds a new description to the publication. + * + * @param value + * the description text + * @return the new description + */ + public Description addDescription(String value) { + return addDescription(null, null, value); + } + + /** + * Adds a new description to the publication. + * + * @param id + * identifier or <code>null</code> + * @param lang + * the language code or <code>null</code> + * @param value + * the description text + * @return the new description + */ + public Description addDescription(String id, Locale lang, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + log(MessageFormat.format( + Messages.getString("OPSPublication.6"), value, lang == null ? Messages.getString("OPSPublication.3") : lang), //$NON-NLS-1$ //$NON-NLS-2$ + Severity.VERBOSE, indent); + Description dc = DCFactory.eINSTANCE.createDescription(); + setDcLocalized(dc, id, lang, value); + opfPackage.getMetadata().getDescriptions().add(dc); + return dc; + } + + /** + * Adds an optional publication format. + * + * @param value + * the format to add + * @return the new format + */ + public Format addFormat(String value) { + return addFormat(null, value); + } + + /** + * Adds an optional publication format. + * + * @param id + * identifier or <code>null</code> + * @param value + * the format to add + * @return the new format + */ + public Format addFormat(String id, String value) { + Format dc = DCFactory.eINSTANCE.createFormat(); + setDcCommon(dc, id, value); + opfPackage.getMetadata().getFormats().add(dc); + return dc; + } + + /** + * Adds a new identifier to the publication. + * + * @param value + * the identifier value + * @return the new identifier + */ + public Identifier addIdentifier(String value) { + return addIdentifier(null, null, value); + } + + /** + * Adds a new identifier to the publication. + * + * @param id + * the identifier id + * @param scheme + * the scheme used for representing the identifier + * @param value + * the identifier value + * @return the new identifier + */ + public Identifier addIdentifier(String id, String scheme, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + Identifier dc = DCFactory.eINSTANCE.createIdentifier(); + dc.setId(id); + dc.setScheme(scheme); + FeatureMapUtil.addText(dc.getMixed(), value); + opfPackage.getMetadata().getIdentifiers().add(dc); + return dc; + } + + /** + * Adds a new item to the manifest using default values for properties not specified. Same as + * <code>addItem(null, null, file, null, null, true, false);</code>. + * + * @param file + * @return the new item + */ + public Item addItem(File file) { + return addItem(null, null, file, null, null, true, true, false); + } + + /** + * Adds a new item to the manifest. If an identifier is not specified it will automatically be assigned. + * <p> + * The <i>spine</i> defines the reading order, so the order items are added and whether or not <i>spine</i> is + * <code>true</code> does matter. Unless a table of contents file has been specified it will be generated. All files + * that have been added to the spine will be examined unless the <i>noToc</i> attribute has been set to + * <code>true</code>. + * </p> + * + * @param file + * the file to add + * @param dest + * the destination sub-folder or <code>null</code> + * @param id + * identifier or <code>null</code> + * @param type + * MIME file type + * @param spine + * whether or not to add the item to the spine + * @param linear + * whether or not the item is part of the reading order + * @param noToc + * whether or not to include in TOC when automatically generated + * @return the new item + */ + public Item addItem(String id, Locale lang, File file, String dest, String type, boolean spine, boolean linear, + boolean noToc) { + if (file == null) { + throw new IllegalArgumentException("\"file\" must be specified"); //$NON-NLS-1$ + } + if (!file.exists()) { + throw new IllegalArgumentException("\"file\" " + file.getAbsolutePath() + " must exist."); //$NON-NLS-1$ //$NON-NLS-2$ + } + if (file.isDirectory()) { + throw new IllegalArgumentException("\"file\" " + file.getAbsolutePath() + " must not be a directory."); //$NON-NLS-1$ //$NON-NLS-2$ + } + Item item = OPFFactory.eINSTANCE.createItem(); + // Attempt to determine the type of file if none has been specified + if (type == null) { + type = EPUBFileUtil.getMimeType(file); + if (type == null) { + throw new IllegalArgumentException("Could not automatically determine MIME type for file " + file //$NON-NLS-1$ + + ". Please specify the correct value"); //$NON-NLS-1$ + } + } + // Assign the required identifier if none has been specified + if (id == null) { + String prefix = EMPTY_STRING; + if (!type.equals(MIMETYPE_XHTML)) { + prefix = (type.indexOf('/')) == -1 ? type : type.substring(0, type.indexOf('/')) + '-'; + } + id = prefix + file.getName().substring(0, file.getName().lastIndexOf('.')); + } + item.setId(id); + if (dest == null) { + item.setHref(file.getName()); + } else { + item.setHref(dest + '/' + file.getName()); + } + item.setNoToc(noToc); + item.setMedia_type(type); + item.setFile(file.getAbsolutePath()); + log(MessageFormat.format(Messages.getString("OPSPublication.8"), item.getHref(), item.getMedia_type()), //$NON-NLS-1$ + Severity.VERBOSE, indent); + opfPackage.getManifest().getItems().add(item); + if (spine) { + Itemref ref = OPFFactory.eINSTANCE.createItemref(); + if (!linear) { + ref.setLinear("no"); //$NON-NLS-1$ + } + ref.setIdref(id); + getSpine().getSpineItems().add(ref); + } + return item; + } + + /** + * Adds a new language specification to the publication. + * + * @param value + * the RFC-3066 format of the language code + * @return the language instance + */ + public Language addLanguage(String value) { + return addLanguage(null, value); + } + + /** + * Adds a new language specification to the publication. + * + * @param id + * identifier or <code>null</code> + * @param lang + * the RFC-3066 format of the language code or <code>null</code> + * @return the language instance + */ + public Language addLanguage(String id, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + Language dc = DCFactory.eINSTANCE.createLanguage(); + setDcCommon(dc, id, value); + opfPackage.getMetadata().getLanguages().add(dc); + return dc; + } + + /** + * Adds a new meta item to the publication. + * + * @param name + * name of the item + * @param value + * content of the item + * @return the new meta + */ + public org.eclipse.mylyn.docs.epub.opf.Meta addMeta(String name, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + if (name == null) { + throw new IllegalArgumentException("A name must be specified"); //$NON-NLS-1$ + } + org.eclipse.mylyn.docs.epub.opf.Meta opf = OPFFactory.eINSTANCE.createMeta(); + opf.setName(name); + opf.setContent(value); + opfPackage.getMetadata().getMetas().add(opf); + return opf; + } + + /** + * Adds a new publisher to the publication. + * + * @param value + * name of the publisher + * @return the new publisher + */ + public Publisher addPublisher(String value) { + return addPublisher(null, null, value); + } + + /** + * Adds a new publisher to the publication. + * + * @param id + * identifier or <code>null</code> + * @param lang + * the language code or <code>null</code> + * @param value + * name of the publisher + * @return the new publisher + */ + public Publisher addPublisher(String id, Locale lang, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + log(MessageFormat.format(Messages.getString("OPSPublication.9"), value, //$NON-NLS-1$ + lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ + Publisher dc = DCFactory.eINSTANCE.createPublisher(); + setDcLocalized(dc, id, lang, value); + opfPackage.getMetadata().getPublishers().add(dc); + return dc; + } + + /** + * The structural components of the books are listed in reference elements contained within the guide element. These + * components could refer to the table of contents, list of illustrations, foreword, bibliography, and many other + * standard parts of the book. Reading systems are not required to use the guide element but it is a good idea to + * use it. + * + * @param href + * the item referenced + * @param title + * title of the reference (optional) + * @param value + * type of the reference + * @return the reference + */ + public Reference addReference(String href, String title, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + if (href == null) { + throw new IllegalArgumentException("A href must be specified"); //$NON-NLS-1$ + } + log(MessageFormat.format(Messages.getString("OPSPublication.11"), value, title, href), Severity.VERBOSE, //$NON-NLS-1$ + indent); + Reference reference = OPFFactory.eINSTANCE.createReference(); + reference.setHref(href); + reference.setTitle(title); + reference.setType(value); + opfPackage.getGuide().getGuideItems().add(reference); + return reference; + } + + /** + * Adds a optional <i>relation</i> specification to the publication. + * + * @param value + * the value of the relation + * @return the new relation + */ + public Relation addRelation(String value) { + return addRelation(null, null, value); + } + + /** + * Adds a optional <i>relation</i> specification to the publication. + * + * @param id + * identifier or <code>null</code> + * @param lang + * the language code or <code>null</code> + * @param value + * the value of the relation + * @return the new relation + */ + public Relation addRelation(String id, Locale lang, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + log(MessageFormat.format(Messages.getString("OPSPublication.12"), value, //$NON-NLS-1$ + lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ + Relation dc = DCFactory.eINSTANCE.createRelation(); + setDcLocalized(dc, id, lang, value); + opfPackage.getMetadata().getRelations().add(dc); + return dc; + } + + /** + * Adds a optional <i>rights</i> specification to the publication. + * + * @param value + * the rights text + * @return the new rights element + */ + public Rights addRights(String value) { + return addRights(null, null, value); + } + + /** + * Adds a optional <i>rights</i> specification to the publication. + * + * @param id + * identifier or <code>null</code> + * @param lang + * the language code or <code>null</code> + * @param value + * the rights text + * @return the new rights element + */ + public Rights addRights(String id, Locale lang, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + log(MessageFormat.format(Messages.getString("OPSPublication.14"), value, //$NON-NLS-1$ + lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ + Rights dc = DCFactory.eINSTANCE.createRights(); + setDcLocalized(dc, id, lang, value); + opfPackage.getMetadata().getRights().add(dc); + return dc; + } + + /** + * Adds a optional <i>source</i> specification to the publication. + * + * @param value + * the source text + * @return the new source element + */ + public Source addSource(String value) { + return addSource(null, null, value); + } + + /** + * Adds a optional <i>source</i> specification to the publication. + * + * @param id + * identifier or <code>null</code> + * @param lang + * the language code or <code>null</code> + * @param value + * the source text + * @return the new source element + */ + public Source addSource(String id, Locale lang, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + log(MessageFormat.format(Messages.getString("OPSPublication.16"), value, //$NON-NLS-1$ + lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ + Source dc = DCFactory.eINSTANCE.createSource(); + setDcLocalized(dc, id, lang, value); + opfPackage.getMetadata().getSources().add(dc); + return dc; + } + + /** + * Adds a required <i>subject</i> specification to the publication. + * + * @param value + * the subject + */ + public Subject addSubject(String value) { + return addSubject(null, null, value); + } + + /** + * Adds a required <i>subject</i> specification to the publication. + * + * @param id + * identifier or <code>null</code> + * @param lang + * the language code or <code>null</code> + * @param value + * the subject + */ + public Subject addSubject(String id, Locale lang, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + log(MessageFormat.format(Messages.getString("OPSPublication.18"), value, //$NON-NLS-1$ + lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ + Subject dc = DCFactory.eINSTANCE.createSubject(); + setDcLocalized(dc, id, lang, value); + opfPackage.getMetadata().getSubjects().add(dc); + return dc; + } + + /** + * Adds a required <i>title</i> specification to the publication. + * + * @param value + * the new title + * @return the new title + */ + public Title addTitle(String value) { + return addTitle(null, null, value); + } + + /** + * Adds a required <i>title</i> specification to the publication. + * + * @param id + * identifier or <code>null</code> + * @param lang + * the language code or <code>null</code> + * @param value + * the new title + * @return the new title + */ + public Title addTitle(String id, Locale lang, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + log(MessageFormat.format(Messages.getString("OPSPublication.20"), value, //$NON-NLS-1$ + lang == null ? Messages.getString("OPSPublication.3") : lang.getDisplayName()), Severity.VERBOSE, indent); //$NON-NLS-1$ + Title dc = DCFactory.eINSTANCE.createTitle(); + setDcLocalized(dc, id, lang, value); + opfPackage.getMetadata().getTitles().add(dc); + return dc; + } + + /** + * Adds a optional <i>type</i> specification to the publication. + * + * @param type + * the type to add + * @return the new type + */ + public org.eclipse.mylyn.docs.epub.dc.Type addType(String value) { + return addType(null, value); + } + + /** + * Adds a optional <i>type</i> specification to the publication. + * + * @param id + * identifier or <code>null</code> + * @param type + * the type to add + * @return the new type + */ + public org.eclipse.mylyn.docs.epub.dc.Type addType(String id, String value) { + if (value == null) { + throw new IllegalArgumentException("A value must be specified"); //$NON-NLS-1$ + } + org.eclipse.mylyn.docs.epub.dc.Type dc = DCFactory.eINSTANCE.createType(); + setDcCommon(dc, id, value); + opfPackage.getMetadata().getTypes().add(dc); + return dc; + } + + /** + * Implement to handle generation of table of contents from the items added to the <i>spine</i>. + * + * @throws Exception + */ + protected abstract void generateTableOfContents() throws Exception; + + /** + * Returns the main identifier of the publication or <code>null</code> if it could not be determined. + * + * @return the main identifier or <code>null</code> + */ + public Identifier getIdentifier() { + EList<Identifier> identifiers = opfPackage.getMetadata().getIdentifiers(); + for (Identifier identifier : identifiers) { + if (identifier.getId().equals(opfPackage.getUniqueIdentifier())) { + return identifier; + } + } + return null; + } + + /** + * Locates and returns an item from the manifest corresponding to the given identifier, or <code>null</code> if the + * identifier could not be found. + * + * @param id + * the identifier + * @return the item or <code>null</code>. + */ + public Item getItemById(String id) { + EList<Item> items = opfPackage.getManifest().getItems(); + for (Item item : items) { + if (item.getId().equals(id)) { + return item; + } + } + return null; + } + + /** + * Returns a list of all manifest items that have the specified MIME type. + * + * @param mimetype + * the MIME type to search for + * @return a list of all items + */ + public List<Item> getItemsByMIMEType(String mimetype) { + ArrayList<Item> stylesheets = new ArrayList<Item>(); + EList<Item> items = opfPackage.getManifest().getItems(); + for (Item item : items) { + if (item.getMedia_type().equals(mimetype)) { + stylesheets.add(item); + } + } + return stylesheets; + } + + /** + * Returns the list of validation messages. + * + * @return the list of validation message + */ + public List<ValidationMessage> getMessages() { + return messages; + } + + /** + * Returns the root item of the publication. + * + * @return the publication root item + */ + public Package getPackage() { + return opfPackage; + } + + /** + * Returns the root folder of the publication. This is the folder where the OPF file resides. Note that this + * property will only have a value if this instance has been populated using an existing publication, such as when + * unpacking an EPUB file. + * + * @return the root folder or <code>null</code> + */ + public File getRootFolder() { + return rootFolder; + } + + /** + * Returns the publication spine. + * + * @return the spine + */ + protected Spine getSpine() { + return opfPackage.getSpine(); + } + + /** + * Returns the table of contents for the publication. As the actual implementation may vary depending on + * + * @return the table of contents + */ + public abstract Object getTableOfContents(); + + /** + * Returns a list of validation messages. This list is only populated when {@link #pack(File)} has taken place. + * + * @return a list of validation messages + */ + public List<ValidationMessage> getValidationMessages() { + return messages; + } + + /** + * Returns the EPUB version number of the publication. + * + * @return the version number + */ + protected abstract String getVersion(); + + /** + * Iterates over all XHTML (non-generated) files in the manifest attempting to determine referenced resources such + * as image files and adds these to the manifest. This method is not recursive, so items added through this + * mechanism will not be searched for more content to add. + * + * @throws ParserConfigurationException + * @throws SAXException + * @throws IOException + */ + private void includeReferencedResources() throws ParserConfigurationException, SAXException, IOException { + log(Messages.getString("OPSPublication.23"), Severity.INFO, indent++); //$NON-NLS-1$ + EList<Item> manifestItems = opfPackage.getManifest().getItems(); + // Compose a list of file references + HashMap<File, List<File>> references = new HashMap<File, List<File>>(); + for (Item item : manifestItems) { + // Only parse XHTML-files and files that are not generated + if (item.getMedia_type().equals(MIMETYPE_XHTML) && !item.isGenerated()) { + File source = null; + if (item.getSourcePath() != null) { + source = new File(item.getSourcePath()); + log(MessageFormat.format(Messages.getString("OPSPublication.24"), source), Severity.VERBOSE, indent); //$NON-NLS-1$ + references.put(source, ReferenceScanner.parse(item)); + } else { + source = new File(item.getFile()); + log(MessageFormat.format(Messages.getString("OPSPublication.25"), source), Severity.VERBOSE, indent); //$NON-NLS-1$ + } + references.put(source, ReferenceScanner.parse(item)); + } else { + log(MessageFormat.format(Messages.getString("OPSPublication.26"), item.getFile()), Severity.DEBUG, indent); //$NON-NLS-1$ + } + } + indent--; + // Add all referenced items to the manifest + for (File root : references.keySet()) { + List<File> files = references.get(root); + for (File file : files) { + // Determine a sub-folder to place the resource in. + File relativePath = new File(EPUBFileUtil.getRelativePath(root, file)); + // If "file" is not relative to "root" it will be placed it in + // same folder as "root". + if (relativePath.isAbsolute()) { + relativePath = new File(EMPTY_STRING); + } + // Add those files that does not already exist in the manifest + boolean add = true; + EList<Item> items = getPackage().getManifest().getItems(); + for (Item item : items) { + if (item.getFile().equals(file.getAbsolutePath())) { + add = false; + } + } + if (add) { + try { + addItem(null, null, file, relativePath.getParent(), null, false, false, false); + } catch (Exception e) { + throw new RuntimeException(String.format("Could not add file referenced from \"%1$s\"", root), //$NON-NLS-1$ + e); + } + } + } + } + indent--; + } + + /** + * Logs a message using the specified logger. If no logger has been assigned, the message is ignored. + * + * @param message + * the message to log + * @param severity + * severity of the log message + * @param indent + * the number of indents + */ + protected void log(String message, Severity severity, int indent) { + if (logger != null) { + if (indent == 0) { + logger.log(message, severity); + } else { + StringBuilder sb = new StringBuilder(message); + for (int i = 0; i < indent; i++) { + sb.insert(0, " "); //$NON-NLS-1$ + } + logger.log(sb.toString(), severity); + } + } + } + + /** + * Assembles the OPS publication in a location relative to the root file. Two levels of validation is performed. + * First the contents are validated. This may result in warning or error class of messages. An error will result in + * a {@link ValidationException} being thrown. + * + * @param rootFile + * the root file + * @throws ValidationException + * when the EPUB contains errors + * @throws SAXException + * when content cannot be read + * @throws ParserConfigurationException + * when the SAX parser cannot configured + */ + void pack(File rootFile) throws IOException, ValidationException, ParserConfigurationException, SAXException { + if (opfPackage.getSpine().getSpineItems().isEmpty()) { + throw new ValidationException("Spine does not contain any items"); //$NON-NLS-1$ + } + // Include items that have been referenced + if (opfPackage.isIncludeReferencedResources()) { + includeReferencedResources(); + } + // Make sure all data is in place in the OPF + addCompulsoryData(); + // Note that order is important here. Some of the steps for assembling + // the EPUB may insert data into the publication structure. Hence the OPF must + // be written last. + this.rootFolder = rootFile.getAbsoluteFile().getParentFile(); + if (rootFolder.isDirectory() || rootFolder.mkdirs()) { + // Validate contents. + messages = validateContents(); + log(Messages.getString("OPSPublication.5"), Severity.INFO, indent); //$NON-NLS-1$ + indent++; + for (ValidationMessage validation : messages) { + switch (validation.getSeverity()) { + case ERROR: + throw new ValidationException(validation.getMessage()); + case WARNING: + log(validation.getMessage(), Severity.WARNING, indent); + break; + default: + break; + } + } + indent--; + // Validate metadata. These are "hard" requirements, so any problem here is an exception + List<Diagnostic> problems = validateMetadata(); + if (problems.size() > 0) { + for (Diagnostic diagnostic : problems) { + throw new ValidationException(diagnostic.getMessage()); + } + } + // Validation OK -- Write content. + if (opfPackage.isGenerateCoverHTML()) { + writeCoverHTML(rootFolder); + } + writeContent(rootFolder); + writeTableOfContents(rootFolder); + writeOPF(rootFile); + } else { + throw new IOException("Could not create OEBPS folder in " + rootFolder.getAbsolutePath()); //$NON-NLS-1$ + } + } + + /** + * Reads the root file. + * + * @param rootFile + * the file to read + * @throws IOException + */ + protected void readOPF(File rootFile) throws IOException { + ResourceSet resourceSet = new ResourceSetImpl(); + URI fileURI = URI.createFileURI(rootFile.getAbsolutePath()); + Resource resource = resourceSet.createResource(fileURI); + resource.load(null); + opfPackage = (Package) resource.getContents().get(0); + } + + /** + * Implement to read the table of contents for the particular OEPBS implementation. + * + * @param tocFile + * the table of contents file + * @throws IOException + */ + protected abstract void readTableOfContents(File tocFile) throws IOException; + + /** + * Registers a new resource factory for OPF data structures. This is normally done through Eclipse extension points + * but we also need to be able to create this factory without the Eclipse runtime. + */ + private void registerOPFResourceFactory() { + // Register package so that it is available even without the Eclipse runtime + @SuppressWarnings("unused") + OPFPackage packageInstance = OPFPackage.eINSTANCE; + + // Register the file suffix + Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(OPF_FILE_SUFFIX, + new XMLResourceFactoryImpl() { + + @Override + public Resource createResource(URI uri) { + OPFResourceImpl xmiResource = new OPFResourceImpl(uri) { + + @Override + protected XMLHelper createXMLHelper() { + EPUBXMLHelperImp xmlHelper = new EPUBXMLHelperImp(); + return xmlHelper; + } + + }; + Map<Object, Object> loadOptions = xmiResource.getDefaultLoadOptions(); + Map<Object, Object> saveOptions = xmiResource.getDefaultSaveOptions(); + // We use extended metadata + saveOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); + loadOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); + // Required in order to correctly read in attributes + loadOptions.put(XMLResource.OPTION_LAX_FEATURE_PROCESSING, Boolean.TRUE); + // Treat "href" attributes as features + loadOptions.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE); + // UTF-8 encoding is required per specification + saveOptions.put(XMLResource.OPTION_ENCODING, XML_ENCODING); + // Do not download any external DTDs. + Map<String, Object> parserFeatures = new HashMap<String, Object>(); + parserFeatures.put("http://xml.org/sax/features/validation", Boolean.FALSE); //$NON-NLS-1$ + parserFeatures.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", //$NON-NLS-1$ + Boolean.FALSE); + loadOptions.put(XMLResource.OPTION_PARSER_FEATURES, parserFeatures); + return xmiResource; + } + + }); + } + + /** + * Convenience method for adding a cover to the publication. This method will make sure the required actions are + * taken to provide a cover page for all reading systems. + * + * @param image + * the cover image (jpeg, png, svg or gif) + * @param title + * title of the cover page + */ + public void setCover(File image, String title) { + // Add the cover image to the manifest + Item item = addItem(COVER_IMAGE_ID, null, image, null, null, false, false, true); + item.setTitle(title); + // Point to the cover using a meta tag + addMeta(COVER_ID, COVER_IMAGE_ID); + opfPackage.setGenerateCoverHTML(true); + + } + + /** + * Sets common properties for <i>Dublin Core</i> elements. + * + * @param dc + * the Dublin Core element + * @param id + * optional identifier + * @param value + * value of the element + */ + private void setDcCommon(DCType dc, String id, String value) { + FeatureMapUtil.addText(dc.getMixed(), value); + if (id != null) { + dc.setId(id); + } + } + + /** + * Sets common properties for localized <i>Dublin Core</i> elements. + * + * @param dc + * the Dublin Core element + * @param id + * optional identifier + * @param lang + * language code + * @param value + * value of the element + */ + private void setDcLocalized(LocalizedDCType dc, String id, Locale lang, String value) { + setDcCommon(dc, id, value); + if (lang != null) { + dc.setLang(lang.toString()); + } + } + + /** + * Specifies whether or not to automatically generate table of contents from the publication contents. The default + * is <code>true</code> + * + * @param generateToc + * whether or not to generate a table of contents + */ + public void setGenerateToc(boolean generateToc) { + opfPackage.setGenerateTableOfContents(generateToc); + } + + /** + * Specifies the id of the identifier used for the publication. + * + * @param identifier_id + * the identifier id + * @see #addIdentifier(String, String, String) + */ + public void setIdentifierId(String identifier_id) { + opfPackage.setUniqueIdentifier(identifier_id); + } + + /** + * Specifies whether or not to automatically include resources (files) that are referenced in the contents. The + * default is <code>false</code>. + * + * @param include + * whether or not automatically include resources + */ + public void setIncludeReferencedResources(boolean include) { + opfPackage.setIncludeReferencedResources(include); + } + + /** + * Specifies a target of contents file for the publication. This is an alternative to + * {@link #setGenerateToc(boolean)}. + * + * @param tocFile + * the table of contents file + */ + public abstract void setTableOfContents(File tocFile); + + /** + * Populates the data model with the content from an unpacked EPUB. + * + * @param opfFile + * the (OPS) root file + * @throws Exception + */ + void unpack(File opfFile) throws Exception { + readOPF(opfFile); + rootFolder = opfFile.getAbsoluteFile().getParentFile(); + String tocId = opfPackage.getSpine().getToc(); + Item tocItem = getItemById(tocId); + File tocFile = new File(rootFolder.getAbsolutePath() + File.separator + tocItem.getHref()); + readTableOfContents(tocFile); + } + + /** + * Implement to validate contents. + * + * @throws FileNotFoundException + * @throws IOException + * @throws SAXException + * @throws ParserConfigurationException + */ + protected abstract List<ValidationMessage> validateContents() throws FileNotFoundException, IOException, + SAXException, ParserConfigurationException; + + /** + * Validates the data model contents. + * + * @return a list of EMF diagnostics + */ + public List<Diagnostic> validateMetadata() { + EValidator.Registry.INSTANCE.put(OPFPackage.eINSTANCE, new OPFValidator()); + BasicDiagnostic diagnostics = new BasicDiagnostic(); + for (EObject eo : opfPackage.eContents()) { + Map<Object, Object> context = new HashMap<Object, Object>(); + Diagnostician.INSTANCE.validate(eo, diagnostics, context); + } + return diagnostics.getChildren(); + } + + /** + * Copies all items part of the publication into the OEPBS folder unless the item in question will be generated. + * + * @param rootFolder + * the folder to copy into. + * @throws IOException + */ + private void writeContent(File rootFolder) throws IOException { + log(Messages.getString("OPSPublication.22"), Severity.INFO, indent); //$NON-NLS-1$ + EList<Item> items = opfPackage.getManifest().getItems(); + for (Item item : items) { + if (!item.isGenerated()) { + File source = new File(item.getFile()); + File destination = new File(rootFolder.getAbsolutePath() + File.separator + item.getHref()); + EPUBFileUtil.copy(source, destination); + } + } + } + + /** + * Writes a XHTML-file for the cover image. This is added to the publication and all required references set. + * + * @param rootFolder + * the publication root folder + * @throws IOException + */ + private void writeCoverHTML(File rootFolder) throws IOException { + Item coverImage = getItemById(COVER_IMAGE_ID); + File coverFile = new File(rootFolder.getAbsolutePath() + File.separator + "cover-page.xhtml"); //$NON-NLS-1$ + if (!coverFile.exists()) { + try { + log(MessageFormat.format(Messages.getString("OPSPublication.28"), coverImage.getHref()), Severity.INFO, //$NON-NLS-1$ + indent); + FileWriter fw = new FileWriter(coverFile); + fw.append("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n"); //$NON-NLS-1$ + fw.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"); //$NON-NLS-1$ + fw.append("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"); //$NON-NLS-1$ + fw.append(" <head>\n"); //$NON-NLS-1$ + fw.append(" <title>" + coverImage.getTitle() + "</title>\n"); //$NON-NLS-1$ //$NON-NLS-2$ + fw.append(" <style type=\"text/css\">"); //$NON-NLS-1$ + fw.append(" #cover-body {\n"); //$NON-NLS-1$ + fw.append(" margin: 0px;\n"); //$NON-NLS-1$ + fw.append(" text-align: center;\n"); //$NON-NLS-1$ + fw.append(" background-color: #222222;\n"); //$NON-NLS-1$ + fw.append(" }\n"); //$NON-NLS-1$ + fw.append(" #cover-block {\n"); //$NON-NLS-1$ + fw.append(" height: 100%;\n"); //$NON-NLS-1$ + fw.append(" margin-top: 0;\n"); //$NON-NLS-1$ + fw.append(" }\n"); //$NON-NLS-1$ + fw.append(" #cover-image {\n"); //$NON-NLS-1$ + fw.append(" height: 100%;\n"); //$NON-NLS-1$ + fw.append(" text-align: center;\n"); //$NON-NLS-1$ + fw.append(" max-width: 100%;\n"); //$NON-NLS-1$ + fw.append(" }\n"); //$NON-NLS-1$ + fw.append(" </style>\n"); //$NON-NLS-1$ + fw.append(" </head>\n"); //$NON-NLS-1$ + fw.append(" <body id=\"cover-body\">\n"); //$NON-NLS-1$ + fw.append(" <div id=\"cover-block\">\n"); //$NON-NLS-1$ + fw.append(" <img id=\"cover-image\" src=\"" + coverImage.getHref() + "\" alt=\"" //$NON-NLS-1$ //$NON-NLS-2$ + + coverImage.getTitle() + "\"/>\n"); //$NON-NLS-1$ + fw.append(" </div>\n"); //$NON-NLS-1$ + fw.append(" </body>\n"); //$NON-NLS-1$ + fw.append("</html>\n"); //$NON-NLS-1$ + fw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + // Add the cover page item + Item coverPage = addItem(COVER_ID, null, coverFile, null, MIMETYPE_XHTML, true, false, false); + coverPage.setGenerated(true); + addReference(coverPage.getHref(), coverImage.getTitle(), Type.COVER.getLiteral()); + // Move the cover page first in the spine. + EList<Itemref> spine = opfPackage.getSpine().getSpineItems(); + Itemref cover = null; + for (Itemref itemref : spine) { + if (itemref.getIdref().equals(COVER_ID)) { + cover = itemref; + } + } + if (cover != null) { + spine.move(0, cover); + } + } + + /** + * Writes the <b>content.opf</b> file. + * + * @param opfFile + * the location of the OPF file + * @throws IOException + */ + private void writeOPF(File opfFile) throws IOException { + ResourceSet resourceSet = new ResourceSetImpl(); + // Register the packages to make it available during loading. + URI fileURI = URI.createFileURI(opfFile.getAbsolutePath()); + Resource resource = resourceSet.createResource(fileURI); + resource.getContents().add(opfPackage); + resource.save(null); + } + + /** + * Implement to handle writing of the table of contents. Note that this method should do nothing if the table of + * contents has already been specified using {@link #setTableOfContents(File)}. + * + * @param rootFolder + * the folder to write in + * @throws Exception + */ + protected abstract void writeTableOfContents(File rootFolder) throws IOException, ParserConfigurationException, + SAXException; +}
diff --git a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/PublicationProxy.java b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/PublicationProxy.java new file mode 100644 index 0000000..e82baa4 --- /dev/null +++ b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/PublicationProxy.java
@@ -0,0 +1,334 @@ +/******************************************************************************* + * Copyright (c) 2011-2014 Torkild U. Resheim. + * + * All rights reserved. This program and the accompanying materials are made + * available under the terms of the Eclipse License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Torkild U. Resheim - initial API and implementation + *******************************************************************************/ +package org.eclipse.mylyn.docs.epub.core; + +import java.io.File; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; +import java.util.UUID; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.ecore.util.FeatureMapUtil.FeatureEList; +import org.eclipse.emf.ecore.xml.type.XMLTypePackage; +import org.eclipse.mylyn.docs.epub.dc.Creator; +import org.eclipse.mylyn.docs.epub.dc.Date; +import org.eclipse.mylyn.docs.epub.dc.Identifier; +import org.eclipse.mylyn.docs.epub.dc.Language; +import org.eclipse.mylyn.docs.epub.dc.Rights; +import org.eclipse.mylyn.docs.epub.dc.Subject; +import org.eclipse.mylyn.docs.epub.dc.Title; +import org.eclipse.mylyn.docs.epub.opf.Item; + +/** + * Simplified representation of an {@link Publication} - designed for common use cases and to make it easier to edit + * instances in user interfaces etc. + * + * @author Torkild U. Resheim + * @see Publication + * @since 2.0 TODO: add tests for this type + */ +public class PublicationProxy { + + class ValueComparator implements Comparator<String> { + + Map<String, String> base; + + public ValueComparator(Map<String, String> base) { + this.base = base; + } + + public int compare(String a, String b) { + String key_a = a; + String key_b = b; + + return key_a.compareTo(key_b); + } + } + + private static final String EMPTY_STRING = ""; //$NON-NLS-1$ + + private final static String ID = "epub-id"; //$NON-NLS-1$ + + private static final String STYLING_ID = "styling"; //$NON-NLS-1$ + + private static final EStructuralFeature TEXT = XMLTypePackage.eINSTANCE.getXMLTypeDocumentRoot_Text(); + + private final Publication publication; + + private final File markupFile; + + TreeMap<String, String> sorted_locales; + + public PublicationProxy() { + publication = Publication.getVersion2Instance(); + markupFile = null; + } + + public PublicationProxy(Publication publication, File markupFile) { + this.publication = publication; + this.markupFile = markupFile; + String id = publication.getPackage().getUniqueIdentifier(); + if (id == null || id.trim().length() == 0) { + publication.getPackage().setUniqueIdentifier(ID); + publication.addIdentifier(ID, "UUID", UUID.randomUUID().toString()); //$NON-NLS-1$ + } + // Clear everything except the metadata + publication.getPackage().getManifest().getItems().clear(); + publication.getPackage().getGuide().getGuideItems().clear(); + publication.getPackage().getSpine().getSpineItems().clear(); + + sorted_locales = new TreeMap<String, String>(); + String[] iso639s = Locale.getISOLanguages(); + for (String iso639 : iso639s) { + Locale locale = new Locale(iso639); + sorted_locales.put(locale.getDisplayLanguage(), locale.getLanguage()); + } + } + + /** + * Returns the path to the file used as a cover image if specified, otherwise an empty string is returned. + * + * @return the cover image file + */ + public String getCover() { + Item item = publication.getItemById(Publication.COVER_IMAGE_ID); + if (item == null) { + return EMPTY_STRING; + } else { + return item.getFile(); + } + } + + /** + * Returns the name of the first instance of an {@link Creator} in the publication. If a value has not been assigned + * an empty string will be returned. + * + * @return the creator name + */ + @SuppressWarnings("rawtypes") + public String getCreator() { + EList<Creator> creators = publication.getPackage().getMetadata().getCreators(); + if (creators.size() > 0) { + FeatureMap fm = creators.get(0).getMixed(); + Object o = fm.get(TEXT, false); + if (o instanceof FeatureEList) { + if (((FeatureEList) o).size() > 0) { + return ((FeatureEList) o).get(0).toString(); + } + } + } + return EMPTY_STRING; + } + + @SuppressWarnings("rawtypes") + public String getIdentifier() { + EList<Identifier> identifiers = publication.getPackage().getMetadata().getIdentifiers(); + if (identifiers.size() > 0) { + FeatureMap fm = identifiers.get(0).getMixed(); + Object o = fm.get(TEXT, false); + if (o instanceof FeatureEList) { + if (((FeatureEList) o).size() > 0) { + return ((FeatureEList) o).get(0).toString(); + } + } + } + return EMPTY_STRING; + } + + @SuppressWarnings("rawtypes") + public String getLanguage() { + EList<Language> languages = publication.getPackage().getMetadata().getLanguages(); + if (languages.size() > 0) { + FeatureMap fm = languages.get(0).getMixed(); + Object o = fm.get(TEXT, false); + if (o instanceof FeatureEList) { + if (((FeatureEList) o).size() > 0) { + String iso639 = ((FeatureEList) o).get(0).toString(); + Locale l = new Locale(iso639); + return l.getDisplayLanguage(); + } + } + } + return EMPTY_STRING; + } + + /** + * Returns a sorted map of locales that can be used to specify the {@link Language} of the publication. + * + * @return map of locales + */ + public Map<String, String> getLocales() { + return sorted_locales; + } + + public File getMarkupFile() { + return markupFile; + } + + public Publication getOPSPublication() { + return publication; + } + + @SuppressWarnings("rawtypes") + public String getPublicationDate() { + EList<Date> dates = publication.getPackage().getMetadata().getDates(); + if (dates.size() > 0) { + for (Date date : dates) { + if (date.getEvent().equals("publication")) { //$NON-NLS-1$ + FeatureMap fm = date.getMixed(); + Object o = fm.get(TEXT, false); + if (o instanceof FeatureEList) { + if (((FeatureEList) o).size() > 0) { + return ((FeatureEList) o).get(0).toString(); + } + } + } + } + } + return EMPTY_STRING; + } + + @SuppressWarnings("rawtypes") + public String getRights() { + EList<Rights> rights = publication.getPackage().getMetadata().getRights(); + if (rights.size() > 0) { + FeatureMap fm = rights.get(0).getMixed(); + Object o = fm.get(TEXT, false); + if (o instanceof FeatureEList) { + if (((FeatureEList) o).size() > 0) { + return ((FeatureEList) o).get(0).toString(); + } + } + } + return EMPTY_STRING; + } + + public String getScheme() { + Identifier ident = publication.getPackage().getMetadata().getIdentifiers().get(0); + return ident.getScheme(); + } + + public String getStyleSheet() { + List<Item> stylesheets = publication.getItemsByMIMEType(Publication.MIMETYPE_CSS); + if (stylesheets.isEmpty()) { + return EMPTY_STRING; + } else { + return stylesheets.get(0).getHref(); + } + } + + @SuppressWarnings("rawtypes") + public String getSubject() { + EList<Subject> subjects = publication.getPackage().getMetadata().getSubjects(); + if (subjects.size() > 0) { + FeatureMap fm = subjects.get(0).getMixed(); + Object o = fm.get(TEXT, false); + if (o instanceof FeatureEList) { + if (((FeatureEList) o).size() > 0) { + return ((FeatureEList) o).get(0).toString(); + } + } + } + return EMPTY_STRING; + } + + @SuppressWarnings("rawtypes") + public String getTitle() { + EList<Title> titles = publication.getPackage().getMetadata().getTitles(); + if (titles.size() > 0) { + FeatureMap fm = titles.get(0).getMixed(); + Object o = fm.get(TEXT, false); + if (o instanceof FeatureEList) { + if (((FeatureEList) o).size() > 0) { + return ((FeatureEList) o).get(0).toString(); + } + } + } + return EMPTY_STRING; + } + + public void setCover(String cover) { + if (cover.length() > 0) { + publication.setCover(new File(cover), "Cover page"); //$NON-NLS-1$ + } + } + + public void setCreator(String creator) { + publication.getPackage().getMetadata().getCreators().clear(); + publication.addCreator(creator); + } + + public void setIdentifier(String identifier) { + String scheme = getScheme(); + publication.getPackage().getMetadata().getIdentifiers().clear(); + publication.addIdentifier(ID, scheme, identifier); + publication.getPackage().setUniqueIdentifier(ID); + } + + /** + * Sets the language of the publication. If it already contains one or more language specifications, they will be + * removed. + * + * @param language + * the RFC-3066 format of the language code + */ + public void setLanguage(String language) { + publication.getPackage().getMetadata().getLanguages().clear(); + publication.addLanguage(sorted_locales.get(language)); + } + + /** + * Sets the publication date. Must be represented in the form YYYY[-MM[-DD]]: a required 4-digit year, an optional + * 2-digit month, and if the month is given, an optional 2-digit day of month. + * + * @param date + * the date in ISO-8601 format + */ + public void setPublicationDate(String date) { + publication.getPackage().getMetadata().getDates().clear(); + publication.addDate(null, date, "publication"); //$NON-NLS-1$ + } + + public void setRights(String rights) { + publication.getPackage().getMetadata().getRights().clear(); + publication.addRights(rights); + } + + public void setScheme(String schemeName) { + String identifier = getIdentifier(); + publication.getPackage().getMetadata().getIdentifiers().clear(); + publication.getPackage().setUniqueIdentifier(ID); + publication.addIdentifier(ID, schemeName, identifier); + } + + public void setStyleSheet(String css) { + if (css.length() > 0) { + publication.getPackage().getManifest().getItems().remove(publication.getItemById(STYLING_ID)); + publication.addItem(STYLING_ID, null, new File(css), null, null, false, false, true); + } + } + + public void setSubject(String subject) { + publication.getPackage().getMetadata().getSubjects().clear(); + publication.addSubject(subject); + } + + public void setTitle(String title) { + publication.getPackage().getMetadata().getTitles().clear(); + publication.addTitle(title); + } +}
diff --git a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/wikitext/MarkupToOPS.java b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/wikitext/MarkupToOPS.java index 21a7ca9..9360c49 100644 --- a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/wikitext/MarkupToOPS.java +++ b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/docs/epub/core/wikitext/MarkupToOPS.java
@@ -1,12 +1,12 @@ /******************************************************************************* * Copyright (c) 2011,2012 Torkild U. Resheim. - * + * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: + * + * Contributors: * Torkild U. Resheim - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.docs.epub.core.wikitext; @@ -19,7 +19,7 @@ import java.io.Writer; import java.util.List; -import org.eclipse.mylyn.docs.epub.core.OPSPublication; +import org.eclipse.mylyn.docs.epub.core.Publication; import org.eclipse.mylyn.docs.epub.opf.Item; import org.eclipse.mylyn.wikitext.core.parser.MarkupParser; import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder; @@ -28,8 +28,10 @@ import org.eclipse.mylyn.wikitext.core.util.XmlStreamWriter; /** - * This type can be used to populate an OPS publication directly from WikiText markup. - * + * This type can be used to populate an EPUB Publication with content directly from WikiText markup. The markup file + * will be converted to XHTML. (Strictly this file should be converted to the subset of XHTML called <i>Open Publication + * Structure</i>). + * * @author Torkild U. Resheim * @since 1.0 */ @@ -38,15 +40,15 @@ private MarkupLanguage markupLanguage; /** - * Parses the markup file and populates the OPS data. - * + * Parses the markup file and populates the publication with the result. + * * @param ops - * the OPS publication the content will be added to + * the publication the content will be added to * @param markupFile * the WikiText markup file * @return the temporary folder used for generating the HTML from markup */ - public File parse(OPSPublication ops, File markupFile) throws IOException, FileNotFoundException { + public File parse(Publication ops, File markupFile) throws IOException, FileNotFoundException { if (markupLanguage == null) { throw new IllegalStateException("must set markupLanguage"); //$NON-NLS-1$ } @@ -62,7 +64,7 @@ } }; - List<Item> stylesheets = ops.getItemsByMIMEType(OPSPublication.MIMETYPE_CSS); + List<Item> stylesheets = ops.getItemsByMIMEType(Publication.MIMETYPE_CSS); for (Item item : stylesheets) { File file = new File(item.getFile()); Stylesheet css = new Stylesheet(file); @@ -78,7 +80,6 @@ markupParser.setBuilder(builder); markupParser.setMarkupLanguage(markupLanguage); markupParser.parse(new FileReader(markupFile)); - // Convert the generated HTML to EPUB ops.setGenerateToc(true); ops.setIncludeReferencedResources(true); Item item = ops.addItem(htmlFile); @@ -89,7 +90,7 @@ /** * Sets the markup language to use when generating HTML from markup. - * + * * @param markupLanguage * the markup language */
diff --git a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/EPUBFileUtil.java b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/EPUBFileUtil.java index 771d593..e0cae67 100644 --- a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/EPUBFileUtil.java +++ b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/EPUBFileUtil.java
@@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright (c) 2011, 2012 Torkild U. Resheim. - * + * Copyright (c) 2011-2014 Torkild U. Resheim. + * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: + * + * Contributors: * Torkild U. Resheim - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.docs.epub.core; @@ -30,7 +30,7 @@ /** * Various EPUB file related utilities. - * + * * @author Torkild U. Resheim */ public class EPUBFileUtil { @@ -39,7 +39,7 @@ /** * Copies the contents of <i>source</i> to the new <i>destination</i> file. - * + * * @param source * the source file * @param destination @@ -77,7 +77,7 @@ /** * Attempts to figure out the MIME-type for the file. - * + * * @param file * the file to determine MIME-type for * @return the MIME-type or <code>null</code> @@ -130,7 +130,7 @@ /** * Creates a path segment list. - * + * * @param root * the root folder * @param file @@ -154,7 +154,7 @@ * <p> * Note that if <i>file</i> is <b>not relative</b> to root, it's absolute path will be returned. * </p> - * + * * @param root * the root directory or file * @param file @@ -184,10 +184,11 @@ * Unpacks the given <i>epubfile</i> to the <i>destination</i> directory. This method will also validate the first * item contained in the EPUB (see {@link #writeEPUBHeader(ZipOutputStream)}). * <p> - * If the destination folder does not already exist it will be created. Additionally the modification timestamp of + * If the destination folder does not already exist it will be created. Additionally the modification time stamp of * this folder will be set to the same as the originating EPUB file. * </p> - * + * TODO: Actually validate the mimetype file + * * @param epubfile * the EPUB file * @param destination @@ -239,7 +240,7 @@ * A correctly formatted EPUB file must contain an uncompressed entry named <b>mimetype</b> that is placed at the * beginning. The contents of this file must be the ASCII-encoded string <b>application/epub+zip</b>. This method * will create this file. - * + * * @param zos * the zip output stream to write to. * @throws IOException @@ -261,7 +262,7 @@ /** * Recursively compresses contents of the given folder into a zip-file. If a file already exists in the given * location an exception will be thrown. - * + * * @param destination * the destination file * @param folder @@ -283,7 +284,7 @@ /** * Adds a folder recursively to the output stream. - * + * * @param folder * the root folder * @param out
diff --git a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/OPS2Validator.java b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/OPSValidator.java similarity index 88% rename from org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/OPS2Validator.java rename to org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/OPSValidator.java index 4d3814c..32474bc 100644 --- a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/OPS2Validator.java +++ b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/OPSValidator.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2013 Torkild U. Resheim + * Copyright (c) 2012-2014 Torkild U. Resheim * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -27,14 +27,14 @@ import org.xml.sax.helpers.DefaultHandler; /** - * This type is a SAX parser that will read a XHTML file and produce a new version where elements and attributes not in - * the EPUB 2.0.1 <b>preferred</b> vocabulary are stripped. Alternatively warnings can be issued when such elements and - * attributes are found. - * + * This type is a SAX parser that will read an <i>Open Publication Structure</i> file and optionally produce a new + * version where elements and attributes not in the EPUB 2.0.1 <b>preferred</b> vocabulary are stripped. Alternatively + * warnings can be issued when such elements and attributes are found and the contents left as is. + * * @author Torkild U. Resheim * @see http://idpf.org/epub/20/spec/OPS_2.0.1_draft.htm */ -public class OPS2Validator extends DefaultHandler { +public class OPSValidator extends DefaultHandler { public enum Mode { /** Remove non-preferred elements and attributes */ @@ -43,42 +43,13 @@ WARN } - private StringBuilder contents = null; - - private final ArrayList<ValidationMessage> messages; - - public StringBuilder getContents() { - return contents; - } - - public ArrayList<ValidationMessage> getMessages() { - return messages; - } - - public static List<ValidationMessage> validate(InputSource file, String href) throws ParserConfigurationException, - SAXException, IOException { - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setFeature("http://xml.org/sax/features/validation", false); //$NON-NLS-1$ - factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$ - SAXParser parser = factory.newSAXParser(); - OPS2Validator tocGenerator = new OPS2Validator(href, Mode.WARN); - try { - parser.parse(file, tocGenerator); - return tocGenerator.getMessages(); - } catch (SAXException e) { - System.err.println("Could not parse " + href); //$NON-NLS-1$ - e.printStackTrace(); - } - return null; - } - public static String clean(InputSource file, String href) throws ParserConfigurationException, SAXException, IOException { SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setFeature("http://xml.org/sax/features/validation", false); //$NON-NLS-1$ factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$ SAXParser parser = factory.newSAXParser(); - OPS2Validator tocGenerator = new OPS2Validator(href, Mode.REMOVE); + OPSValidator tocGenerator = new OPSValidator(href, Mode.REMOVE); try { parser.parse(file, tocGenerator); return tocGenerator.getContents().toString(); @@ -89,8 +60,29 @@ return null; } + public static List<ValidationMessage> validate(InputSource file, String href) throws ParserConfigurationException, + SAXException, IOException { + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setFeature("http://xml.org/sax/features/validation", false); //$NON-NLS-1$ + factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$ + SAXParser parser = factory.newSAXParser(); + OPSValidator tocGenerator = new OPSValidator(href, Mode.WARN); + try { + parser.parse(file, tocGenerator); + return tocGenerator.getMessages(); + } catch (SAXException e) { + System.err.println("Could not parse " + href); //$NON-NLS-1$ + e.printStackTrace(); + } + return null; + } + private StringBuilder buffer = null; + private StringBuilder contents = null; + + private final String href; + @SuppressWarnings("nls") private final String[] legalAttributes = new String[] { "accesskey", "charset", "class", "coords", "dir", "href", "hreflang", "id", "rel", "rev", "shape", "style", "tabindex", "target", "title", "type", "xml:lang", @@ -99,7 +91,7 @@ /** * A list of legal elements according to the EPUB 2.0.1 specification - * + * * @see http://idpf.org/epub/20/spec/OPS_2.0.1_draft.htm#Section1.3.4 * @see http://idpf.org/epub/20/spec/OPS_2.0.1_draft.htm#Section2.2 */ @@ -111,19 +103,20 @@ "colgroup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "img", "area", "map", "style", "link", "base" }; + private final ArrayList<ValidationMessage> messages; + private Mode mode = Mode.WARN; /** - * A list of elements that should be let through regardless of contents. + * A list of elements that should be let through regardless of contents. Some publishers use this element to handle + * features present in certain reading systems. */ @SuppressWarnings("nls") private final String[] passthroughElements = new String[] { "meta" }; private boolean recording = false; - private final String href; - - public OPS2Validator(String href, Mode mode) { + public OPSValidator(String href, Mode mode) { super(); this.href = href; buffer = new StringBuilder(); @@ -149,9 +142,17 @@ recording = false; } + public StringBuilder getContents() { + return contents; + } + + public ArrayList<ValidationMessage> getMessages() { + return messages; + } + /** * Returns <code>true</code> if the given attribute name is legal. - * + * * @param name * @return */ @@ -173,6 +174,14 @@ return false; } + /** + * Use to determine whether or not elements with this name should be let trough the validator with any change or + * warning. + * + * @param name + * the name of the element + * @return whether or not to pass through + */ private boolean isPassthroughElement(String name) { for (String legal : passthroughElements) { if (name.equalsIgnoreCase(legal)) {
diff --git a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/ReferenceScanner.java b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/ReferenceScanner.java index 06f0df0..01c0246 100644 --- a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/ReferenceScanner.java +++ b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/ReferenceScanner.java
@@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright (c) 2011,2012 Torkild U. Resheim. - * + * Copyright (c) 2011-2014 Torkild U. Resheim. + * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: + * + * Contributors: * Torkild U. Resheim - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.docs.epub.core; @@ -27,8 +27,8 @@ import org.xml.sax.SAXException; /** - * This type is a SAX parser that will read a XHTML file and create a list of all images that are referenced either - * through an <i>img<i/> tag or a link. + * This type is a SAX parser that will read a XHTML file and create a list of all images, content and CSS-files that are + * referenced either through an <i>img<i/> tag or a link. * * @author Torkild U. Resheim */ @@ -109,7 +109,7 @@ } } - // Also handle links to image files + // Also handle links to files if (qName.equalsIgnoreCase("a")) { //$NON-NLS-1$ String ref = getAttribute(attributes, "href"); //$NON-NLS-1$ if (ref != null) { @@ -128,10 +128,10 @@ private void includeRef(String ref) { String t = ref.toLowerCase(); - if (t.startsWith("#") || t.startsWith("http://") || t.startsWith("https://")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + if (t.startsWith("#") || t.startsWith("http://") || t.startsWith("https://")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return; } - // Handle links to anchors within resources (bug 375795). + // Handle links to anchors within resources (bug 375795). if (ref.indexOf('#') > -1) { ref = ref.substring(0, ref.indexOf('#')); }
diff --git a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/TOCGenerator.java b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/TOCGenerator.java index 54aee10..48ebbfb 100644 --- a/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/TOCGenerator.java +++ b/org.eclipse.mylyn.docs.epub.core/src/org/eclipse/mylyn/internal/docs/epub/core/TOCGenerator.java
@@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright (c) 2011,2012 Torkild U. Resheim. - * + * Copyright (c) 2011-2014 Torkild U. Resheim. + * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: + * + * Contributors: * Torkild U. Resheim - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.docs.epub.core; @@ -29,8 +29,8 @@ import org.xml.sax.SAXException; /** - * This type is a SAX parser that will read a XHTML file, locate headers and create NCX items for the EPUB table of - * contents. Each header must have an "id" attribute or it will not be possible to link to the header. + * This type is a SAX parser that will read a XHTML file, locate header text (<b>H1</b> trough <b>H6</b>) and create NCX + * items for the EPUB table of contents. * * @author Torkild U. Resheim */ @@ -112,10 +112,14 @@ } /** + * Parses an XHTML file, representing a publication chapter, and generates a table of contents for this chapter. + * * @param file + * the XHTML file to parse * @param href + * the XHTML file referencing this file * @param ncx - * the NCX + * the NCX to add headers to * @param playOrder * initial play order * @return
diff --git a/org.eclipse.mylyn.docs.epub.tests/META-INF/MANIFEST.MF b/org.eclipse.mylyn.docs.epub.tests/META-INF/MANIFEST.MF index c140279..9af8305 100644 --- a/org.eclipse.mylyn.docs.epub.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.mylyn.docs.epub.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.mylyn.docs.epub.tests -Bundle-Version: 1.3.0.qualifier +Bundle-Version: 2.0.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Require-Bundle: org.junit,
diff --git a/org.eclipse.mylyn.docs.epub.tests/pom.xml b/org.eclipse.mylyn.docs.epub.tests/pom.xml index 612533b..8c09000 100644 --- a/org.eclipse.mylyn.docs.epub.tests/pom.xml +++ b/org.eclipse.mylyn.docs.epub.tests/pom.xml
@@ -9,7 +9,7 @@ <version>2.0.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.mylyn.docs.epub.tests</artifactId> - <version>1.3.0-SNAPSHOT</version> + <version>2.0.0-SNAPSHOT</version> <packaging>eclipse-test-plugin</packaging> <properties> <test.suite>${project.artifactId}.AllTests</test.suite>
diff --git a/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/AbstractTest.java b/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/AbstractTest.java index ddf9972..5e00306 100644 --- a/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/AbstractTest.java +++ b/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/AbstractTest.java
@@ -21,8 +21,8 @@ import org.eclipse.emf.ecore.xml.type.XMLTypePackage; import org.eclipse.mylyn.docs.epub.core.EPUB; import org.eclipse.mylyn.docs.epub.core.ILogger; -import org.eclipse.mylyn.docs.epub.core.OPS2Publication; import org.eclipse.mylyn.docs.epub.core.OPSPublication; +import org.eclipse.mylyn.docs.epub.core.Publication; import org.eclipse.mylyn.docs.epub.dc.DCType; import org.eclipse.mylyn.docs.epub.dc.Identifier; import org.eclipse.mylyn.docs.epub.tests.ValidationReport; @@ -80,7 +80,7 @@ protected final StdOutLogger logger = new StdOutLogger(); - protected OPSPublication oebps; + protected Publication oebps; protected boolean deleteFolder(File folder) { if (folder.isDirectory()) { @@ -134,7 +134,7 @@ } epubFolder.mkdirs(); epub = new EPUB(logger); - oebps = new OPS2Publication(logger); + oebps = new OPSPublication(logger); } /**
diff --git a/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/TestEPUB.java b/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/TestEPUB.java index f8ccfaf..89bf6a6 100644 --- a/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/TestEPUB.java +++ b/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/TestEPUB.java
@@ -18,8 +18,8 @@ import org.eclipse.emf.common.util.EList; import org.eclipse.mylyn.docs.epub.core.EPUB; -import org.eclipse.mylyn.docs.epub.core.OPS2Publication; import org.eclipse.mylyn.docs.epub.core.OPSPublication; +import org.eclipse.mylyn.docs.epub.core.Publication; import org.eclipse.mylyn.docs.epub.ocf.Container; import org.eclipse.mylyn.docs.epub.ocf.RootFile; import org.eclipse.mylyn.docs.epub.ocf.RootFiles; @@ -93,7 +93,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.EPUB#add(org.eclipse.mylyn.docs.epub.core.OPSPublication)} . + * {@link org.eclipse.mylyn.docs.epub.core.EPUB#add(org.eclipse.mylyn.docs.epub.core.Publication)} . * <ul> * <li>Container shall hold more than one OPS publication</li> * <li>OPS structures shall follow naming conventions.</li> @@ -106,8 +106,8 @@ @Test public final void testAddOPSPublication() throws Exception { EPUB epub = new EPUB(); - OPSPublication oebps1 = new OPS2Publication(); - OPSPublication oebps2 = new OPS2Publication(); + Publication oebps1 = new OPSPublication(); + Publication oebps2 = new OPSPublication(); epub.add(oebps1); epub.add(oebps2); Container container = epub.getContainer(); @@ -132,7 +132,7 @@ @Test public final void testGetOPSPublications() throws Exception { EPUB epub = new EPUB(); - OPSPublication oebps = new OPS2Publication(); + Publication oebps = new OPSPublication(); epub.add(oebps); File drawing = new File("testdata/drawing.svg"); epub.add(drawing, "image/svg+xml"); @@ -150,7 +150,7 @@ @Test public final void testPackFile() throws Exception { EPUB epub = new EPUB(); - OPSPublication oebps = new OPS2Publication(); + Publication oebps = new OPSPublication(); oebps.addItem(new File("testdata/plain-page.xhtml")); epub.add(oebps); File drawing = new File("testdata/drawing.svg"); @@ -172,7 +172,7 @@ @Test public final void testPackFileFile() throws Exception { EPUB epub = new EPUB(); - OPSPublication oebps = new OPS2Publication(); + Publication oebps = new OPSPublication(); oebps.addItem(new File("testdata/plain-page.xhtml")); epub.add(oebps); epub.pack(epubFile, epubFolder); @@ -201,7 +201,7 @@ public final void testPackFileFileExists() throws Exception { File workingFolder = File.createTempFile("epub_", null); EPUB epub = new EPUB(); - OPSPublication oebps = new OPS2Publication(); + Publication oebps = new OPSPublication(); epub.add(oebps); try { epub.pack(epubFile, workingFolder); @@ -238,7 +238,7 @@ @Test public final void testUnpackFile() throws Exception { EPUB epub = new EPUB(); - OPSPublication oebps = new OPS2Publication(); + Publication oebps = new OPSPublication(); oebps.addItem(new File("testdata/plain-page.xhtml")); epub.add(oebps); epub.pack(epubFile, epubFolder); @@ -256,7 +256,7 @@ public final void testUnpackFileFile() throws Exception { // First pack the EPUB EPUB epub = new EPUB(); - OPSPublication oebps = new OPS2Publication(); + Publication oebps = new OPSPublication(); oebps.addItem(new File("testdata/plain-page.xhtml")); epub.add(oebps); epub.pack(epubFile, epubFolder); @@ -374,7 +374,7 @@ @Test public final void test_Bug378800() throws Exception { EPUB epub = new EPUB(); - OPSPublication oebps = new OPS2Publication(); + Publication oebps = new OPSPublication(); oebps.addItem(new File("testdata/plain-page.xhtml")); epub.add(oebps); epub.pack(epubFile, epubFolder);
diff --git a/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/TestOPS2Publication.java b/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/TestOPS2Publication.java index 8129ccc..db60fb7 100644 --- a/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/TestOPS2Publication.java +++ b/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/TestOPS2Publication.java
@@ -19,8 +19,8 @@ import org.eclipse.emf.ecore.util.FeatureMapUtil.FeatureEList; import org.eclipse.emf.ecore.xml.type.XMLTypePackage; import org.eclipse.mylyn.docs.epub.core.EPUB; -import org.eclipse.mylyn.docs.epub.core.OPS2Publication; import org.eclipse.mylyn.docs.epub.core.OPSPublication; +import org.eclipse.mylyn.docs.epub.core.Publication; import org.eclipse.mylyn.docs.epub.core.ValidationMessage; import org.eclipse.mylyn.docs.epub.core.ValidationMessage.Severity; import org.eclipse.mylyn.docs.epub.ncx.Meta; @@ -30,7 +30,7 @@ import org.junit.Test; /** - * Tests features and regressions specific to the OPS 2.0.1 supporting implementation {@link OPS2Publication}. + * Tests features and regressions specific to the OPS 2.0.1 supporting implementation {@link OPSPublication}. * * @author Torkild U. Resheim */ @@ -60,7 +60,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPS2Publication#generateTableOfContents()} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#generateTableOfContents()} . * <ul> * <li>Table of contents shall be generated from content per default.</li> * </ul> @@ -83,7 +83,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPS2Publication#generateTableOfContents()} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#generateTableOfContents()} . * <ul> * <li>Table of contents shall exist but be empty if not otherwise specified.</li> * </ul> @@ -101,7 +101,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPS2Publication#getTableOfContents()} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#getTableOfContents()} . * <ul> * <li>There shall be a table of contents, even if empty.</li> * </ul> @@ -116,7 +116,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPS2Publication#readTableOfContents(java.io.File)} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#readTableOfContents(java.io.File)} . * * @throws Exception */ @@ -128,7 +128,7 @@ EPUB epub_in = new EPUB(); epub_in.unpack(epubFile, epubFolder); - OPSPublication oebps_in = epub_in.getOPSPublications().get(0); + Publication oebps_in = epub_in.getOPSPublications().get(0); assertTrue(oebps_in.getTableOfContents() != null); assertTrue(oebps_in.getTableOfContents() instanceof Ncx); Ncx ncx = (Ncx) oebps_in.getTableOfContents(); @@ -139,7 +139,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPS2Publication#setTableOfContents(java.io.File)} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#setTableOfContents(java.io.File)} . * * @throws Exception */ @@ -151,7 +151,7 @@ epub.pack(epubFile); EPUB epub_in = new EPUB(); epub_in.unpack(epubFile, epubFolder); - OPSPublication oebps_in = epub_in.getOPSPublications().get(0); + Publication oebps_in = epub_in.getOPSPublications().get(0); assertTrue(oebps_in.getTableOfContents() != null); assertTrue(oebps_in.getTableOfContents() instanceof Ncx); Ncx ncx = (Ncx) oebps_in.getTableOfContents(); @@ -168,7 +168,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPS2Publication#validateContents()} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#validateContents()} . * <ul> * <li>There shall be a warning message</li> * </ul> @@ -204,7 +204,7 @@ oebps.addItem(new File("testdata/OPF-Tests/Bug_379052/chapter-1.xhtml")); epub.pack(epubFile); // Two XHTML files, one with a warning. One CSS file and the NCX. - assertEquals(4, oebps.getOpfPackage().getManifest().getItems().size()); + assertEquals(4, oebps.getPackage().getManifest().getItems().size()); // Should be exactly two warning. assertEquals(1, oebps.getValidationMessages().size()); epubFile.delete(); @@ -277,7 +277,7 @@ item.setFallback("fallback"); oebps.addItem("fallback", null, new File("testdata/plain-page.xhtml"), null, null, true, true, false); epub.pack(epubFile); - assertEquals(3, oebps.getOpfPackage().getManifest().getItems().size()); + assertEquals(3, oebps.getPackage().getManifest().getItems().size()); assertEquals(1, oebps.getValidationMessages().size()); ValidationMessage msg = oebps.getValidationMessages().get(0); assertEquals(Severity.WARNING, msg.getSeverity()); @@ -287,7 +287,7 @@ .equals("Item \"illegal-type.html\" is not a core media type but a legal fallback item has been specified.")); } - private class EPUB_NCX_Test extends OPS2Publication { + private class EPUB_NCX_Test extends OPSPublication { public void testReadOCF(File tocFile) throws IOException { readTableOfContents(tocFile); }
diff --git a/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/TestOPSPublication.java b/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/TestOPSPublication.java index ec6236f..6066634 100644 --- a/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/TestOPSPublication.java +++ b/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/api/TestOPSPublication.java
@@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright (c) 2011,2012 Torkild U. Resheim. - * + * Copyright (c) 2011-2014 Torkild U. Resheim. + * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: + * + * Contributors: * Torkild U. Resheim - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.docs.epub.tests.api; @@ -20,9 +20,10 @@ import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.EList; import org.eclipse.mylyn.docs.epub.core.EPUB; -import org.eclipse.mylyn.docs.epub.core.OPS2Publication; import org.eclipse.mylyn.docs.epub.core.OPSPublication; +import org.eclipse.mylyn.docs.epub.core.Publication; import org.eclipse.mylyn.docs.epub.core.ValidationException; +import org.eclipse.mylyn.docs.epub.dc.Contributor; import org.eclipse.mylyn.docs.epub.dc.Coverage; import org.eclipse.mylyn.docs.epub.dc.Date; import org.eclipse.mylyn.docs.epub.dc.Description; @@ -34,6 +35,7 @@ import org.eclipse.mylyn.docs.epub.dc.Subject; import org.eclipse.mylyn.docs.epub.dc.Title; import org.eclipse.mylyn.docs.epub.opf.Item; +import org.eclipse.mylyn.docs.epub.opf.Role; import org.junit.Assert; import org.junit.Test; @@ -42,8 +44,8 @@ import com.adobe.epubcheck.util.DefaultReportImpl; /** - * Tests features and regressions for all versions of the OPS supporting implementation {@link OPSPublication}. - * + * Tests features and regressions for all versions of the OPS supporting implementation {@link Publication}. + * * @author Torkild U. Resheim */ @SuppressWarnings("nls") @@ -51,17 +53,20 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addContributor(java.lang.String, java.util.Locale, java.lang.String, org.eclipse.mylyn.docs.epub.opf.Role, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addContributor(java.lang.String, java.util.Locale, java.lang.String, org.eclipse.mylyn.docs.epub.opf.Role, java.lang.String)} * . */ @Test public final void testAddContributor() { - // TODO + Contributor contributor = oebps.addContributor("Nomen Nescio"); + contributor.setRole(Role.AUTHOR); + + oebps.addContributor(null, null, "Nomen Nescio", Role.AUTHOR, null); } /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addCoverage(java.lang.String, java.util.Locale, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addCoverage(java.lang.String, java.util.Locale, java.lang.String)} * . */ @Test @@ -69,7 +74,7 @@ oebps.addCoverage("Coverage", Locale.CANADA_FRENCH, "My Coverage"); oebps.addCoverage(null, Locale.CANADA_FRENCH, "My Coverage"); oebps.addCoverage(null, null, "My Coverage"); - EList<Coverage> Coverages = oebps.getOpfPackage().getMetadata().getCoverages(); + EList<Coverage> Coverages = oebps.getPackage().getMetadata().getCoverages(); Assert.assertEquals("Coverage", Coverages.get(0).getId()); Assert.assertEquals("fr_CA", Coverages.get(0).getLang()); Assert.assertEquals("My Coverage", getText(Coverages.get(0))); @@ -88,7 +93,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addCreator(java.lang.String, java.util.Locale, java.lang.String, org.eclipse.mylyn.docs.epub.opf.Role, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addCreator(java.lang.String, java.util.Locale, java.lang.String, org.eclipse.mylyn.docs.epub.opf.Role, java.lang.String)} * . */ @Test @@ -98,7 +103,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addDate(java.lang.String, java.util.Date, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addDate(java.lang.String, java.util.Date, java.lang.String)} * . */ @Test @@ -108,7 +113,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addDate(java.lang.String, java.lang.String, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addDate(java.lang.String, java.lang.String, java.lang.String)} * . */ @Test @@ -117,7 +122,7 @@ oebps.addDate(null, "1969-03", null); oebps.addDate(null, "1969-03-14", null); oebps.addDate(null, "1969-03-14", "event"); - EList<Date> dates = oebps.getOpfPackage().getMetadata().getDates(); + EList<Date> dates = oebps.getPackage().getMetadata().getDates(); assertEquals("1969", getText(dates.get(0))); assertEquals("1969-03", getText(dates.get(1))); assertEquals("1969-03-14", getText(dates.get(2))); @@ -131,7 +136,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addDescription(java.lang.String, java.util.Locale, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addDescription(java.lang.String, java.util.Locale, java.lang.String)} * . */ @Test @@ -139,7 +144,7 @@ oebps.addDescription("Description", Locale.CANADA_FRENCH, "My Description"); oebps.addDescription(null, Locale.CANADA_FRENCH, "My Description"); oebps.addDescription(null, null, "My Description"); - EList<Description> Descriptions = oebps.getOpfPackage().getMetadata().getDescriptions(); + EList<Description> Descriptions = oebps.getPackage().getMetadata().getDescriptions(); Assert.assertEquals("Description", Descriptions.get(0).getId()); Assert.assertEquals("fr_CA", Descriptions.get(0).getLang()); Assert.assertEquals("My Description", getText(Descriptions.get(0))); @@ -158,14 +163,14 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addFormat(java.lang.String, java.lang.String)} . + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addFormat(java.lang.String, java.lang.String)} . */ @Test public final void testAddFormat() { oebps.addDescription("Description", Locale.CANADA_FRENCH, "My Description"); oebps.addDescription(null, Locale.CANADA_FRENCH, "My Description"); oebps.addDescription(null, null, "My Description"); - EList<Description> Descriptions = oebps.getOpfPackage().getMetadata().getDescriptions(); + EList<Description> Descriptions = oebps.getPackage().getMetadata().getDescriptions(); Assert.assertEquals("Description", Descriptions.get(0).getId()); Assert.assertEquals("fr_CA", Descriptions.get(0).getLang()); Assert.assertEquals("My Description", getText(Descriptions.get(0))); @@ -184,7 +189,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addIdentifier(java.lang.String, java.lang.String, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addIdentifier(java.lang.String, java.lang.String, java.lang.String)} * . */ @Test @@ -192,7 +197,7 @@ oebps.addIdentifier("Identifier", "ID", "My Identifier"); oebps.addIdentifier(null, "ID", "My Identifier"); oebps.addIdentifier(null, null, "My Identifier"); - EList<Identifier> Identifiers = oebps.getOpfPackage().getMetadata().getIdentifiers(); + EList<Identifier> Identifiers = oebps.getPackage().getMetadata().getIdentifiers(); Assert.assertEquals("Identifier", Identifiers.get(0).getId()); Assert.assertEquals("ID", Identifiers.get(0).getScheme()); Assert.assertEquals("My Identifier", getText(Identifiers.get(0))); @@ -210,7 +215,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addItem(java.io.File)} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#addItem(java.io.File)} . */ @Test public final void testAddItemFile() { @@ -219,7 +224,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addItem(java.lang.String, java.util.Locale, java.io.File, java.lang.String, java.lang.String, boolean, boolean, boolean)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addItem(java.lang.String, java.util.Locale, java.io.File, java.lang.String, java.lang.String, boolean, boolean, boolean)} * . */ @Test @@ -229,14 +234,14 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addLanguage(java.lang.String, java.lang.String)} . + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addLanguage(java.lang.String, java.lang.String)} . */ @Test public final void testAddLanguage() { oebps.addLanguage(null, "no"); oebps.addLanguage("id", "no"); - Assert.assertEquals("no", getText(oebps.getOpfPackage().getMetadata().getLanguages().get(0))); - Assert.assertEquals("id", oebps.getOpfPackage().getMetadata().getLanguages().get(1).getId()); + Assert.assertEquals("no", getText(oebps.getPackage().getMetadata().getLanguages().get(0))); + Assert.assertEquals("id", oebps.getPackage().getMetadata().getLanguages().get(1).getId()); try { oebps.addLanguage(null, null); fail(); @@ -246,13 +251,13 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addMeta(java.lang.String, java.lang.String)} . + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addMeta(java.lang.String, java.lang.String)} . */ @Test public final void testAddMeta() { oebps.addMeta("name", "value"); - assertEquals("name", oebps.getOpfPackage().getMetadata().getMetas().get(0).getName()); - assertEquals("value", oebps.getOpfPackage().getMetadata().getMetas().get(0).getContent()); + assertEquals("name", oebps.getPackage().getMetadata().getMetas().get(0).getName()); + assertEquals("value", oebps.getPackage().getMetadata().getMetas().get(0).getContent()); try { oebps.addMeta(null, "value"); fail(); @@ -267,7 +272,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addPublisher(java.lang.String, java.util.Locale, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addPublisher(java.lang.String, java.util.Locale, java.lang.String)} * . */ @Test @@ -275,7 +280,7 @@ oebps.addPublisher("Publisher", Locale.CANADA_FRENCH, "My Publisher"); oebps.addPublisher(null, Locale.CANADA_FRENCH, "My Publisher"); oebps.addPublisher(null, null, "My Publisher"); - EList<Publisher> Publishers = oebps.getOpfPackage().getMetadata().getPublishers(); + EList<Publisher> Publishers = oebps.getPackage().getMetadata().getPublishers(); Assert.assertEquals("Publisher", Publishers.get(0).getId()); Assert.assertEquals("fr_CA", Publishers.get(0).getLang()); Assert.assertEquals("My Publisher", getText(Publishers.get(0))); @@ -294,7 +299,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addReference(java.lang.String, java.lang.String, org.eclipse.mylyn.docs.epub.opf.Type)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addReference(java.lang.String, java.lang.String, org.eclipse.mylyn.docs.epub.opf.Type)} * . */ @Test @@ -304,7 +309,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addRelation(java.lang.String, java.util.Locale, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addRelation(java.lang.String, java.util.Locale, java.lang.String)} * . */ @Test @@ -312,7 +317,7 @@ oebps.addRelation("Relation", Locale.CANADA_FRENCH, "My Relation"); oebps.addRelation(null, Locale.CANADA_FRENCH, "My Relation"); oebps.addRelation(null, null, "My Relation"); - EList<Relation> Relations = oebps.getOpfPackage().getMetadata().getRelations(); + EList<Relation> Relations = oebps.getPackage().getMetadata().getRelations(); Assert.assertEquals("Relation", Relations.get(0).getId()); Assert.assertEquals("fr_CA", Relations.get(0).getLang()); Assert.assertEquals("My Relation", getText(Relations.get(0))); @@ -331,7 +336,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addRights(java.lang.String, java.util.Locale, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addRights(java.lang.String, java.util.Locale, java.lang.String)} * . */ @Test @@ -339,7 +344,7 @@ oebps.addRights("Rights", Locale.CANADA_FRENCH, "My Rights"); oebps.addRights(null, Locale.CANADA_FRENCH, "My Rights"); oebps.addRights(null, null, "My Rights"); - EList<Rights> Rightss = oebps.getOpfPackage().getMetadata().getRights(); + EList<Rights> Rightss = oebps.getPackage().getMetadata().getRights(); Assert.assertEquals("Rights", Rightss.get(0).getId()); Assert.assertEquals("fr_CA", Rightss.get(0).getLang()); Assert.assertEquals("My Rights", getText(Rightss.get(0))); @@ -358,7 +363,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addSource(java.lang.String, java.util.Locale, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addSource(java.lang.String, java.util.Locale, java.lang.String)} * . */ @Test @@ -366,7 +371,7 @@ oebps.addSource("Source", Locale.CANADA_FRENCH, "My Source"); oebps.addSource(null, Locale.CANADA_FRENCH, "My Source"); oebps.addSource(null, null, "My Source"); - EList<Source> Sources = oebps.getOpfPackage().getMetadata().getSources(); + EList<Source> Sources = oebps.getPackage().getMetadata().getSources(); Assert.assertEquals("Source", Sources.get(0).getId()); Assert.assertEquals("fr_CA", Sources.get(0).getLang()); Assert.assertEquals("My Source", getText(Sources.get(0))); @@ -386,7 +391,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addSubject(java.lang.String, java.util.Locale, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addSubject(java.lang.String, java.util.Locale, java.lang.String)} * . */ @Test @@ -394,7 +399,7 @@ oebps.addSubject("Subject", Locale.CANADA_FRENCH, "My Subject"); oebps.addSubject(null, Locale.CANADA_FRENCH, "My Subject"); oebps.addSubject(null, null, "My Subject"); - EList<Subject> subjects = oebps.getOpfPackage().getMetadata().getSubjects(); + EList<Subject> subjects = oebps.getPackage().getMetadata().getSubjects(); Assert.assertEquals("Subject", subjects.get(0).getId()); Assert.assertEquals("fr_CA", subjects.get(0).getLang()); Assert.assertEquals("My Subject", getText(subjects.get(0))); @@ -413,7 +418,7 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addTitle(java.lang.String, java.util.Locale, java.lang.String)} + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addTitle(java.lang.String, java.util.Locale, java.lang.String)} * . */ @Test @@ -421,7 +426,7 @@ oebps.addTitle("Title", Locale.CANADA_FRENCH, "My Title"); oebps.addTitle(null, Locale.CANADA_FRENCH, "My Title"); oebps.addTitle(null, null, "My Title"); - EList<Title> titles = oebps.getOpfPackage().getMetadata().getTitles(); + EList<Title> titles = oebps.getPackage().getMetadata().getTitles(); Assert.assertEquals("Title", titles.get(0).getId()); Assert.assertEquals("fr_CA", titles.get(0).getLang()); Assert.assertEquals("My Title", getText(titles.get(0))); @@ -440,13 +445,13 @@ /** * Test method for - * {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#addType(java.lang.String, java.lang.String)} . + * {@link org.eclipse.mylyn.docs.epub.core.Publication#addType(java.lang.String, java.lang.String)} . */ @Test public final void testAddType() { oebps.addType("Type", "My Type"); oebps.addType(null, "My Type"); - EList<org.eclipse.mylyn.docs.epub.dc.Type> Types = oebps.getOpfPackage().getMetadata().getTypes(); + EList<org.eclipse.mylyn.docs.epub.dc.Type> Types = oebps.getPackage().getMetadata().getTypes(); Assert.assertEquals("Type", Types.get(0).getId()); Assert.assertEquals("My Type", getText(Types.get(0))); Assert.assertEquals(null, Types.get(1).getId()); @@ -459,7 +464,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#generateTableOfContents()} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#generateTableOfContents()} . */ @Test public final void testGenerateTableOfContents() { @@ -467,7 +472,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#getIdentifier()}. + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#getIdentifier()}. */ @Test public final void testGetIdentifier() { @@ -475,7 +480,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#getItemById(java.lang.String)} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#getItemById(java.lang.String)} . */ @Test public final void testGetItemById() { @@ -483,7 +488,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#getItemsByMIMEType(java.lang.String)} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#getItemsByMIMEType(java.lang.String)} . */ @Test public final void testGetItemsByMIMEType() { @@ -498,7 +503,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#getOpfPackage()}. + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#getPackage()}. */ @Test public final void testGetOpfPackage() { @@ -506,7 +511,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#getRootFolder()}. + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#getRootFolder()}. */ @Test public final void testGetRootFolder() { @@ -514,7 +519,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#getSpine()}. + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#getSpine()}. */ @Test public final void testGetSpine() { @@ -522,7 +527,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#getTableOfContents()} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#getTableOfContents()} . */ @Test public final void testGetTableOfContents() { @@ -530,7 +535,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#getValidationMessages()} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#getValidationMessages()} . */ @Test public final void testGetValidationMessages() { @@ -538,9 +543,9 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#pack(java.io.File)}. An EPUB where only a + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#pack(java.io.File)}. An EPUB where only a * single page has been added shall be packed without issues - * + * * @throws Exception */ @Test @@ -557,14 +562,14 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#pack(java.io.File)}. An EPUB with no + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#pack(java.io.File)}. An EPUB with no * content shall fail when packed. - * + * * @throws Exception */ @Test public final void testPack_Empty() throws Exception { - epub.add(new OPS2Publication()); + epub.add(new OPSPublication()); try { epubFile.delete(); epub.pack(epubFile); @@ -574,7 +579,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#readTableOfContents(java.io.File)} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#readTableOfContents(java.io.File)} . */ @Test public final void testReadTableOfContents() { @@ -582,13 +587,13 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#setCover(java.io.File, java.lang.String)} + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#setCover(java.io.File, java.lang.String)} * . * <ul> * <li>Cover page SVG shall exist in the unpacked folder</li> * <li>Cover page HTML shall exist in the unpacked folder</li> * </ul> - * + * * @throws Exception */ @Test @@ -609,7 +614,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#setGenerateToc(boolean)} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#setGenerateToc(boolean)} . */ @Test public final void testSetGenerateToc() { @@ -617,7 +622,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#setIdentifierId(java.lang.String)} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#setIdentifierId(java.lang.String)} . */ @Test public final void testSetIdentifierId() { @@ -625,11 +630,11 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#setIncludeReferencedResources(boolean)}. + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#setIncludeReferencedResources(boolean)}. * This is determining whether or not the referenced resources has been picked up and included in the resulting * EPUB. Also handles <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=375795">bug 375795</a>: [epub][patch] * Automatic inclusion of referenced resources fail on anchor references - * + * * @throws Exception */ @Test @@ -655,14 +660,14 @@ Assert.assertTrue(html2.exists()); // The manifest shall only contain the items we have linked to in addition to the toc.ncx and the file that we // started from -- a total of six files. - Assert.assertEquals(6, oebps.getOpfPackage().getManifest().getItems().size()); + Assert.assertEquals(6, oebps.getPackage().getManifest().getItems().size()); } /** * Test method for <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=380016">bug 380016</a>: Reference scanner * should also include referenced CSS style sheets - * + * * @throws Exception */ @Test @@ -683,7 +688,7 @@ /** * Test method for <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=360701">bug 360701</a>: [epub] Automatic * inclusion of referenced resources don't work for WikiText generated HTML. - * + * * @throws Exception */ @Test @@ -713,7 +718,7 @@ /** * Test method for <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=373052">bug 373052</a>: [epub] Reference * scanner does not handle absolute paths - * + * * @throws Exception */ @Test @@ -753,7 +758,7 @@ * File A references file C as do file B. File C references file A. Before the fix there would be two instances of * file C. * </p> - * + * * @throws Exception */ public final void test_Bug376312() throws Exception { @@ -763,14 +768,14 @@ oebps.addItem(new File("testdata/circular/file-b.xhtml")); epub.add(oebps); epub.pack(epubFile); - EList<Item> items = oebps.getOpfPackage().getManifest().getItems(); + EList<Item> items = oebps.getPackage().getManifest().getItems(); // File A, B, C and the NCX assertEquals(4, items.size()); } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#setTableOfContents(java.io.File)} . - * + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#setTableOfContents(java.io.File)} . + * * @see TestOPS2Publication#testSetTableOfContents() */ @Test @@ -779,7 +784,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#unpack(java.io.File)} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#unpack(java.io.File)} . */ @Test public final void testUnpack() { @@ -787,7 +792,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#validateContents()} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#validateContents()} . */ @Test public final void testValidateContents() { @@ -795,7 +800,7 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#validateMetadata()} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#validateMetadata()} . */ @Test public final void testValidateMetadata() { @@ -803,14 +808,14 @@ } /** - * Test method for {@link org.eclipse.mylyn.docs.epub.core.OPSPublication#writeTableOfContents(java.io.File)} . + * Test method for {@link org.eclipse.mylyn.docs.epub.core.Publication#writeTableOfContents(java.io.File)} . */ @Test public final void testWriteTableOfContents() { // TODO } - private class EPUB_OPF_Test extends OPS2Publication { + private class EPUB_OPF_Test extends OPSPublication { public void testReadOPF(File rootFile) throws IOException { readOPF(rootFile); } @@ -818,7 +823,7 @@ /** * See if the OPF file generated by this tooling can be read. - * + * * @throws Exception */ @Test @@ -832,7 +837,7 @@ * This case was discovered when testing an EPUB file generated by DocBook Reading the OPF fails with a * java.net.SocketException: Unexpected end of file from server. On closer inspection we can see that the file is * declared as XHTML (which it of course is not). This is probably due to an issue in DocBook XSL 1.76.1 - * + * * @see http://sourceforge.net/tracker/index.php?func=detail&aid=3353537 &group_id=21935&atid=373747. * @throws Exception */ @@ -846,14 +851,14 @@ /** * Test method for <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=380729">bug 380729</a>: Allow reference * elements to have "other." types - * + * * @throws Exception */ @Test public final void test_Bug380729() throws Exception { - // Validation is normally not performed when loading content. However - // the previous implementation of the reference type was an - // enumeration so it would fail when attempting to set it and there + // Validation is normally not performed when loading content. However + // the previous implementation of the reference type was an + // enumeration so it would fail when attempting to set it and there // was no matching item. Hence this code should now pass as the OPF // contains previously invalid values. File rootFile = new File("testdata/OPF-Tests/Bug_380729/content.opf");
diff --git a/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/core/TestOPS2Validator.java b/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/core/TestOPS2Validator.java index f5fafb8..2ad9506 100644 --- a/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/core/TestOPS2Validator.java +++ b/org.eclipse.mylyn.docs.epub.tests/src/org/eclipse/mylyn/docs/epub/tests/core/TestOPS2Validator.java
@@ -18,7 +18,7 @@ import junit.framework.TestCase; -import org.eclipse.mylyn.internal.docs.epub.core.OPS2Validator; +import org.eclipse.mylyn.internal.docs.epub.core.OPSValidator; import org.junit.Test; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -57,7 +57,7 @@ for (String attr : illegalAttributes) { String in = "<html><body><div " + attr + "=\"test\">content</div></body></html>"; String expected = "<html><body><div>content</div></body></html>"; - String out = OPS2Validator.clean(new InputSource(new StringReader(in)), "test.html"); + String out = OPSValidator.clean(new InputSource(new StringReader(in)), "test.html"); assertEquals(expected, out); } } @@ -67,7 +67,7 @@ for (String element : illegalElements) { String in = "<html><body><" + element + "></" + element + "></body></html>"; String result = "<html><body></body></html>"; - String out = OPS2Validator.clean(new InputSource(new StringReader(in)), "test.html"); + String out = OPSValidator.clean(new InputSource(new StringReader(in)), "test.html"); assertEquals(result, out); } @@ -77,7 +77,7 @@ public void testLegalAttributes() throws ParserConfigurationException, SAXException, IOException { for (String attr : legalAttributes) { String in = "<html><body><div " + attr + "=\"test\"></div></body></html>"; - String out = OPS2Validator.clean(new InputSource(new StringReader(in)), "test.html"); + String out = OPSValidator.clean(new InputSource(new StringReader(in)), "test.html"); assertEquals(in, out); } } @@ -86,7 +86,7 @@ public void testLegalElements() throws ParserConfigurationException, SAXException, IOException { for (String element : legalElements) { String in = "<html><body><" + element + ">content</" + element + "></body></html>"; - String out = OPS2Validator.clean(new InputSource(new StringReader(in)), "test.html"); + String out = OPSValidator.clean(new InputSource(new StringReader(in)), "test.html"); assertEquals(in, out); } @@ -95,7 +95,7 @@ @Test public void testNormal() throws ParserConfigurationException, SAXException, IOException { String in = "<body><h1 id=\"h1-1\">test</h1></body>"; - String out = OPS2Validator.clean(new InputSource(new StringReader(in)), "test.html"); + String out = OPSValidator.clean(new InputSource(new StringReader(in)), "test.html"); assertEquals(in, out); } }
diff --git a/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/ConvertFromMarkupWizard.java b/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/ConvertFromMarkupWizard.java index bc945e0..ce6a689 100644 --- a/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/ConvertFromMarkupWizard.java +++ b/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/ConvertFromMarkupWizard.java
@@ -1,11 +1,11 @@ /******************************************************************************* - * Copyright (c) 2011, 2012 Torkild U. Resheim. - * + * Copyright (c) 2011-2014 Torkild U. Resheim. + * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html - * + * * Contributors: * Torkild U. Resheim - initial API and implementation *******************************************************************************/ @@ -23,7 +23,8 @@ import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.wizard.Wizard; import org.eclipse.mylyn.docs.epub.core.EPUB; -import org.eclipse.mylyn.docs.epub.core.OPSPublication; +import org.eclipse.mylyn.docs.epub.core.Publication; +import org.eclipse.mylyn.docs.epub.core.PublicationProxy; import org.eclipse.mylyn.docs.epub.core.ValidationMessage; import org.eclipse.mylyn.docs.epub.core.wikitext.MarkupToOPS; import org.eclipse.mylyn.wikitext.core.parser.markup.MarkupLanguage; @@ -31,9 +32,9 @@ public class ConvertFromMarkupWizard extends Wizard { - private EPUB2Bean bean; + private PublicationProxy bean; - OPSPublication oebps; + Publication oebps; private IFile epubFile; @@ -54,16 +55,15 @@ @Override public void addPages() { - oebps = OPSPublication.getVersion2Instance(); - File workingFolder = null; - bean = new EPUB2Bean(oebps, markupFile.getLocation().toFile(), epubFile.getLocation().toFile(), workingFolder); + oebps = Publication.getVersion2Instance(); + bean = new PublicationProxy(oebps, markupFile.getLocation().toFile()); page = new MainPage(bean); addPage(page); } /** * Delete the folder recursively. - * + * * @param folder * the folder to delete * @return <code>true</code> if the folder was deleted
diff --git a/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/EPUB2Bean.java b/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/EPUB2Bean.java deleted file mode 100644 index 87892d2..0000000 --- a/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/EPUB2Bean.java +++ /dev/null
@@ -1,303 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011,2012 Torkild U. Resheim. - * - * All rights reserved. This program and the accompanying materials are made - * available under the terms of the Eclipse License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Torkild U. Resheim - initial API and implementation - *******************************************************************************/ -package org.eclipse.mylyn.internal.docs.epub.ui; - -import java.io.File; -import java.util.Comparator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.TreeMap; -import java.util.UUID; - -import org.eclipse.emf.common.util.EList; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.util.FeatureMap; -import org.eclipse.emf.ecore.util.FeatureMapUtil.FeatureEList; -import org.eclipse.emf.ecore.xml.type.XMLTypePackage; -import org.eclipse.mylyn.docs.epub.core.OPSPublication; -import org.eclipse.mylyn.docs.epub.dc.Creator; -import org.eclipse.mylyn.docs.epub.dc.Date; -import org.eclipse.mylyn.docs.epub.dc.Identifier; -import org.eclipse.mylyn.docs.epub.dc.Language; -import org.eclipse.mylyn.docs.epub.dc.Rights; -import org.eclipse.mylyn.docs.epub.dc.Subject; -import org.eclipse.mylyn.docs.epub.dc.Title; -import org.eclipse.mylyn.docs.epub.opf.Item; - -/** - * Simplified representation of an EPUB revision 2.0 instance. - * - * @author Torkild U. Resheim - */ -class EPUB2Bean { - - private static final String STYLING_ID = "styling"; //$NON-NLS-1$ - - private static final String EMPTY_STRING = ""; //$NON-NLS-1$ - - private static final EStructuralFeature TEXT = XMLTypePackage.eINSTANCE.getXMLTypeDocumentRoot_Text(); - - private final OPSPublication epub; - - private final File markupFile; - - public File getMarkupFile() { - return markupFile; - } - - public EPUB2Bean() { - epub = OPSPublication.getVersion2Instance(); - markupFile = null; - } - - class ValueComparator implements Comparator<String> { - - Map<String, String> base; - - public ValueComparator(Map<String, String> base) { - this.base = base; - } - - public int compare(String a, String b) { - String key_a = a; - String key_b = b; - - return key_a.compareTo(key_b); - } - } - - TreeMap<String, String> sorted_locales; - - public EPUB2Bean(OPSPublication epub, File markupFile, File epubFile, File workingFolder) { - this.epub = epub; - this.markupFile = markupFile; - String id = epub.getOpfPackage().getUniqueIdentifier(); - if (id == null || id.trim().length() == 0) { - epub.getOpfPackage().setUniqueIdentifier(ID); - epub.addIdentifier(ID, "UUID", UUID.randomUUID().toString()); //$NON-NLS-1$ - } - // Clear everything except the metadata - epub.getOpfPackage().getManifest().getItems().clear(); - epub.getOpfPackage().getGuide().getGuideItems().clear(); - epub.getOpfPackage().getSpine().getSpineItems().clear(); - - sorted_locales = new TreeMap<String, String>(); - String[] iso639s = Locale.getISOLanguages(); - for (String iso639 : iso639s) { - Locale locale = new Locale(iso639); - sorted_locales.put(locale.getDisplayLanguage(), locale.getLanguage()); - } - } - - public String getCover() { - Item item = epub.getItemById(OPSPublication.COVER_IMAGE_ID); - if (item == null) { - return EMPTY_STRING; - } else { - return item.getFile(); - } - } - - @SuppressWarnings("rawtypes") - public String getCreator() { - EList<Creator> creators = epub.getOpfPackage().getMetadata().getCreators(); - if (creators.size() > 0) { - FeatureMap fm = creators.get(0).getMixed(); - Object o = fm.get(TEXT, false); - if (o instanceof FeatureEList) { - if (((FeatureEList) o).size() > 0) { - return ((FeatureEList) o).get(0).toString(); - } - } - } - return EMPTY_STRING; - } - - public OPSPublication getEPUB() { - return epub; - } - - @SuppressWarnings("rawtypes") - public String getIdentifier() { - EList<Identifier> identifiers = epub.getOpfPackage().getMetadata().getIdentifiers(); - if (identifiers.size() > 0) { - FeatureMap fm = identifiers.get(0).getMixed(); - Object o = fm.get(TEXT, false); - if (o instanceof FeatureEList) { - if (((FeatureEList) o).size() > 0) { - return ((FeatureEList) o).get(0).toString(); - } - } - } - return EMPTY_STRING; - } - - @SuppressWarnings("rawtypes") - public String getLanguage() { - EList<Language> languages = epub.getOpfPackage().getMetadata().getLanguages(); - if (languages.size() > 0) { - FeatureMap fm = languages.get(0).getMixed(); - Object o = fm.get(TEXT, false); - if (o instanceof FeatureEList) { - if (((FeatureEList) o).size() > 0) { - String iso639 = ((FeatureEList) o).get(0).toString(); - Locale l = new Locale(iso639); - return l.getDisplayLanguage(); - } - } - } - return EMPTY_STRING; - } - - public void setLanguage(String language) { - epub.getOpfPackage().getMetadata().getLanguages().clear(); - epub.addLanguage(null, sorted_locales.get(language)); - } - - @SuppressWarnings("rawtypes") - public String getRights() { - EList<Rights> rights = epub.getOpfPackage().getMetadata().getRights(); - if (rights.size() > 0) { - FeatureMap fm = rights.get(0).getMixed(); - Object o = fm.get(TEXT, false); - if (o instanceof FeatureEList) { - if (((FeatureEList) o).size() > 0) { - return ((FeatureEList) o).get(0).toString(); - } - } - } - return EMPTY_STRING; - } - - public String getStyleSheet() { - List<Item> stylesheets = epub.getItemsByMIMEType(OPSPublication.MIMETYPE_CSS); - if (stylesheets.isEmpty()) { - return EMPTY_STRING; - } else { - return stylesheets.get(0).getHref(); - } - } - - @SuppressWarnings("rawtypes") - public String getSubject() { - EList<Subject> subjects = epub.getOpfPackage().getMetadata().getSubjects(); - if (subjects.size() > 0) { - FeatureMap fm = subjects.get(0).getMixed(); - Object o = fm.get(TEXT, false); - if (o instanceof FeatureEList) { - if (((FeatureEList) o).size() > 0) { - return ((FeatureEList) o).get(0).toString(); - } - } - } - return EMPTY_STRING; - } - - @SuppressWarnings("rawtypes") - public String getTitle() { - EList<Title> titles = epub.getOpfPackage().getMetadata().getTitles(); - if (titles.size() > 0) { - FeatureMap fm = titles.get(0).getMixed(); - Object o = fm.get(TEXT, false); - if (o instanceof FeatureEList) { - if (((FeatureEList) o).size() > 0) { - return ((FeatureEList) o).get(0).toString(); - } - } - } - return EMPTY_STRING; - } - - public void setCover(String cover) { - if (cover.length() > 0) { - epub.setCover(new File(cover), Messages.EPUB2Bean_0); - } - } - - public void setCreator(String creator) { - epub.getOpfPackage().getMetadata().getCreators().clear(); - epub.addCreator(null, null, creator, null, null); - } - - private final static String ID = "epub-id"; //$NON-NLS-1$ - - public void setIdentifier(String identifier) { - String scheme = getScheme(); - epub.getOpfPackage().getMetadata().getIdentifiers().clear(); - epub.addIdentifier(ID, scheme, identifier); - epub.getOpfPackage().setUniqueIdentifier(ID); - } - - public void setScheme(String schemeName) { - String identifier = getIdentifier(); - epub.getOpfPackage().getMetadata().getIdentifiers().clear(); - epub.getOpfPackage().setUniqueIdentifier(ID); - epub.addIdentifier(ID, schemeName, identifier); - } - - public String getScheme() { - Identifier ident = epub.getOpfPackage().getMetadata().getIdentifiers().get(0); - return ident.getScheme(); - } - - public void setRights(String rights) { - epub.getOpfPackage().getMetadata().getRights().clear(); - epub.addRights(null, null, rights); - } - - public void setStyleSheet(String css) { - if (css.length() > 0) { - epub.getOpfPackage().getManifest().getItems().remove(epub.getItemsByMIMEType(OPSPublication.MIMETYPE_CSS)); - epub.addItem(STYLING_ID, null, new File(css), null, null, false, false, true); - } - } - - public void setSubject(String subject) { - epub.getOpfPackage().getMetadata().getSubjects().clear(); - epub.addSubject(null, null, subject); - } - - public void setTitle(String title) { - epub.getOpfPackage().getMetadata().getTitles().clear(); - epub.addTitle(null, null, title); - } - - public void setPublicationDate(String date) { - epub.getOpfPackage().getMetadata().getDates().clear(); - epub.addDate(null, date, "publication"); //$NON-NLS-1$ - } - - @SuppressWarnings("rawtypes") - public String getPublicationDate() { - EList<Date> dates = epub.getOpfPackage().getMetadata().getDates(); - if (dates.size() > 0) { - for (Date date : dates) { - if (date.getEvent().equals("publication")) { //$NON-NLS-1$ - FeatureMap fm = date.getMixed(); - Object o = fm.get(TEXT, false); - if (o instanceof FeatureEList) { - if (((FeatureEList) o).size() > 0) { - return ((FeatureEList) o).get(0).toString(); - } - } - } - } - } - return EMPTY_STRING; - - } - - public Map<String, String> getLocales() { - return sorted_locales; - } -}
diff --git a/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/MainPage.java b/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/MainPage.java index 15d5fae..e3c11fd 100644 --- a/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/MainPage.java +++ b/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/MainPage.java
@@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright (c) 2011, 2012 Torkild U. Resheim. - * + * Copyright (c) 2011-2014 Torkild U. Resheim. + * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: + * + * Contributors: * Torkild U. Resheim - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.docs.epub.ui; @@ -27,6 +27,7 @@ import org.eclipse.jface.fieldassist.FieldDecoration; import org.eclipse.jface.fieldassist.FieldDecorationRegistry; import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.mylyn.docs.epub.core.PublicationProxy; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; @@ -63,7 +64,7 @@ /** * @wbp.nonvisual location=681,21 */ - private EPUB2Bean bean = new EPUB2Bean(); + private PublicationProxy bean = new PublicationProxy(); private Combo schemeText; @@ -75,7 +76,7 @@ /** * Create the wizard. - * + * * @wbp.parser.constructor */ public MainPage() { @@ -85,14 +86,14 @@ setTitle(Messages.MainPage_1); } - public MainPage(EPUB2Bean bean) { + public MainPage(PublicationProxy bean) { this(); this.bean = bean; } /** * Create contents of the wizard. - * + * * @param parent */ public void createControl(Composite parent) { @@ -338,7 +339,7 @@ UpdateValueStrategy coverStrategy = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE); coverStrategy.setBeforeSetValidator(new FileValidator( "The cover image must be a valid image file of type PNG, SVG or JPEG.", coverText, new String[] { //$NON-NLS-1$ - ".png", ".svg", ".jpeg", ".jpg" })); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + ".png", ".svg", ".jpeg", ".jpg" })); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ bindingContext.bindValue(coverObserveTextObserveWidget, beanCoverObserveValue, coverStrategy, null); // IObservableValue styleSheetTextObserveTextObserveWidget = SWTObservables.observeText(styleSheetText, SWT.Modify);
diff --git a/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/Messages.java b/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/Messages.java index c39361b..755f5fc 100644 --- a/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/Messages.java +++ b/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/Messages.java
@@ -1,11 +1,11 @@ /******************************************************************************* - * Copyright (c) 2011, 2012 Torkild U. Resheim. - * + * Copyright (c) 2011-2014 Torkild U. Resheim. + * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html - * + * * Contributors: Torkild U. Resheim - initial API and implementation *******************************************************************************/ @@ -29,8 +29,6 @@ public static String ConvertFromMarkupWizard_4; - public static String EPUB2Bean_0; - public static String MainPage_0; public static String MainPage_1;
diff --git a/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/messages.properties b/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/messages.properties index 75fcec0..0a0aa8a 100644 --- a/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/messages.properties +++ b/org.eclipse.mylyn.docs.epub.ui/src/org/eclipse/mylyn/internal/docs/epub/ui/messages.properties
@@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2011, 2012 Torkild U. Resheim and others. +# Copyright (c) 2011-2014 Torkild U. Resheim and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at @@ -13,7 +13,6 @@ ConvertFromMarkupWizard_2=Generate EPUB. ConvertFromMarkupWizard_3=Could not convert to EPUB. ConvertFromMarkupWizard_4=An exception was thrown -EPUB2Bean_0=Cover page MainPage_0=Define properties for the resulting EPUB file. MainPage_1=EPUB Properties MainPage_10=Language: