/**
* Copyright (c) 2007 Really Strategies, Inc.
*/
package org.dita2indesign.indesign.inx.model;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import org.apache.log4j.Logger;
import org.dita2indesign.indesign.inx.model.Link.LinkType;
import org.dita2indesign.indesign.inx.visitors.InDesignDocumentVisitor;
import org.dita2indesign.util.DataUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
/**
* Represents a complete InDesign document.
*/
public class InDesignDocument extends InDesignObject {
/**
*
*/
public static final double SPREAD_TO_PAGE_PADDING = 144.0;
/**
*
*/
public static final double SPREAD_TO_SPREAD_GAP = 36.0;
/**
*
*/
public static final String CFLO_TAGNAME = "cflo";
/**
*
*/
public static final String DOCP_TAGNAME = "docp";
/**
*
*/
public static final String MSPR_TAGNAME = "mspr";
private static Logger logger = Logger.getLogger(InDesignDocument.class);
/**
*
*/
public static final String SPRD_TAGNAME = "sprd";
private URL dataSourceUrl;
protected List<Story> stories = new ArrayList<Story>();
private Map<String, InDesignObject> objectsById = new HashMap<String, InDesignObject>();
private Map<String, MasterSpread> masterSpreads = new HashMap<String, MasterSpread>();
private List<Spread> spreads = new ArrayList<Spread>();
private DocumentPreferences docPrefs;
private Document dataSource;
private Map<InDesignDocument, Map<String, InDesignObject>> clonedObjectMaps =
new HashMap<InDesignDocument, Map<String, InDesignObject>>();
private List<Link> links = new ArrayList<Link>();
private Map<String, ParagraphStyle> pstylesByName = new HashMap<String, ParagraphStyle>();
private Map<String, CharacterStyle> cstylesByName = new HashMap<String, CharacterStyle>();
// private Map<String, InDesignObject> ostylesByName = new HashMap<String, InDesignObject>();
// private Map<String, InDesignObject> tstylesByName = new HashMap<String, InDesignObject>();
/**
*
*/
public static final String TAG_KEY_LABEL = "Label";
/**
*
*/
public static final String PROP_PNAM = "pnam";
/**
*
*/
public static final String PROP_SELF = "Self";
/**
*
*/
public static final String PROP_NTXF = "ntxf";
public static final String PROP_NMBS = "nmbs";
public static final String PROP_NPFX = "npfx";
public static final String PROP_PAGC = "PagC";
public static final String PROP_IGEO = "IGeo";
public static final String PROP_PGSD = "PgSd";
public static final String PROP_PBND = "pbnd";
public static final String PROP_PTAG = "ptag";
public static final String PROP_PBIN = "pbin";
public static final String CLNK_TAGNAME = "clnk";
public static final String PAGE_TAGNAME = "page";
public static final String CREC_TAGNAME = "crec";
public static final String TXTF_TAGNAME = "txtf";
public static final String TXSR_TAGNAME = "txsr";
public static final String PCNT_TAGNAME = "pcnt";
public static final String IMAG_TAGNAME = "imag";
public static final String PROP_LNKI = "LnkI";
public static final String PROP_STRP = "strp";
public static final String PROP_LTXF = "ltxf";
public static final String PROP_FTXF = "ftxf";
public static final String PROP_PTXF = "ptxf";
public static final String PROP_OVRL = "ovrl";
public static final String PROP_PMAS = "pmas";
private static final Map<String, Class<? extends InDesignObject>> tagToObjectClassMap = new HashMap<String, Class<? extends InDesignObject>>();
private static final Map<String, Class<? extends InDesignComponent>> tagToComponentClassMap = new HashMap<String, Class<? extends InDesignComponent>>();
public static final String PROP_PRST = "prst";
public static final String PROP_CRST = "crst";
public static final String PSTY_TAGNAME = "psty";
public static final String CSTY_TAGNAME = "csty";
static {
// Tags to Objects:
tagToObjectClassMap.put(CLNK_TAGNAME, Link.class);
tagToObjectClassMap.put(CFLO_TAGNAME, Story.class);
tagToObjectClassMap.put(PAGE_TAGNAME, Page.class);
tagToObjectClassMap.put(CREC_TAGNAME, Rectangle.class);
tagToObjectClassMap.put(TXTF_TAGNAME, TextFrame.class);
tagToObjectClassMap.put(CSTY_TAGNAME, CharacterStyle.class);
tagToObjectClassMap.put(PSTY_TAGNAME, ParagraphStyle.class);
// Tags to Components:
tagToComponentClassMap.put(TXSR_TAGNAME, TextStyleRange.class);
tagToComponentClassMap.put(PCNT_TAGNAME, TextContents.class);
}
/**
* @param inxData
*/
public InDesignDocument() {
super();
}
/**
* Construct a new document by cloning an existing document,
* copying only the master spreads. Note that this is different
* from a generic loadObject(InDesignObject) operation (as for InDesignObject), which
* is a full copy.
* @param inddDoc
* @throws Exception
*/
public InDesignDocument(InDesignDocument inddDoc) throws Exception {
// Clone the document and do not remove spreads
this(inddDoc, false);
}
/**
* Construct a new document by cloning an existing document,
* copying only the master spreads. Note that this is different
* from a generic loadObject(InDesignObject) operation (as for InDesignObject), which
* is a full copy.
* @param inddDoc
* @throws Exception
*/
public InDesignDocument(InDesignDocument inddDoc, boolean removeSpreads) throws Exception {
Document cloneSourceDoc = inddDoc.getDataSource();
if (cloneSourceDoc == null)
throw new Exception("Got null data source from input InDesign document.");
this.dataSource = (Document)cloneSourceDoc.cloneNode(true);
logger.debug("InDesignDocument(inddDoc): setting dataSource to " + dataSource);
Element clonedDataSource = this.dataSource.getDocumentElement();
if (removeSpreads) {
// Now delete the components that hold actual content, namely spreads and stories:
for (Element spread : DataUtil.getElementChildren(clonedDataSource, null, SPRD_TAGNAME)) {
clonedDataSource.removeChild(spread);
}
// FIXME: For stories, we only want to delete stories that are associated with frames on
// normal spreads, not master spreads. So for now just leaving them in.
// for (Element story : DataUtil.getElementChildren(clonedDataSource, null, CFLO_TAGNAME)) {
// clonedDataSource.removeChild(story);
// }
}
this.load(clonedDataSource);
this.spreads.clear(); // Just to make sure
// Now make sure there is a spread as a document must have at least one spread.
Spread spread = this.newSpread(this.getMasterSpreads().get(0).getName());
spread.addPage(1);
}
/**
* @param templateUrl
* @throws Exception
*/
public InDesignDocument(URL templateUrl) throws Exception {
this.load(templateUrl);
}
/**
* @param inxSource
* @throws Exception
*/
public InDesignDocument(InputSource inxSource) throws Exception {
this.load(inxSource);
}
public void addChild(InDesignComponent comp) throws Exception {
super.addChild(comp);
if (comp instanceof Story) {
this.stories.add((Story)comp);
// FIXME: Need to do some more refactoring in order to be able to do
// this processing at this point.
// } else if (comp instanceof MasterSpread) {
// MasterSpread masterSpread = (MasterSpread)comp;
// this.masterSpreads.put(masterSpread.getPName(), masterSpread);
// } else if (comp instanceof Spread) {
// this.spreads.add((Spread)comp);
} else if (comp instanceof ParagraphStyle) {
this.pstylesByName.put(comp.getPName(), (ParagraphStyle)comp);
} else if (comp instanceof CharacterStyle) {
this.cstylesByName.put(comp.getPName(), (CharacterStyle)comp);
} else if (comp instanceof DocumentPreferences) {
this.docPrefs = (DocumentPreferences)comp;
}
}
/**
* @return
*/
public Document getDataSource() {
return this.dataSource;
}
/**
* @return
*/
public Iterator<Story> getStoryIterator() {
return stories.iterator();
}
/**
* @throws Exception
*
*/
public void load(URL dataSource) throws Exception {
this.dataSourceUrl = dataSource;
logger.debug("load(): + Loading data source=\"" + dataSource.toExternalForm());
InputSource source = new InputSource(dataSource.openStream());
load(source);
}
/**
* Gets the data source URL for the document, if any.
* @return The URL of the data source from which the document was constructed. May be null.
*/
public URL getDataSourceUrl() {
return this.dataSourceUrl;
}
public void load(InputSource source) throws Exception {
DocumentBuilder builder = DataUtil.constructNonValidatingDocumentBuilder();
Document dom = builder.parse(source);
Element docElem = dom.getDocumentElement();
if (docElem == null) {
throw new IOException("No root element for input document " + source.getSystemId());
}
load(docElem);
logger.debug("load(): Setting dataSource to " + dom);
this.dataSource = dom;
}
public void load(Element docElem) throws Exception {
this.dataSource = docElem.getOwnerDocument();
Iterator<Element> elemIter = DataUtil.getElementChildrenIterator(docElem);
while (elemIter.hasNext()) {
Element child = elemIter.next();
logger.debug("load(): Element: " + child.getNodeName());
if (child.getNodeName().equals(CFLO_TAGNAME)) {
logger.debug("load(): Creating new Story...");
this.newStory(child);
} else if (child.getNodeName().equals(DOCP_TAGNAME)) {
logger.debug("load(): Getting document preferences...");
this.newDocumentPreferences(child);
} else if (child.getNodeName().equals(MSPR_TAGNAME)) {
logger.debug("load(): Creating new Master Spread...");
this.newMasterSpread(child);
} else if (child.getNodeName().equals(SPRD_TAGNAME)) {
logger.debug("load(): Creating new Spread...");
this.newSpread(child);
} else {
logger.debug(" + Creating new unhandled child " + child.getNodeName() + "...");
InDesignComponent comp = this.newInDesignComponent(child);
this.addChild(comp);
}
}
}
/**
* @param child
* @throws Exception
*/
private void newSpread(Element child) throws Exception {
newSpread(Spread.class, child);
}
/**
* @param child
* @throws Exception
*/
private DocumentPreferences newDocumentPreferences(Element child) throws Exception {
DocumentPreferences prefs = (DocumentPreferences) newComponent(DocumentPreferences.class, child);
this.addChild(prefs);
// this.docPrefs = prefs;
return prefs;
}
/**
* @param child
* @return
* @throws Exception
*/
private MasterSpread newMasterSpread(Element child) throws Exception {
MasterSpread obj = (MasterSpread) newSpread(MasterSpread.class, child);
this.masterSpreads.put(obj.getPName(), obj);
return obj;
}
/**
* @param child
* @return
* @throws Exception
*/
private Spread newSpread(Class<? extends Spread> clazz, Element child) throws Exception {
Spread obj = (Spread) newObject(clazz, child);
this.addChild(obj);
// The spreadIndex parameter is zero-index
// for spread in list of spreads.
obj.setSpreadIndex(spreads.size());
if (!(obj instanceof MasterSpread)) {
this.spreads.add(obj);
}
obj.postLoad();
return obj;
}
/**
* Constructs a new component, which may be an InDesignComponent or an InDesignObject.
* @param child
* @return
* @throws Exception
*/
public InDesignComponent newInDesignComponent(Element child) throws Exception {
logger.debug("newInDesignObject(): Creating new object or component from <" + child.getNodeName() + ">...");
if (child.hasAttribute(PROP_SELF)) {
Class<? extends InDesignObject> objectClass = tagToObjectClassMap.get(child.getNodeName());
if (objectClass == null)
objectClass = DefaultInDesignObject.class;
InDesignObject newObject = (InDesignObject)newObject(objectClass, child);
logger.debug("newInDesignObject(): New object has ID [" + newObject.getId() + "]");
return newObject;
} else {
Class<? extends InDesignComponent> objectClass = tagToComponentClassMap.get(child.getNodeName());
if (objectClass == null)
objectClass = DefaultInDesignComponent.class;
return newComponent(objectClass, child);
}
}
/**
* @param child
* @return
* @throws Exception
*/
public Story newStory(Element child) throws Exception {
Story story = (Story) newObject(Story.class, child);
this.addChild(story);
return story;
}
/**
* @param string
* @return
*/
public InDesignObject getObject(String id) {
return this.objectsById.get(id);
}
/**
* @return
*/
public Set<String> getPageMasterNames() {
return this.masterSpreads.keySet();
}
/**
* @param pageMasterName
* @return
*/
public MasterSpread getMasterSpread(String pageMasterName) {
if (this.masterSpreads.containsKey(pageMasterName))
return this.masterSpreads.get(pageMasterName);
return null;
}
/**
* Register a new object with the document so it can maintain
* a master index of objects by ID.
* @param object
*/
public void registerObject(InDesignObject object) {
String id = object.getId();
if (id == null || this.objectsById.containsKey(id)) {
id = assignObjectId();
object.setId(id);
}
this.objectsById.put(object.getId(), object);
object.setDocument(this);
}
/**
* @return
*/
public List<Spread> getSpreads() {
return this.spreads;
}
/**
* @return
*/
public DocumentPreferences getDocumentPreferences() {
return this.docPrefs;
}
/**
* @param i
* @return
*/
public Spread getSpread(int i) {
if (i >= this.spreads.size())
return null;
return this.spreads.get(i);
}
/**
*
* @return
* @throws Exception
*/
public double getSpreadOffset() throws Exception {
logger.debug("getSpreadOffset(): Starting, this.spreads.size=" + this.spreads.size());
if (this.spreads.size() < 2) {
return 0.0;
}
// Spread geometry is page-height + 144pt (72pt gap above and below page).
// There is a 36pt gap between spreads.
double pageHeight = this.getDocumentPreferences().getPageHeight();
double spreadHeight = pageHeight + SPREAD_TO_PAGE_PADDING;
int spreadCount = this.spreads.size() - 1; // Offset for first spread is always 0
double offset = (spreadHeight * spreadCount) + (SPREAD_TO_SPREAD_GAP * spreadCount);
logger.debug("getSpreadOffset(): Returning " + offset);
return offset;
}
/**
* @return
*/
public List<MasterSpread> getMasterSpreads() {
return new ArrayList<MasterSpread>(this.masterSpreads.values());
}
/**
* @param masterSpreadName
* @return
* @throws Exception
*/
public Spread newSpread(String masterSpreadName) throws Exception {
Spread newSpread = new Spread();
assignIdAndRegister(newSpread);
newSpread.setParent(this);
newSpread.setSpreadIndex(this.spreads.size());
this.spreads.add(newSpread);
MasterSpread masterSpread = this.getMasterSpread(masterSpreadName);
if (masterSpread == null) {
logger.info("Master spread \"" + masterSpreadName + "\" not found. Master spreads: ");
for (String key : this.masterSpreads.keySet()) {
logger.info(" \"" + key + "\"");
}
throw new Exception("Failed to find master spread \"" + masterSpreadName + "\"");
}
newSpread.setTransformationMatrix(this.spreads.size());
// Note that masters apply to pages, not spreads.
for (Page page : newSpread.getPages()) {
page.setAppliedMaster(masterSpread);
}
this.addChild(newSpread);
return newSpread;
}
/**
* Create a new spread that reflects the
* @param masterSpreadName
* @return
* @throws Exception
*/
public Spread addSpread(String masterSpreadName) throws Exception {
Spread spread = newSpread(masterSpreadName);
// Get the corresponding master spread, clone its data source,
// and use that to load the spread.
spread.setTransformationMatrix(this.spreads.size());
return spread;
}
/**
* @param newObject
*/
protected void assignIdAndRegister(InDesignObject newObject) {
newObject.setId(this.assignObjectId());
registerObject(newObject);
}
/**
* @param dataSource
* @return
* @throws Exception
*/
public Page newPage(Element dataSource) throws Exception {
Page page = (Page)newObject(Page.class, dataSource);
page.postLoad();
return page;
}
/**
* @return
* @throws Exception
*/
public Page newPage() throws Exception {
return (Page)newObject(Page.class, null);
}
/**
* @return
*/
String assignObjectId() {
return "obj" + (this.objectsById.size() + 100);
}
/**
* @return
* @throws Exception
*/
public boolean isFacingPages() throws Exception {
return this.docPrefs.isFacingPages();
}
/**
* @return New rectangle
* @throws Exception
*/
public Rectangle newRectangle() throws Exception {
Rectangle rect = new Rectangle();
assignIdAndRegister(rect);
return rect;
}
/**
* @return New rectangle
* @throws Exception
*/
public ParagraphStyle newParagraphStyle() throws Exception {
ParagraphStyle obj = new ParagraphStyle();
assignIdAndRegister(obj);
return obj;
}
/**
* Unconditionally clone an InDesign Object.
* @param sourceObj
* @return The clone of the object.
* @throws Exception
*/
public InDesignComponent clone(InDesignComponent sourceComp) throws Exception {
if (sourceComp instanceof InDesignObject) {
return clone((InDesignObject)sourceComp);
}
logger.debug("Cloning component " + sourceComp.getClass().getSimpleName());
InDesignComponent clone = sourceComp.getClass().newInstance();
clone.setDocument(this);
clone.loadComponent(sourceComp);
return clone;
}
/**
* Unconditionally clone an InDesign Object.
* @param sourceObj
* @return The clone of the object.
* @throws Exception
*/
public InDesignComponent clone(InDesignObject sourceObj) throws Exception {
logger.debug("Cloning object " + sourceObj.getClass().getSimpleName() + " [" + sourceObj.getId() + "]...");
InDesignObject clone = sourceObj.getClass().newInstance();
assignIdAndRegister(clone);
// Now remember that we've cloned this source object so we can not
// clone it again if we don't want to:
Map<String, InDesignObject> cloneMap = getCloneMapForDoc(sourceObj.getDocument());
cloneMap.put(sourceObj.getId(), clone);
clone.loadObject(sourceObj, clone.getId());
return clone;
}
/**
* @param document
* @return
*/
private Map<String, InDesignObject> getCloneMapForDoc(
InDesignDocument document) {
if (!this.clonedObjectMaps.containsKey(document))
this.clonedObjectMaps.put(document, new HashMap<String, InDesignObject>());
return this.clonedObjectMaps.get(document);
}
/**
* @return
*/
public String reportObjectsById() {
StringBuilder report = new StringBuilder("Objects By ID:\n");
for (Map.Entry<String, InDesignObject> entry : this.objectsById.entrySet()) {
report.append("[").append(entry.getKey()).append("] ").append(entry.getValue().getClass().getSimpleName()).append("\n");
}
return report.toString();
}
/**
* @param dataSource
* @return
* @throws Exception
*/
public Rectangle newRectangle(Element dataSource) throws Exception {
return (Rectangle)newObject(Rectangle.class, dataSource);
}
/**
* @param dataSource
* @return
* @throws Exception
*/
public TextFrame newFrame(Element dataSource) throws Exception {
return (TextFrame)newObject(TextFrame.class, dataSource);
}
/**
* @param dataSource
* @return
*/
public Group newGroup(Element dataSource) throws Exception {
return (Group)newObject(Group.class, dataSource);
}
/**
* @param class1
* @param dataSource
* @return
* @throws Exception
* @throws InstantiationException
*/
private InDesignComponent newObject(Class<? extends InDesignObject> clazz, Element dataSource) throws Exception {
logger.debug("newObject(): Creating new " + clazz.getSimpleName() + "...");
InDesignObject obj = (InDesignObject) clazz.newInstance();
obj.setDocument(this);
if (dataSource != null) {
logger.debug("newObject(): From element " + dataSource.getNodeName() + "...");
obj.loadObject(dataSource);
String selfValue = dataSource.getAttribute(PROP_SELF);
if (selfValue != null && !"".equals(selfValue.trim())) {
String id = InxHelper.decodeRawValueToSingleString(selfValue);
obj.setId(id);
this.registerObject(obj);
} else {
assignIdAndRegister(obj);
}
} else {
assignIdAndRegister(obj);
}
logger.debug("newObject(): New object has ID [" + obj.getId() + "]");
return obj;
}
/**
* @param objectClass
* @param child
* @return
* @throws Exception
*/
private InDesignComponent newComponent(
Class<? extends InDesignComponent> clazz, Element child) throws InstantiationException, Exception {
InDesignComponent comp = (InDesignComponent) clazz.newInstance();
comp.setDocument(this);
comp.loadComponent(child);
return comp;
}
/**
* @param visitor
* @throws Exception
*/
public void accept(InDesignDocumentVisitor visitor) throws Exception {
visitor.visit(this);
}
/**
* @return
*/
public String reportChildObjects() {
StringBuilder report = new StringBuilder("Child Objects::\n");
for (InDesignComponent comp : this.getChildren()) {
String dsName = comp.getInxTagName();
if (comp instanceof InDesignObject) {
InDesignObject obj = (InDesignObject)comp;
report.append("[").append(obj.getId())
.append("] ");
}
report
.append(comp.getClass().getSimpleName())
.append(", <")
.append(dsName)
.append(">")
.append("\n");
}
return report.toString();
}
/**
* Clones an object only if it hasn't been already cloned. Returns
* the clone.
* @param sourceObj
* @return The clone of the source object.
* @throws Exception
*/
public InDesignComponent cloneIfNew(InDesignObject sourceObj) throws Exception {
return cloneIfNew(sourceObj, (InDesignComponent)null);
}
/**
* Clones an object only if it hasn't been already cloned. Returns
* the clone.
* @param sourceObj
* @return The clone of the source object.
* @throws Exception
*/
public InDesignComponent cloneIfNew(InDesignObject sourceObj, InDesignComponent targetParent) throws Exception {
Map<String, InDesignObject> cloneMap = getCloneMapForDoc(sourceObj.getDocument());
if (cloneMap.containsKey(sourceObj.getId()))
return cloneMap.get(sourceObj.getId());
InDesignComponent clone = this.clone(sourceObj);
if (targetParent != null)
targetParent.addChild(clone);
return clone;
}
/**
* @return
*/
public List<Link> getLinks() {
return this.links;
}
/**
* Adds or updates a Link in the link map.
* @param link
* @return the link that was added
*/
public InDesignComponent addLink(Link link) {
this.links.add(link);
return link;
}
/**
* Construct a new link.
* @return
*/
public Link newLink() {
Link link = new Link();
assignIdAndRegister(link);
this.links.add(link);
return link;
}
/**
* Create a new text frame with the specified link placed
* as its content. This results in a new story, which holds
* the link and to which the text frame is associated.
* @param link Link to place in the frame.
* @return
* @throws Exception
*/
public TextFrame newTextFrame(Link link) throws Exception {
TextFrame frame = new TextFrame();
assignIdAndRegister(frame);
// Create the story that is the parent of the frame and contains
// the link:
this.newStory(frame, link);
return frame;
}
/**
* Create a new text frame. This results in a new story, which
* the text frame is associated.
* @return
* @throws Exception
*/
public TextFrame newTextFrame() throws Exception {
TextFrame frame = new TextFrame();
assignIdAndRegister(frame);
this.newStory(frame);
return frame;
}
/**
* Construct a new Story that is associated with the specified
* text frame and which contains the specified link as its
* placed content.
* @param frame Text frame to which the story is associated.
* @param link Link containing the content for the story.
* @return
* @throws Exception
*/
private Story newStory(TextFrame frame, Link link) throws Exception {
Story story = new Story();
assignIdAndRegister(story);
story.addChild(link);
this.addChild(story);
frame.setParentStory(story);
return story;
}
/**
* Construct a new Story that is associated with the specified
* text frame,
* @param frame Text frame to which the story is associated.
* @return
* @throws Exception
*/
private Story newStory(TextFrame frame) throws Exception {
Story story = new Story();
assignIdAndRegister(story);
this.addChild(story);
frame.setParentStory(story);
return story;
}
/**
* @param link
* @return
* @throws Exception
*/
public Rectangle newRectangle(Link link) throws Exception {
if (link.getLinkType() == LinkType.INCOPY) {
throw new Exception("Cannot link to an InCopy article from a graphic rectangle");
}
Rectangle rect = newRectangle();
return rect;
}
/**
* @return
* @throws Exception
*/
public Image newImage() throws Exception {
Image image = new Image();
assignIdAndRegister(image);
return image;
}
/* (non-Javadoc)
* @see org.dita2indesign.indesign.inx.model.InDesignComponent#updatePropertyMap()
*/
@Override
public void updatePropertyMap() throws Exception {
InxObjectList storyList = new InxObjectList(this.stories);
this.setProperty("stls", storyList);
}
/**
* Import a story from one document (e.g., an InCopy article) into this document,
* updating style references as necessary.
* @param incxStory The story to be imported.
* @return The imported story object.
* @throws Exception
*/
public Story importStory(Story incxStory) throws Exception {
Map<String, ParagraphStyle> paraStyleMap = new HashMap<String, ParagraphStyle>();
Story newStory = new Story();
this.assignIdAndRegister(newStory);
Iterator<TextStyleRange> iter = incxStory.getTextStyleRangeIterator();
while (iter.hasNext()) {
TextStyleRange incomingTxsr = iter.next();
TextStyleRange txsr = (TextStyleRange)this.clone(incomingTxsr);
InDesignObject incomingStyle = incomingTxsr.getParagraphStyle();
if (incomingStyle == null) {
throw new Exception("Failed to get object for referenced paragraph style ID [" + txsr.getObjectReferenceProperty(PROP_PRST) + "]");
}
String styleName = incomingStyle.getPName();
ParagraphStyle targetPStyle = this.getParagraphStyle(styleName);
if (targetPStyle == null) {
targetPStyle = (ParagraphStyle)this.clone(incomingStyle);
this.addParagraphStyle(targetPStyle);
}
txsr.setObjectReferenceProperty(PROP_PRST, targetPStyle);
incomingStyle = incomingTxsr.getCharacterStyle();
if (incomingStyle == null) {
logger.warn("Failed to get object for referenced character style ID [" + txsr.getObjectReferenceProperty(PROP_PRST) + "]");
} else {
styleName = incomingStyle.getPName();
CharacterStyle targetCStyle = this.getCharacterStyle(styleName);
if (targetCStyle == null) {
targetCStyle = (CharacterStyle)this.clone(incomingStyle);
this.addCharacterStyle(targetCStyle);
}
txsr.setObjectReferenceProperty(PROP_CRST, targetCStyle);
}
newStory.addChild(txsr);
}
this.addChild(newStory);
return newStory;
}
/**
* Add a paragraph style to the document.
* @param styleObject
* @throws Exception
*/
public ParagraphStyle addParagraphStyle(ParagraphStyle styleObject) throws Exception {
this.pstylesByName.put(styleObject.getPName(), styleObject);
return styleObject;
}
/**
* Add a character style to the document.
* @param styleObject
* @throws Exception
*/
public CharacterStyle addCharacterStyle(CharacterStyle styleObject) throws Exception {
this.cstylesByName.put(styleObject.getPName(), styleObject);
return styleObject;
}
/**
* @param styleName
* @return
*/
public ParagraphStyle getParagraphStyle(String styleName) throws Exception {
ParagraphStyle style = null;
if (this.pstylesByName.containsKey(styleName)) {
style = this.pstylesByName.get(styleName);
}
return style;
}
/**
* @param styleName
* @return
*/
public CharacterStyle getCharacterStyle(String styleName) throws Exception {
CharacterStyle style = null;
if (this.cstylesByName.containsKey(styleName)) {
style = this.cstylesByName.get(styleName);
}
return style;
}
public static void updateThreadsForOverriddenFrames(
Page masterPage,
Map<Rectangle, Rectangle> masterToOverride)
throws Exception,
InDesignDocumentException {
for (Rectangle rect : masterToOverride.keySet()) {
if (!(rect instanceof TextFrame)) continue;
TextFrame master = (TextFrame)rect;
TextFrame clone = (TextFrame)masterToOverride.get(master);
TextFrame prev = clone.getPreviousInThread();
if (prev != null) {
TextFrame prevClone = (TextFrame)masterToOverride.get(prev);
clone.setPreviousInThread(prevClone);
}
TextFrame next = clone.getNextInThread();
if (next != null) {
TextFrame nextClone = (TextFrame)masterToOverride.get(next);
clone.setNextInThread(nextClone);
}
}
}
}