/* ******************************************************************************
* Copyright (c) 2006-2016 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
/**
*
*/
package org.xmind.core.util;
import static org.xmind.core.internal.dom.DOMConstants.ATTR_OBJECT_ID;
import static org.xmind.core.internal.dom.DOMConstants.ATTR_RESOURCE_PATH;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.xmind.core.CoreException;
import org.xmind.core.IBoundary;
import org.xmind.core.ICloneData;
import org.xmind.core.IComment;
import org.xmind.core.ICommentManager;
import org.xmind.core.IControlPoint;
import org.xmind.core.IFileEntry;
import org.xmind.core.IHtmlNotesContent;
import org.xmind.core.IHyperlinkSpan;
import org.xmind.core.IImage;
import org.xmind.core.IImageSpan;
import org.xmind.core.IManifest;
import org.xmind.core.IMeta;
import org.xmind.core.INotes;
import org.xmind.core.INotesContent;
import org.xmind.core.IParagraph;
import org.xmind.core.IPlainNotesContent;
import org.xmind.core.IRelationship;
import org.xmind.core.IResourceRef;
import org.xmind.core.ISettingEntry;
import org.xmind.core.ISheet;
import org.xmind.core.ISpan;
import org.xmind.core.ISpanList;
import org.xmind.core.ISummary;
import org.xmind.core.ITextSpan;
import org.xmind.core.ITopic;
import org.xmind.core.ITopicExtension;
import org.xmind.core.ITopicExtensionElement;
import org.xmind.core.IWorkbook;
import org.xmind.core.IWorkbookExtension;
import org.xmind.core.IWorkbookExtensionElement;
import org.xmind.core.IWorkbookExtensionManager;
import org.xmind.core.internal.CloneData;
import org.xmind.core.internal.zip.ArchiveConstants;
import org.xmind.core.marker.IMarker;
import org.xmind.core.marker.IMarkerGroup;
import org.xmind.core.marker.IMarkerRef;
import org.xmind.core.marker.IMarkerResource;
import org.xmind.core.marker.IMarkerSheet;
import org.xmind.core.style.IStyle;
import org.xmind.core.style.IStyleSheet;
/**
* @author Frank Shaka
* @since 3.6.50
*/
public class CloneHandler {
private ICloneData mapper;
private IWorkbook sourceWorkbook;
private IWorkbook targetWorkbook;
private IManifest sourceManifest;
private IManifest targetManifest;
private IStyleSheet sourceStyleSheet;
private IStyleSheet targetStyleSheet;
private IMarkerSheet sourceMarkerSheet;
private IMarkerSheet targetMarkerSheet;
/**
*
*/
public CloneHandler() {
this(null);
}
/**
*
*/
public CloneHandler(ICloneData mapper) {
this.mapper = mapper == null
? new CloneData(Collections.emptyList(), null) : mapper;
this.sourceWorkbook = null;
this.targetWorkbook = null;
this.sourceManifest = null;
this.targetManifest = null;
this.sourceStyleSheet = null;
this.targetStyleSheet = null;
this.sourceMarkerSheet = null;
this.targetMarkerSheet = null;
}
public CloneHandler withWorkbooks(IWorkbook sourceWorkbook,
IWorkbook targetWorkbook) {
if (sourceWorkbook == null)
throw new IllegalArgumentException();
if (targetWorkbook == null)
throw new IllegalArgumentException();
this.sourceWorkbook = sourceWorkbook;
this.targetWorkbook = targetWorkbook;
this.sourceManifest = sourceWorkbook.getManifest();
this.targetManifest = targetWorkbook.getManifest();
this.sourceStyleSheet = sourceWorkbook.getStyleSheet();
this.targetStyleSheet = targetWorkbook.getStyleSheet();
this.sourceMarkerSheet = sourceWorkbook.getMarkerSheet();
this.targetMarkerSheet = targetWorkbook.getMarkerSheet();
return this;
}
public CloneHandler withManifests(IManifest sourceManifest,
IManifest targetManifest) {
if (sourceManifest == null)
throw new IllegalArgumentException();
if (targetManifest == null)
throw new IllegalArgumentException();
this.sourceManifest = sourceManifest;
this.targetManifest = targetManifest;
return this;
}
public CloneHandler withStyleSheets(IStyleSheet sourceStyleSheet,
IStyleSheet targetStyleSheet) {
if (sourceStyleSheet == null)
throw new IllegalArgumentException();
if (targetStyleSheet == null)
throw new IllegalArgumentException();
this.sourceStyleSheet = sourceStyleSheet;
this.targetStyleSheet = targetStyleSheet;
this.sourceManifest = sourceStyleSheet.getAdapter(IManifest.class);
this.targetManifest = targetStyleSheet.getAdapter(IManifest.class);
return this;
}
public CloneHandler withMarkerSheets(IMarkerSheet sourceMarkerSheet,
IMarkerSheet targetMarkerSheet) {
if (sourceMarkerSheet == null)
throw new IllegalArgumentException();
if (targetMarkerSheet == null)
throw new IllegalArgumentException();
this.sourceMarkerSheet = sourceMarkerSheet;
this.targetMarkerSheet = targetMarkerSheet;
this.sourceManifest = sourceMarkerSheet.getAdapter(IManifest.class);
this.targetManifest = targetMarkerSheet.getAdapter(IManifest.class);
return this;
}
/**
* @return the mapper
*/
public ICloneData getMapper() {
return mapper;
}
public void copyWorkbookContents() throws IOException {
if (sourceWorkbook == null)
throw new AssertionError("sourceWorkbook is null"); //$NON-NLS-1$
if (targetWorkbook == null)
throw new AssertionError("targetWorkbook is null"); //$NON-NLS-1$
List<ISheet> oldSheets = new ArrayList<ISheet>(
targetWorkbook.getSheets());
for (ISheet sourceSheet : sourceWorkbook.getSheets()) {
targetWorkbook.addSheet(cloneSheet(sourceSheet));
}
if (targetWorkbook.getSheets().isEmpty()) {
targetWorkbook.addSheet(targetWorkbook.createSheet());
}
for (ISheet oldSheet : oldSheets) {
targetWorkbook.removeSheet(oldSheet);
}
IMeta sourceMeta = sourceWorkbook.getMeta();
IMeta targetMeta = targetWorkbook.getMeta();
for (String keyPath : sourceMeta.getKeyPaths()) {
targetMeta.setValue(keyPath, sourceMeta.getValue(keyPath));
}
List<ISheet> sheets = targetWorkbook.getSheets();
ArrayList<ITopic> targetAllTopics = new ArrayList<ITopic>();
for (ISheet sheet : sheets) {
targetAllTopics.add(sheet.getRootTopic());
targetAllTopics.addAll(sheet.getRootTopic().getAllChildren());
}
IWorkbookExtensionManager sourceExtensionManager = sourceWorkbook
.getAdapter(IWorkbookExtensionManager.class);
IWorkbookExtensionManager targetExtensionManager = targetWorkbook
.getAdapter(IWorkbookExtensionManager.class);
if (sourceExtensionManager != null && targetExtensionManager != null) {
for (IWorkbookExtension sourceExtension : sourceExtensionManager
.getExtensions()) {
IWorkbookExtension targetExtension = targetExtensionManager
.createExtension(sourceExtension.getProviderName());
copyWorkbookExtension(sourceExtension, targetExtension);
}
}
fixInternalHyperlinkFor(targetAllTopics);
}
/**
* Clones a source object into the target container (e.g. workbook or style
* sheet, etc.). Currently only these kinds of objects can be cloned:
* <ul>
* <li>{@link org.xmind.core.ISheet} (require sourceWorkbook/targetWorkbook)
* </li>
* <li>{@link org.xmind.core.ITopic} (require sourceWorkbook/targetWorkobok)
* </li>
* <li>{@link org.xmind.core.IBoundary} (require
* sourceWorkbook/targetWorkbook)</li>
* <li>{@link org.xmind.core.ISummary} (require
* sourceWorkbook/targetWorkbook)</li>
* <li>{@link org.xmind.core.IRelationship} (require
* sourceWorkbook/targetWorkbook)</li>
* <li>{@link org.xmind.core.IImage} (require sourceWorkbook/targetWorkbook)
* </li>
* <li>{@link org.xmind.core.style.IStyle} (require
* sourceStyleSheet/targetStyleSheet)</li>
* </ul>
*
* @param source
* the source object to clone
* @return a cloned object, or <code>null</code> if the object is
* unrecognized
* @throws IOException
* if any I/O error occurred during the clone process (e.g. when
* importing attachments along with its referrence topic)
* @throws AssertionError
* if required target contexts are missing
*/
public Object cloneObject(Object source) throws IOException {
Object target = mapper.get(source);
if (target != null)
return target;
if (source instanceof ISheet) {
if (sourceWorkbook == null)
throw new AssertionError("sourceWorkbook is null"); //$NON-NLS-1$
if (targetWorkbook == null)
throw new AssertionError("targetWorkbook is null"); //$NON-NLS-1$
if (sourceManifest == null)
throw new AssertionError("sourceManifest is null"); //$NON-NLS-1$
if (targetManifest == null)
throw new AssertionError("targetManifest is null"); //$NON-NLS-1$
return cloneSheet((ISheet) source);
} else if (source instanceof ITopic) {
if (sourceWorkbook == null)
throw new AssertionError("sourceWorkbook is null"); //$NON-NLS-1$
if (targetWorkbook == null)
throw new AssertionError("targetWorkbook is null"); //$NON-NLS-1$
if (sourceManifest == null)
throw new AssertionError("sourceManifest is null"); //$NON-NLS-1$
if (targetManifest == null)
throw new AssertionError("targetManifest is null"); //$NON-NLS-1$
ITopic sourceTopic = (ITopic) source;
ITopic targetTopic = targetWorkbook.createTopic();
copyTopicContents(sourceTopic, targetTopic);
return targetTopic;
} else if (source instanceof IBoundary) {
if (sourceWorkbook == null)
throw new AssertionError("sourceWorkbook is null"); //$NON-NLS-1$
if (targetWorkbook == null)
throw new AssertionError("targetWorkbook is null"); //$NON-NLS-1$
if (sourceManifest == null)
throw new AssertionError("sourceManifest is null"); //$NON-NLS-1$
if (targetManifest == null)
throw new AssertionError("targetManifest is null"); //$NON-NLS-1$
IBoundary sourceBoundary = (IBoundary) source;
IBoundary targetBoundary = targetWorkbook.createBoundary();
copyBoundaryContents(sourceBoundary, targetBoundary);
return targetBoundary;
} else if (source instanceof ISummary) {
if (sourceWorkbook == null)
throw new AssertionError("sourceWorkbook is null"); //$NON-NLS-1$
if (targetWorkbook == null)
throw new AssertionError("targetWorkbook is null"); //$NON-NLS-1$
if (sourceManifest == null)
throw new AssertionError("sourceManifest is null"); //$NON-NLS-1$
if (targetManifest == null)
throw new AssertionError("targetManifest is null"); //$NON-NLS-1$
ISummary sourceSummary = (ISummary) source;
ISummary targetSummary = targetWorkbook.createSummary();
copySummaryContents(sourceSummary, targetSummary);
return targetSummary;
} else if (source instanceof IRelationship) {
if (sourceWorkbook == null)
throw new AssertionError("sourceWorkbook is null"); //$NON-NLS-1$
if (targetWorkbook == null)
throw new AssertionError("targetWorkbook is null"); //$NON-NLS-1$
if (sourceManifest == null)
throw new AssertionError("sourceManifest is null"); //$NON-NLS-1$
if (targetManifest == null)
throw new AssertionError("targetManifest is null"); //$NON-NLS-1$
IRelationship sourceRel = (IRelationship) source;
IRelationship targetRel = targetWorkbook.createRelationship();
copyRelationshipContents(sourceRel, targetRel);
return targetRel;
} else if (source instanceof IStyle) {
if (sourceStyleSheet == null)
throw new AssertionError("sourceStyleSheet is null"); //$NON-NLS-1$
if (targetStyleSheet == null)
throw new AssertionError("targetStyleSheet is null"); //$NON-NLS-1$
if (sourceManifest == null)
throw new AssertionError("sourceManifest is null"); //$NON-NLS-1$
if (targetManifest == null)
throw new AssertionError("targetManifest is null"); //$NON-NLS-1$
return findOrCloneStyle((IStyle) source);
} else if (source instanceof IImage) {
if (sourceWorkbook == null)
throw new AssertionError("sourceWorkbook is null"); //$NON-NLS-1$
if (targetWorkbook == null)
throw new AssertionError("targetWorkbook is null"); //$NON-NLS-1$
if (sourceManifest == null)
throw new AssertionError("sourceManifest is null"); //$NON-NLS-1$
if (targetManifest == null)
throw new AssertionError("targetManifest is null"); //$NON-NLS-1$
IImage sourceImage = (IImage) source;
ITopic sourceTopic = sourceImage.getParent();
ITopic targetTopic = targetWorkbook.createTopic();
copyTopicContents(sourceTopic, targetTopic);
IImage targetImage = targetTopic.getImage();
mapper.put(sourceImage, targetImage);
return targetImage;
} else if (source instanceof IMarker) {
if (sourceMarkerSheet == null)
throw new AssertionError("sourceMarkerSheet is null"); //$NON-NLS-1$
if (targetMarkerSheet == null)
throw new AssertionError("targetMarkerSheet is null"); //$NON-NLS-1$
/// marker sheets require not manifests, but resource providers,
/// so sourceManifest and targetManifest are not checked here
IMarker marker = findOrCloneMarker((IMarker) source);
mapper.put(source, marker);
return marker;
} else if (source instanceof IMarkerRef) {
if (sourceWorkbook == null)
throw new AssertionError("sourceWorkbook is null"); //$NON-NLS-1$
if (targetWorkbook == null)
throw new AssertionError("targetWorkbook is null"); //$NON-NLS-1$
IMarkerRef sourceMarkerRef = (IMarkerRef) source;
IMarkerRef targetMarkerRef = cloneMarkerRef(sourceMarkerRef);
mapper.put(sourceMarkerRef, targetMarkerRef);
return targetMarkerRef;
}
return null;
}
/**
* @param sourceMarkerRef
* @return
* @throws IOException
*/
private IMarkerRef cloneMarkerRef(IMarkerRef sourceMarkerRef)
throws IOException {
IMarkerRef targetMarkerRef;
IMarker sourceMarker = sourceMarkerRef.getMarker();
if (sourceMarker == null) {
targetMarkerRef = sourceMarkerRef;
} else {
IMarker targetMarker = findOrCloneMarker(sourceMarker);
if (targetMarker == null) {
targetMarkerRef = null;
} else {
mapper.put(sourceMarker, targetMarker);
mapper.putString(ICloneData.MARKERSHEET_COMPONENTS,
sourceMarker.getId(), targetMarker.getId());
ITopic tempTopic = targetWorkbook.createTopic();
tempTopic.addMarker(targetMarker.getId());
targetMarkerRef = tempTopic.getMarkerRefs().iterator().next();
}
}
return targetMarkerRef;
}
private IMarker findOrCloneMarker(IMarker sourceMarker) throws IOException {
if (sourceMarker == null)
return null;
IMarker targetMarker = (IMarker) mapper.get(sourceMarker);
if (targetMarker != null)
return targetMarker;
String markerId = sourceMarker.getId();
targetMarker = targetMarkerSheet.findMarker(markerId);
if (targetMarker != null) {
mapper.put(sourceMarker, targetMarker);
return targetMarker;
}
/// markers do not change across permanent marker sheets
if (sourceMarker.getOwnedSheet().isPermanent())
return sourceMarker;
IMarkerGroup sourceGroup = sourceMarker.getParent();
IMarkerGroup targetGroup = findOrCloneMarkerGroup(sourceGroup);
String sourceResourcePath = sourceMarker.getResourcePath();
String targetResourcePath = null;
/// copy marker resource content
IMarkerResource sourceResource = sourceMarker.getResource();
if (sourceResource != null) {
InputStream input = sourceResource.openInputStream();
try {
targetResourcePath = targetMarkerSheet
.allocateMarkerResource(input, sourceResourcePath);
} finally {
input.close();
}
}
/// create target marker with the same marker id
targetMarker = targetMarkerSheet.createMarkerById(markerId,
targetResourcePath);
targetMarker.setName(sourceMarker.getName());
if (targetGroup != null)
targetGroup.addMarker(targetMarker);
mapper.put(sourceMarker, targetMarker);
return targetMarker;
}
private IMarkerGroup findOrCloneMarkerGroup(
IMarkerGroup sourceMarkerGroup) {
if (sourceMarkerGroup == null)
return null;
IMarkerGroup targetMarkerGroup = (IMarkerGroup) mapper
.get(sourceMarkerGroup);
if (targetMarkerGroup != null)
return targetMarkerGroup;
String groupId = sourceMarkerGroup.getId();
targetMarkerGroup = targetMarkerSheet.findMarkerGroup(groupId);
if (targetMarkerGroup == null
|| targetMarkerGroup.getOwnedSheet() != targetMarkerSheet) {
/// make sure the new group is owned by the target marker sheet
targetMarkerGroup = targetMarkerSheet
.createMarkerGroupById(groupId);
targetMarkerGroup.setSingleton(sourceMarkerGroup.isSingleton());
targetMarkerGroup.setName(sourceMarkerGroup.getName());
}
if (targetMarkerGroup.getParent() == null) {
targetMarkerSheet.addMarkerGroup(targetMarkerGroup);
}
return targetMarkerGroup;
}
private ISheet cloneSheet(ISheet sourceSheet) throws IOException {
ISheet targetSheet = targetWorkbook.createSheet();
copySheetContents(sourceSheet, targetSheet);
ArrayList<ITopic> targetAllTopics = new ArrayList<ITopic>();
targetAllTopics.add(targetSheet.getRootTopic());
targetAllTopics.addAll(targetSheet.getRootTopic().getAllChildren());
fixInternalHyperlinkFor(targetAllTopics);
return targetSheet;
}
/**
* @param sourceSheet
* @param targetSheet
* @throws IOException
* @throws CoreException
*/
private void copySheetContents(ISheet sourceSheet, ISheet targetSheet)
throws IOException {
mapper.put(sourceSheet, targetSheet);
mapper.putString(ICloneData.WORKBOOK_COMPONENTS, sourceSheet.getId(),
targetSheet.getId());
targetSheet.setTitleText(sourceSheet.getTitleText());
targetSheet.setStyleId(convertStyleId(sourceSheet.getStyleId()));
targetSheet.setThemeId(convertStyleId(sourceSheet.getThemeId()));
ITopic sourceRootTopic = sourceSheet.getRootTopic();
if (sourceRootTopic != null) {
ITopic targetRootTopic = targetSheet.getRootTopic();
copyTopicContents(sourceRootTopic, targetRootTopic);
}
for (IRelationship sourceRel : sourceSheet.getRelationships()) {
IRelationship targetRel = targetWorkbook.createRelationship();
copyRelationshipContents(sourceRel, targetRel);
targetSheet.addRelationship(targetRel);
}
targetSheet.getLegend().setVisible(sourceSheet.getLegend().isVisible());
targetSheet.getLegend()
.setPosition(sourceSheet.getLegend().getPosition());
for (String markerId : sourceSheet.getLegend().getMarkerIds()) {
targetSheet.getLegend().setMarkerDescription(markerId,
sourceSheet.getLegend().getMarkerDescription(markerId));
}
for (String settingPath : sourceSheet.getSettings().getPaths()) {
for (ISettingEntry sourceSettingEntry : sourceSheet.getSettings()
.getEntries(settingPath)) {
ISettingEntry targetSettingEntry = targetSheet.getSettings()
.createEntry(settingPath);
for (String key : sourceSettingEntry.getAttributeKeys()) {
targetSettingEntry.setAttribute(key,
sourceSettingEntry.getAttribute(key));
}
targetSheet.getSettings().addEntry(targetSettingEntry);
}
}
copyComments(sourceSheet.getId(), targetSheet.getId());
}
private void copyTopicContents(ITopic sourceTopic, ITopic targetTopic)
throws IOException {
mapper.put(sourceTopic, targetTopic);
mapper.putString(ICloneData.WORKBOOK_COMPONENTS, sourceTopic.getId(),
targetTopic.getId());
targetTopic.setTitleText(
sourceTopic.hasTitle() ? sourceTopic.getTitleText() : null);
targetTopic.setTitleWidth(sourceTopic.getTitleWidth());
targetTopic.setFolded(sourceTopic.isFolded());
targetTopic.setStructureClass(sourceTopic.getStructureClass());
targetTopic.setPosition(sourceTopic.getPosition());
targetTopic.setHyperlink(convertHyperlink(sourceTopic.getHyperlink()));
for (String label : sourceTopic.getLabels()) {
targetTopic.addLabel(label);
}
for (IMarkerRef markerRef : sourceTopic.getMarkerRefs()) {
IMarkerRef mr = (IMarkerRef) cloneObject(markerRef);
if (mr != null) {
targetTopic.addMarker(mr.getMarkerId());
}
}
targetTopic.setStyleId(convertStyleId(sourceTopic.getStyleId()));
targetTopic.getImage().setSource(
convertHyperlink(sourceTopic.getImage().getSource()));
targetTopic.getImage().setWidth(sourceTopic.getImage().getWidth());
targetTopic.getImage().setHeight(sourceTopic.getImage().getHeight());
targetTopic.getImage()
.setAlignment(sourceTopic.getImage().getAlignment());
for (String type : sourceTopic.getChildrenTypes()) {
for (ITopic sourceChild : sourceTopic.getChildren(type)) {
ITopic targetChild = targetTopic.getOwnedWorkbook()
.createTopic();
copyTopicContents(sourceChild, targetChild);
targetTopic.add(targetChild, type);
}
}
for (IBoundary sourceBoundary : sourceTopic.getBoundaries()) {
IBoundary targetBoundary = targetTopic.getOwnedWorkbook()
.createBoundary();
copyBoundaryContents(sourceBoundary, targetBoundary);
targetTopic.addBoundary(targetBoundary);
}
for (ISummary sourceSummary : sourceTopic.getSummaries()) {
ISummary targetSummary = targetTopic.getOwnedWorkbook()
.createSummary();
copySummaryContents(sourceSummary, targetSummary);
targetTopic.addSummary(targetSummary);
}
for (ITopicExtension sourceExt : sourceTopic.getExtensions()) {
ITopicExtension targetExt = targetTopic
.createExtension(sourceExt.getProviderName());
copyTopicExtension(sourceExt, targetExt);
}
targetTopic.getNumbering()
.setFormat(sourceTopic.getNumbering().getNumberFormat());
targetTopic.getNumbering()
.setPrefix(sourceTopic.getNumbering().getPrefix());
targetTopic.getNumbering()
.setSuffix(sourceTopic.getNumbering().getSuffix());
targetTopic.getNumbering()
.setSeparator(sourceTopic.getNumbering().getSeparator());
targetTopic.getNumbering().setPrependsParentNumbers(
sourceTopic.getNumbering().prependsParentNumbers());
targetTopic.getNumbering()
.setDepth(sourceTopic.getNumbering().getDepth());
INotesContent sourcePlainContent = sourceTopic.getNotes()
.getContent(INotes.PLAIN);
if (sourcePlainContent != null
&& sourcePlainContent instanceof IPlainNotesContent) {
INotesContent targetPlainContent = targetWorkbook
.createNotesContent(INotes.PLAIN);
if (targetPlainContent instanceof IPlainNotesContent) {
((IPlainNotesContent) targetPlainContent).setTextContent(
((IPlainNotesContent) sourcePlainContent)
.getTextContent());
targetTopic.getNotes().setContent(INotes.PLAIN,
targetPlainContent);
}
}
INotesContent sourceHtmlContent = sourceTopic.getNotes()
.getContent(INotes.HTML);
if (sourceHtmlContent != null
&& sourceHtmlContent instanceof IHtmlNotesContent) {
INotesContent targetHtmlContent = targetWorkbook
.createNotesContent(INotes.HTML);
if (targetHtmlContent instanceof IHtmlNotesContent) {
copyHtmlNotesContent((IHtmlNotesContent) sourceHtmlContent,
(IHtmlNotesContent) targetHtmlContent);
targetTopic.getNotes().setContent(INotes.HTML,
targetHtmlContent);
}
}
List<ITopic> targetAllTopics = new ArrayList<ITopic>();
targetAllTopics.add(targetTopic);
targetAllTopics.addAll(targetTopic.getAllChildren());
fixInternalHyperlinkFor(targetAllTopics);
copyComments(sourceTopic.getId(), targetTopic.getId());
}
/**
* @param source
* @param target
*/
private void copyComments(String sourceObjectId, String targetObjectId) {
Set<IComment> sourceComments = sourceWorkbook.getCommentManager()
.getComments(sourceObjectId);
if (!sourceComments.isEmpty()) {
ICommentManager targetCommentManager = targetWorkbook
.getCommentManager();
for (IComment sourceComment : sourceComments) {
IComment targetComment = targetCommentManager.createComment(
sourceComment.getAuthor(), sourceComment.getTime(),
targetObjectId);
targetComment.setContent(sourceComment.getContent());
targetCommentManager.addComment(targetComment);
}
}
}
private void fixInternalHyperlinkFor(List<ITopic> allTargetTopics) {
for (ITopic targetTopic : allTargetTopics) {
String hyperlink = targetTopic.getHyperlink();
if (HyperlinkUtils.isInternalURL(hyperlink)) {
Object sourceElement = HyperlinkUtils.findElement(hyperlink,
sourceWorkbook);
Object result = mapper.get(sourceElement);
if (result != null) {
targetTopic
.setHyperlink(HyperlinkUtils.toInternalURL(result));
}
}
}
}
private void copyHtmlNotesContent(IHtmlNotesContent sourceNotesContent,
IHtmlNotesContent targetNotesContent) throws IOException {
for (IParagraph sourceParagraph : sourceNotesContent.getParagraphs()) {
IParagraph targetParagraph = targetNotesContent.createParagraph();
targetParagraph
.setStyleId(convertStyleId(sourceParagraph.getStyleId()));
targetNotesContent.addParagraph(targetParagraph);
copySpanList(sourceParagraph, targetParagraph, targetNotesContent);
}
}
private void copySpanList(ISpanList sourceSpanList,
ISpanList targetSpanList, IHtmlNotesContent spanFactory)
throws IOException {
for (ISpan sourceSpan : sourceSpanList.getSpans()) {
ISpan targetSpan;
if (sourceSpan instanceof ITextSpan) {
targetSpan = spanFactory.createTextSpan(
((ITextSpan) sourceSpan).getTextContent());
} else if (sourceSpan instanceof IImageSpan) {
String source = ((IImageSpan) sourceSpan).getSource();
String newImageSource = convertHyperlink(source);
targetSpan = spanFactory.createImageSpan(newImageSource);
} else if (sourceSpan instanceof IHyperlinkSpan) {
targetSpan = spanFactory.createHyperlinkSpan(
((IHyperlinkSpan) sourceSpan).getHref());
copySpanList((IHyperlinkSpan) sourceSpan,
(IHyperlinkSpan) targetSpan, spanFactory);
} else {
continue;
}
targetSpan.setStyleId(convertStyleId(sourceSpan.getStyleId()));
targetSpanList.addSpan(targetSpan);
}
}
private void copyBoundaryContents(IBoundary sourceBoundary,
IBoundary targetBoundary) throws IOException {
mapper.put(sourceBoundary, targetBoundary);
mapper.putString(ICloneData.WORKBOOK_COMPONENTS, sourceBoundary.getId(),
targetBoundary.getId());
targetBoundary.setTitleText(sourceBoundary.getTitleText());
targetBoundary.setStyleId(convertStyleId(sourceBoundary.getStyleId()));
if (sourceBoundary.isMasterBoundary()) {
targetBoundary.setMasterBoundary(sourceBoundary.isMasterBoundary());
} else {
targetBoundary.setStartIndex(sourceBoundary.getStartIndex());
targetBoundary.setEndIndex(sourceBoundary.getEndIndex());
}
}
private void copySummaryContents(ISummary sourceSummary,
ISummary targetSummary) throws IOException {
mapper.put(sourceSummary, targetSummary);
mapper.putString(ICloneData.WORKBOOK_COMPONENTS, sourceSummary.getId(),
targetSummary.getId());
targetSummary.setStyleId(convertStyleId(sourceSummary.getStyleId()));
targetSummary.setTopicId(mapper.getString(
ICloneData.WORKBOOK_COMPONENTS, sourceSummary.getTopicId()));
targetSummary.setStartIndex(sourceSummary.getStartIndex());
targetSummary.setEndIndex(sourceSummary.getEndIndex());
}
private void copyTopicExtension(ITopicExtension sourceExt,
ITopicExtension targetExt) throws IOException {
for (IResourceRef ref : sourceExt.getResourceRefs()) {
if (IResourceRef.FILE_ENTRY.equals(ref.getType())) {
String targetEntryPath = convertEntryPath(ref.getResourceId());
if (targetEntryPath != null) {
targetExt.addResourceRef(
targetExt.getOwnedWorkbook().createResourceRef(
IResourceRef.FILE_ENTRY, targetEntryPath));
}
}
}
copyTopicExtensionElement(sourceExt.getContent(),
targetExt.getContent());
}
private void copyTopicExtensionElement(ITopicExtensionElement sourceEle,
ITopicExtensionElement targetEle) {
for (String key : sourceEle.getAttributeKeys()) {
targetEle.setAttribute(key, sourceEle.getAttribute(key));
}
targetEle.setTextContent(sourceEle.getTextContent());
for (ITopicExtensionElement sourceChild : sourceEle.getChildren()) {
ITopicExtensionElement targetChild = targetEle
.createChild(sourceChild.getName());
copyTopicExtensionElement(sourceChild, targetChild);
}
}
private void copyRelationshipContents(IRelationship sourceRel,
IRelationship targetRel) throws IOException {
mapper.put(sourceRel, targetRel);
mapper.putString(ICloneData.WORKBOOK_COMPONENTS, sourceRel.getId(),
targetRel.getId());
targetRel.setTitleText(sourceRel.getTitleText());
String end1Id = mapper.getString(ICloneData.WORKBOOK_COMPONENTS,
sourceRel.getEnd1Id());
targetRel.setEnd1Id(end1Id == null ? sourceRel.getEnd1Id() : end1Id);
String end2Id = mapper.getString(ICloneData.WORKBOOK_COMPONENTS,
sourceRel.getEnd2Id());
targetRel.setEnd2Id(end2Id == null ? sourceRel.getEnd2Id() : end2Id);
targetRel.setStyleId(convertStyleId(sourceRel.getStyleId()));
copyControlPointContents(sourceRel, targetRel, 0);
copyControlPointContents(sourceRel, targetRel, 1);
}
private void copyControlPointContents(IRelationship sourceRel,
IRelationship targetRel, int index) {
IControlPoint sourceControlPoint = sourceRel.getControlPoint(index);
if (!sourceControlPoint.hasPosition()
&& !sourceControlPoint.hasPolarAngle()
&& !sourceControlPoint.hasPolarAmount())
return;
IControlPoint targetControlPoint = targetRel.getControlPoint(index);
if (sourceControlPoint.hasPosition()) {
Point position = sourceControlPoint.getPosition();
targetControlPoint.setPosition(new Point(position.x, position.y));
}
if (sourceControlPoint.hasPolarAngle()) {
targetControlPoint
.setPolarAngle(sourceControlPoint.getPolarAngle());
}
if (sourceControlPoint.hasPolarAmount()) {
targetControlPoint
.setPolarAmount(sourceControlPoint.getPolarAmount());
}
}
private void copyWorkbookExtension(IWorkbookExtension sourceExt,
IWorkbookExtension targetExt) throws IOException {
for (IResourceRef ref : sourceExt.getResourceRefs()) {
if (IResourceRef.FILE_ENTRY.equals(ref.getType())) {
String targetEntryPath = convertEntryPath(ref.getResourceId());
if (targetEntryPath != null) {
targetExt.addResourceRef(
targetExt.getOwnedWorkbook().createResourceRef(
IResourceRef.FILE_ENTRY, targetEntryPath));
}
}
}
copyWorkbookExtensionElement(sourceExt.getContent(),
targetExt.getContent());
}
private void copyWorkbookExtensionElement(
IWorkbookExtensionElement sourceEle,
IWorkbookExtensionElement targetEle) throws IOException {
targetEle.setTextContent(sourceEle.getTextContent());
for (String key : sourceEle.getAttributeKeys()) {
String value = sourceEle.getAttribute(key);
if (ATTR_RESOURCE_PATH.equals(key)) {
value = convertEntryPath(value);
} else if (ATTR_OBJECT_ID.equals(key)) {
value = mapper.getString(ICloneData.WORKBOOK_COMPONENTS, value);
}
targetEle.setAttribute(key, value);
}
for (IWorkbookExtensionElement sourceE : sourceEle.getChildren()) {
IWorkbookExtensionElement targetE = targetEle
.createChild(sourceE.getName());
copyWorkbookExtensionElement(sourceE, targetE);
}
}
private String convertHyperlink(String sourceHyperlink) throws IOException {
if (sourceHyperlink == null)
return null;
if (HyperlinkUtils.isAttachmentURL(sourceHyperlink)) {
String sourceEntryPath = HyperlinkUtils
.toAttachmentPath(sourceHyperlink);
String targetEntryPath = convertEntryPath(sourceEntryPath);
return targetEntryPath == null ? null
: HyperlinkUtils.toAttachmentURL(targetEntryPath);
} else if (HyperlinkUtils.isInternalURL(sourceHyperlink)) {
///TODO handle 'xmind:xxxxx'
}
return sourceHyperlink;
}
/**
* @param sourceEntryPath
* @return
* @throws IOException
*/
private String convertEntryPath(String sourceEntryPath) throws IOException {
IFileEntry sourceEntry = sourceManifest.getFileEntry(sourceEntryPath);
if (sourceEntry == null || !sourceEntry.canRead())
// TODO log missing attachment?
return null;
String targetEntryPath;
if (sourceEntryPath.startsWith(ArchiveConstants.PATH_ATTACHMENTS)) {
// convert attachments to resources (using hash as file name)
targetEntryPath = mapper.getString(ICloneData.FILE_ENTRIES,
sourceEntryPath);
if (targetEntryPath == null) {
IFileEntry targetEntry;
InputStream sourceStream = sourceEntry.openInputStream();
try {
targetEntry = targetManifest.createAttachmentFromStream(
sourceStream, sourceEntryPath,
sourceEntry.getMediaType());
} finally {
sourceStream.close();
}
targetEntryPath = targetEntry.getPath();
mapper.putString(ICloneData.FILE_ENTRIES, sourceEntryPath,
targetEntryPath);
}
} else {
targetEntryPath = sourceEntryPath;
IFileEntry targetEntry = targetManifest
.getFileEntry(targetEntryPath);
if (targetEntry == null) {
targetEntry = targetManifest.createFileEntry(targetEntryPath,
sourceEntry.getMediaType());
InputStream sourceStream = sourceEntry.openInputStream();
try {
OutputStream targetStream = targetEntry.openOutputStream();
try {
FileUtils.transfer(sourceStream, targetStream, false);
} finally {
targetStream.close();
}
} finally {
sourceStream.close();
}
}
}
return targetEntryPath;
}
private IStyle findOrCloneStyle(IStyle sourceStyle) throws IOException {
if (sourceStyle == null)
return null;
String sourceStyleId = sourceStyle.getId();
String targetStyleId = mapper
.getString(ICloneData.STYLESHEET_COMPONENTS, sourceStyleId);
if (targetStyleId != null) {
return targetStyleSheet.findStyle(targetStyleId);
}
/// TODO: find similar style to reduce redundant styles
String groupName = sourceStyleSheet.findOwnedGroup(sourceStyle);
if (groupName == null)
return null;
IStyle targetStyle = targetStyleSheet
.createStyle(sourceStyle.getType());
targetStyle.setName(sourceStyle.getName());
Iterator<Property> properties = sourceStyle.properties();
while (properties.hasNext()) {
Property p = properties.next();
String value = p.value;
if (HyperlinkUtils.isAttachmentURL(value)) {
value = convertHyperlink(value);
}
targetStyle.setProperty(p.key, value);
}
Iterator<Property> defaultStyleIds = sourceStyle.defaultStyles();
while (defaultStyleIds.hasNext()) {
Property p = defaultStyleIds.next();
targetStyle.setDefaultStyleId(p.key, convertStyleId(p.value));
}
targetStyleSheet.addStyle(targetStyle, groupName);
mapper.put(sourceStyle, targetStyle);
mapper.putString(ICloneData.STYLESHEET_COMPONENTS, sourceStyleId,
targetStyle.getId());
return targetStyle;
}
private String convertStyleId(String sourceStyleId) throws IOException {
if (sourceStyleId == null)
return null;
String targetStyleId = mapper
.getString(ICloneData.STYLESHEET_COMPONENTS, sourceStyleId);
if (targetStyleId != null)
return targetStyleId;
IStyle sourceStyle = sourceStyleSheet.findStyle(sourceStyleId);
if (sourceStyle == null)
return null;
IStyle targetStyle = findOrCloneStyle(sourceStyle);
return targetStyle == null ? null : targetStyle.getId();
}
}