/* ******************************************************************************
* 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.internal.dom;
import static org.xmind.core.internal.dom.DOMConstants.ATTR_AUTHOR;
import static org.xmind.core.internal.dom.DOMConstants.ATTR_OBJECT_ID;
import static org.xmind.core.internal.dom.DOMConstants.ATTR_TIME;
import static org.xmind.core.internal.dom.DOMConstants.TAG_COMMENT;
import static org.xmind.core.internal.dom.DOMConstants.TAG_COMMENTS;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xmind.core.Core;
import org.xmind.core.IAdaptable;
import org.xmind.core.IComment;
import org.xmind.core.ICommentManager;
import org.xmind.core.IWorkbook;
import org.xmind.core.IWorkbookComponent;
import org.xmind.core.event.ICoreEventSource;
import org.xmind.core.util.DOMUtils;
/**
* @author Frank Shaka
*/
public class CommentManagerImpl
implements ICommentManager, INodeAdaptableFactory {
private final WorkbookImpl ownedWorkbook;
private final Document implementation;
private final NodeAdaptableRegistry registry;
private final Set<CommentImpl> pendingComments;
/**
*
*/
public CommentManagerImpl(WorkbookImpl ownerWorkbook,
Document implementation) {
this.ownedWorkbook = ownerWorkbook;
this.implementation = implementation;
this.registry = new NodeAdaptableRegistry(implementation, this);
this.pendingComments = new HashSet<CommentImpl>();
init();
}
private void init() {
Element m = DOMUtils.ensureChildElement(implementation, TAG_COMMENTS);
NS.setNS(NS.Comments, m);
InternalDOMUtils.addVersion(implementation);
}
private Element getCommentsElement() {
return implementation.getDocumentElement();
}
/*
* (non-Javadoc)
* @see org.xmind.core.IAdaptable#getAdapter(java.lang.Class)
*/
public <T> T getAdapter(Class<T> adapter) {
if (IWorkbook.class.equals(adapter))
return adapter.cast(getOwnedWorkbook());
if (Node.class.equals(adapter) || Document.class.equals(adapter))
return adapter.cast(implementation);
return null;
}
/*
* (non-Javadoc)
* @see org.xmind.core.IWorkbookComponent#getOwnedWorkbook()
*/
public IWorkbook getOwnedWorkbook() {
return ownedWorkbook;
}
/*
* (non-Javadoc)
* @see org.xmind.core.IWorkbookComponent#isOrphan()
*/
public boolean isOrphan() {
return false;
}
protected void objectAddNotify(String objectId, Object obj) {
Element p = getCommentsElement();
Iterator<CommentImpl> it = pendingComments.iterator();
while (it.hasNext()) {
CommentImpl c = it.next();
if (objectId.equals(c.getObjectId())) {
it.remove();
Element ele = c.getImplementation();
if (ele.getParentNode() != p) {
p.appendChild(ele);
if (obj instanceof ICoreEventSource) {
ownedWorkbook.getCoreEventSupport()
.dispatchTargetChange((ICoreEventSource) obj,
Core.CommentAdd, c);
}
}
}
}
}
protected void objectRemoveNotify(String objectId, Object obj) {
Element p = getCommentsElement();
int i = 0;
while (i < p.getChildNodes().getLength()) {
Node n = p.getChildNodes().item(i);
if (n instanceof Element
&& TAG_COMMENT.equals(((Element) n).getTagName())) {
Element ele = (Element) n;
if (objectId
.equals(DOMUtils.getAttribute(ele, ATTR_OBJECT_ID))) {
p.removeChild(ele);
IAdaptable a = registry.getAdaptable(ele);
if (a instanceof CommentImpl) {
CommentImpl c = (CommentImpl) a;
pendingComments.add(c);
if (obj instanceof ICoreEventSource) {
ownedWorkbook.getCoreEventSupport()
.dispatchTargetChange(
(ICoreEventSource) obj,
Core.CommentRemove, c);
}
}
continue;
}
}
i++;
}
}
/*
* (non-Javadoc)
* @see org.xmind.core.ICommentManager#createComment(java.lang.String, long,
* java.lang.String)
*/
public IComment createComment(String author, long time, String objectId) {
if (author == null)
throw new IllegalArgumentException();
if (time <= 0)
throw new IllegalArgumentException();
if (objectId == null)
throw new IllegalArgumentException();
Element ele = implementation.createElement(TAG_COMMENT);
DOMUtils.setAttribute(ele, ATTR_AUTHOR, author);
DOMUtils.setAttribute(ele, ATTR_TIME, Long.toString(time));
DOMUtils.setAttribute(ele, ATTR_OBJECT_ID, objectId);
CommentImpl c = new CommentImpl(ownedWorkbook, this, ele);
registry.register(c, ele);
return c;
}
private static boolean isObjectOrphan(Object obj) {
return !(obj instanceof IWorkbookComponent)
|| ((IWorkbookComponent) obj).isOrphan();
}
/*
* (non-Javadoc)
* @see org.xmind.core.ICommentManager#addCommand(org.xmind.core.IComment)
*/
public void addComment(IComment comment) {
if (!(comment instanceof CommentImpl)
|| comment.getOwnedWorkbook() != getOwnedWorkbook())
throw new IllegalArgumentException();
CommentImpl c = (CommentImpl) comment;
Element ele = c.getImplementation();
Element p = getCommentsElement();
if (ele.getParentNode() == p)
return;
Object obj = ownedWorkbook.getElementById(c.getObjectId());
if (obj == null || isObjectOrphan(obj)) {
/// associated object not exist,
/// add comment to pending set
pendingComments.add(c);
return;
}
p.appendChild(ele);
if (obj instanceof ICoreEventSource) {
ownedWorkbook.getCoreEventSupport().dispatchTargetChange(
(ICoreEventSource) obj, Core.CommentAdd, c);
}
updateModificationInfo();
}
/*
* (non-Javadoc)
* @see
* org.xmind.core.ICommentManager#removeComment(org.xmind.core.IComment)
*/
public void removeComment(IComment comment) {
if (!(comment instanceof CommentImpl)
|| comment.getOwnedWorkbook() != getOwnedWorkbook())
throw new IllegalArgumentException();
CommentImpl c = (CommentImpl) comment;
Element ele = c.getImplementation();
Element p = getCommentsElement();
pendingComments.remove(c);
if (ele.getParentNode() != p)
return;
p.removeChild(ele);
Object obj = ownedWorkbook.getElementById(c.getObjectId());
if (obj instanceof ICoreEventSource) {
ownedWorkbook.getCoreEventSupport().dispatchTargetChange(
(ICoreEventSource) obj, Core.CommentRemove, c);
}
updateModificationInfo();
}
/*
* (non-Javadoc)
* @see org.xmind.core.ICommentManager#getComments(java.lang.String)
*/
public Set<IComment> getComments(String objectId) {
if (objectId == null)
throw new IllegalArgumentException();
Object o = getOwnedWorkbook().getElementById(objectId);
if (o == null || isObjectOrphan(o)) {
return Collections.emptySet();
}
Set<IComment> set = new HashSet<IComment>();
Iterator<Element> it = DOMUtils
.childElementIterByTag(getCommentsElement(), TAG_COMMENT);
while (it.hasNext()) {
Element ele = it.next();
if (objectId.equals(DOMUtils.getAttribute(ele, ATTR_OBJECT_ID))) {
IAdaptable a = registry.getAdaptable(ele);
if (a instanceof CommentImpl) {
set.add((CommentImpl) a);
}
}
}
return set;
}
/*
* (non-Javadoc)
* @see org.xmind.core.ICommentManager#hasComments(java.lang.String)
*/
public boolean hasComments(String objectId) {
if (objectId == null)
throw new IllegalArgumentException();
Object o = getOwnedWorkbook().getElementById(objectId);
if (o == null || isObjectOrphan(o)) {
return false;
}
Iterator<Element> it = DOMUtils
.childElementIterByTag(getCommentsElement(), TAG_COMMENT);
while (it.hasNext()) {
Element ele = it.next();
if (objectId.equals(DOMUtils.getAttribute(ele, ATTR_OBJECT_ID))) {
IAdaptable a = registry.getAdaptable(ele);
if (a instanceof CommentImpl) {
return true;
}
}
}
return false;
}
/*
* (non-Javadoc)
* @see org.xmind.core.ICommentManager#getAllComments()
*/
public Set<IComment> getAllComments() {
Set<IComment> set = new HashSet<IComment>();
Iterator<Element> it = DOMUtils
.childElementIterByTag(getCommentsElement(), TAG_COMMENT);
while (it.hasNext()) {
Element ele = it.next();
IAdaptable a = registry.getAdaptable(ele);
if (a instanceof CommentImpl) {
CommentImpl c = (CommentImpl) a;
Object o = getOwnedWorkbook().getElementById(c.getObjectId());
if (o != null && !isObjectOrphan(o)) {
set.add(c);
}
}
}
return set;
}
/*
* (non-Javadoc)
* @see org.xmind.core.ICommentManager#isEmpty()
*/
public boolean isEmpty() {
Iterator<Element> it = DOMUtils
.childElementIterByTag(getCommentsElement(), TAG_COMMENT);
while (it.hasNext()) {
Element ele = it.next();
IAdaptable a = registry.getAdaptable(ele);
if (a instanceof CommentImpl) {
CommentImpl c = (CommentImpl) a;
Object o = getOwnedWorkbook().getElementById(c.getObjectId());
if (o != null && !isObjectOrphan(o)) {
return false;
}
}
}
return true;
}
/*
* (non-Javadoc)
* @see
* org.xmind.core.internal.dom.INodeAdaptableFactory#createAdaptable(org.w3c
* .dom.Node)
*/
public IAdaptable createAdaptable(Node node) {
if (node instanceof Element) {
Element ele = (Element) node;
String tag = ele.getTagName();
if (TAG_COMMENT.equals(tag)) {
return new CommentImpl(ownedWorkbook, this, ele);
}
}
return null;
}
protected void updateModificationInfo() {
if (ownedWorkbook != null) {
ownedWorkbook.updateModificationInfo();
}
}
}