/* ****************************************************************************** * Copyright (c) 2006-2012 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_END1; import static org.xmind.core.internal.dom.DOMConstants.ATTR_END2; import static org.xmind.core.internal.dom.DOMConstants.ATTR_ID; import static org.xmind.core.internal.dom.DOMConstants.ATTR_STYLE_ID; import static org.xmind.core.internal.dom.DOMConstants.TAG_RELATIONSHIPS; import static org.xmind.core.internal.dom.DOMConstants.TAG_SHEET; import static org.xmind.core.internal.dom.DOMConstants.TAG_TITLE; import java.util.HashMap; import java.util.Map; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xmind.core.Core; import org.xmind.core.IAdaptable; import org.xmind.core.IControlPoint; import org.xmind.core.IRelationshipEnd; import org.xmind.core.ISheet; import org.xmind.core.IWorkbook; import org.xmind.core.event.ICoreEventListener; import org.xmind.core.event.ICoreEventRegistration; import org.xmind.core.event.ICoreEventSource; import org.xmind.core.event.ICoreEventSupport; import org.xmind.core.internal.Relationship; import org.xmind.core.util.DOMUtils; /** * @author briansun */ public class RelationshipImpl extends Relationship implements ICoreEventSource { private Element implementation; private WorkbookImpl ownedWorkbook; private Map<Integer, ControlPointImpl> controlPoints = null; /** * @param implementation */ public RelationshipImpl(Element implementation, WorkbookImpl ownedWorkbook) { super(); this.implementation = DOMUtils.addIdAttribute(implementation); this.ownedWorkbook = ownedWorkbook; } /** * @return the implementation */ public Element getImplementation() { return implementation; } /** * @see org.xmind.core.IRelationship#getId() */ public String getId() { return implementation.getAttribute(ATTR_ID); } /** * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (obj == this) return true; if (obj == null || !(obj instanceof RelationshipImpl)) return false; RelationshipImpl r = (RelationshipImpl) obj; return implementation == r.implementation; } public int hashCode() { return implementation.hashCode(); } public String toString() { return "REL#" + getId() + "(" + getTitleText() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } /** * @see org.xmind.core.IRelationship#getEnd1Id() */ public String getEnd1Id() { return DOMUtils.getAttribute(implementation, ATTR_END1); } /** * @see org.xmind.core.IRelationship#setEnd1Id(java.lang.String) */ public void setEnd1Id(String id) { String oldId = getEnd1Id(); DOMUtils.setAttribute(implementation, ATTR_END1, id); String newId = getEnd1Id(); fireValueChange(Core.RelationshipEnd1, oldId, newId); updateModificationInfo(); } /** * @see org.xmind.core.IRelationship#getEnd2Id() */ public String getEnd2Id() { return DOMUtils.getAttribute(implementation, ATTR_END2); } /** * @see org.xmind.core.IRelationship#setEnd2Id(java.lang.String) */ public void setEnd2Id(String id) { String oldId = getEnd2Id(); DOMUtils.setAttribute(implementation, ATTR_END2, id); String newId = getEnd2Id(); fireValueChange(Core.RelationshipEnd2, oldId, newId); updateModificationInfo(); } /* * (non-Javadoc) * @see org.xmind.core.internal.Relationship#getEnd1() */ @Override public IRelationshipEnd getEnd1() { return findEnd(getEnd1Id()); } /* * (non-Javadoc) * @see org.xmind.core.internal.Relationship#getEnd2() */ @Override public IRelationshipEnd getEnd2() { return findEnd(getEnd2Id()); } private IRelationshipEnd findEnd(String endId) { if (endId == null) return null; IAdaptable obj = ownedWorkbook.getAdaptableRegistry() .getAdaptable(endId, implementation.getOwnerDocument()); if (obj instanceof IRelationshipEnd) { return (IRelationshipEnd) obj; } return null; } /** * @see org.xmind.core.IRelationship#getParent() */ public ISheet getParent() { Node p = implementation.getParentNode(); if (DOMUtils.isElementByTag(p, TAG_RELATIONSHIPS)) { p = p.getParentNode(); if (DOMUtils.isElementByTag(p, TAG_SHEET)) { return (ISheet) ownedWorkbook.getAdaptableRegistry() .getAdaptable(p); } } return null; } /** * @see org.xmind.core.ITitled#setTitleText(java.lang.String) */ public void setTitleText(String titleText) { String oldText = getLocalTitleText(); DOMUtils.setText(implementation, TAG_TITLE, titleText); String newText = getLocalTitleText(); fireValueChange(Core.TitleText, oldText, newText); updateModificationInfo(); } /** * @see org.xmind.core.internal.Relationship#getLocalTitleText() */ @Override protected String getLocalTitleText() { return DOMUtils.getTextContentByTag(implementation, TAG_TITLE); } /** * @see org.xmind.core.internal.Relationship#getOwnedWorkbook() */ public IWorkbook getOwnedWorkbook() { return ownedWorkbook; } public boolean isOrphan() { return DOMUtils.isOrphanNode(implementation); } public <T> T getAdapter(Class<T> adapter) { if (ICoreEventSource.class.equals(adapter)) return adapter.cast(this); if (adapter.isAssignableFrom(Element.class)) return adapter.cast(implementation); return super.getAdapter(adapter); } /** * @see org.xmind.core.IRelationship#checkAvailable() */ public boolean checkAvailable() { IRelationshipEnd end1 = getEnd1(); IRelationshipEnd end2 = getEnd2(); if (end1 != null && end2 != null) { ISheet sheet1 = end1.getOwnedSheet(); if (sheet1 != null && sheet1.equals(end2.getOwnedSheet())) return true; } return false; } public String getStyleId() { return DOMUtils.getAttribute(implementation, ATTR_STYLE_ID); } public void setStyleId(String styleId) { String oldValue = getStyleId(); WorkbookImpl workbook = getRealizedWorkbook(); WorkbookUtilsImpl.decreaseStyleRef(workbook, this); DOMUtils.setAttribute(implementation, ATTR_STYLE_ID, styleId); WorkbookUtilsImpl.increaseStyleRef(workbook, this); String newValue = getStyleId(); fireValueChange(Core.Style, oldValue, newValue); updateModificationInfo(); } public IControlPoint getControlPoint(int index) { if (controlPoints == null) controlPoints = new HashMap<Integer, ControlPointImpl>(); ControlPointImpl controlPoint = controlPoints .get(Integer.valueOf(index)); if (controlPoint == null) { controlPoint = new ControlPointImpl(this, index); controlPoints.put(Integer.valueOf(index), controlPoint); } return controlPoint; // Element cp = getControlPointElement(index); // if (cp != null) { // return new ControlPointImpl(cp); // } // return null; } // private Element getControlPointElement(int index) { // Element cps = getFirstChildElementByTag(implementation, // TAG_CONTROL_POINTS); // return cps == null ? null : getControlPointElement(index, cps); // } // // private Element getControlPointElement(int index, Element cps) { // Iterator<Element> it = childElementIterByTag(cps, TAG_CONTROL_POINT); // while (it.hasNext()) { // Element cp = it.next(); // String i = cp.getAttribute(ATTR_INDEX); // if (i != null && NumberUtils.safeParseInt(i, -1) == index) // return cp; // } // return null; // } // // public void setControlPoint(int index, double angle, double amount) { // Element cps = ensureChildElement(implementation, TAG_CONTROL_POINTS); // Element cp = getControlPointElement(index, cps); // if (cp == null) { // cp = createElement(cps, TAG_CONTROL_POINT); // cp.setAttribute(ATTR_INDEX, Integer.toString(index)); // } // cp.setAttribute(ATTR_ANGLE, Double.toString(angle)); // cp.setAttribute(ATTR_AMOUNT, Double.toString(amount)); // fireIndexedTargetChange(Core.RelationshipControlPoint, // getControlPoint(index), index); // } // // public void resetControlPoint(int index) { // Element cps = getFirstChildElementByTag(implementation, // TAG_CONTROL_POINTS); // if (cps == null) // return; // Element cp = getControlPointElement(index, cps); // if (cp == null) // return; // cp.removeAttribute(ATTR_ANGLE); // cp.removeAttribute(ATTR_AMOUNT); // if (!cp.hasChildNodes()) { // cps.removeChild(cp); // } // fireIndexedTargetChange(Core.RelationshipControlPoint, // getControlPoint(index), index); // } protected WorkbookImpl getRealizedWorkbook() { ISheet sheet = getParent(); if (sheet != null) { if (ownedWorkbook == sheet.getParent()) return ownedWorkbook; } return null; } protected void addNotify(WorkbookImpl workbook, SheetImpl parent) { getImplementation().setIdAttribute(DOMConstants.ATTR_ID, true); workbook.getAdaptableRegistry().registerById(this, getId(), getImplementation().getOwnerDocument()); WorkbookUtilsImpl.increaseStyleRef(workbook, this); } protected void removeNotify(WorkbookImpl workbook, SheetImpl parent) { WorkbookUtilsImpl.decreaseStyleRef(workbook, this); workbook.getAdaptableRegistry().unregisterById(this, getId(), getImplementation().getOwnerDocument()); getImplementation().setIdAttribute(DOMConstants.ATTR_ID, false); } public ICoreEventRegistration registerCoreEventListener(String type, ICoreEventListener listener) { return getCoreEventSupport().registerCoreEventListener(this, type, listener); } public ICoreEventSupport getCoreEventSupport() { // Use workbook's core event support directly, so that // orphan components can have events broadcasted, which // will enable transient actions (such as dragging topics // or adjusting relationship control points, etc.) to // perform correctly. return ownedWorkbook.getCoreEventSupport(); } private void fireValueChange(String type, Object oldValue, Object newValue) { getCoreEventSupport().dispatchValueChange(this, type, oldValue, newValue); } public long getModifiedTime() { return InternalDOMUtils.getModifiedTime(this, implementation); } public String getModifiedBy() { return InternalDOMUtils.getModifiedBy(this, implementation); } protected void updateModificationInfo() { InternalDOMUtils.updateModificationInfo(this); ISheet sheet = getParent(); if (sheet != null) { ((SheetImpl) sheet).updateModificationInfo(); } } }