/* ******************************************************************************
* 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_AMOUNT;
import static org.xmind.core.internal.dom.DOMConstants.ATTR_ANGLE;
import static org.xmind.core.internal.dom.DOMConstants.ATTR_INDEX;
import static org.xmind.core.internal.dom.DOMConstants.ATTR_X;
import static org.xmind.core.internal.dom.DOMConstants.ATTR_Y;
import static org.xmind.core.internal.dom.DOMConstants.TAG_CONTROL_POINT;
import static org.xmind.core.internal.dom.DOMConstants.TAG_CONTROL_POINTS;
import static org.xmind.core.internal.dom.DOMConstants.TAG_POSITION;
import static org.xmind.core.internal.dom.NumberUtils.safeParseInt;
import java.util.Iterator;
import org.w3c.dom.Element;
import org.xmind.core.Core;
import org.xmind.core.IRelationship;
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.ControlPoint;
import org.xmind.core.util.DOMUtils;
import org.xmind.core.util.Point;
public class ControlPointImpl extends ControlPoint implements ICoreEventSource {
private RelationshipImpl parent;
private int index;
public ControlPointImpl(RelationshipImpl parent, int index) {
this.parent = parent;
this.index = index;
}
public int getIndex() {
return index;
}
public IRelationship getParent() {
return parent;
}
public ISheet getOwnedSheet() {
return parent.getOwnedSheet();
}
public IWorkbook getOwnedWorkbook() {
return parent.getOwnedWorkbook();
}
public boolean isOrphan() {
return parent.isOrphan();
}
public boolean equals(Object obj) {
if (obj == this)
return true;
if (obj == null || !(obj instanceof ControlPointImpl))
return false;
ControlPointImpl that = (ControlPointImpl) obj;
return this.index == that.index && this.parent.equals(that.parent);
}
public String toString() {
return "CP{" + index + "," + parent.toString() + "}"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
public <T> T getAdapter(Class<T> adapter) {
if (ICoreEventSource.class.equals(adapter))
return adapter.cast(this);
if (adapter.isAssignableFrom(Element.class))
return adapter.cast(getImplementation());
if (IRelationship.class.equals(adapter))
return adapter.cast(parent);
return super.getAdapter(adapter);
}
private Element getImplementation() {
Element cps = DOMUtils.getFirstChildElementByTag(getRelElement(),
TAG_CONTROL_POINTS);
if (cps != null) {
Element cp = findImplementation(cps);
if (cp != null)
return cp;
}
return null;
}
private Element findImplementation(Element cps) {
Iterator<Element> cpIt = DOMUtils.childElementIterByTag(cps,
TAG_CONTROL_POINT);
String indexString = String.valueOf(index);
while (cpIt.hasNext()) {
Element cp = cpIt.next();
if (indexString.equals(cp.getAttribute(ATTR_INDEX))) {
return cp;
}
}
return null;
}
private Element getRelElement() {
return parent.getImplementation();
}
public double getPolarAmount() {
Element ele = getImplementation();
if (ele != null) {
return NumberUtils.safeParseDouble(
DOMUtils.getAttribute(ele, ATTR_AMOUNT), 0.3);
}
return 0.3;
}
public double getPolarAngle() {
Element ele = getImplementation();
if (ele != null) {
return NumberUtils
.safeParseDouble(DOMUtils.getAttribute(ele, ATTR_ANGLE), 0);
}
return 0;
}
public boolean usesPolarPosition() {
// Element implementation = getImplementation();
// if (implementation == null)
// return false;
// if (implementation.hasAttribute(ATTR_ANGLE)
// || implementation.hasAttribute(ATTR_AMOUNT))
// return true;
// if (hasPosition())
// return false;
// return true;
return false;
}
public boolean hasPolarAmount() {
Element ele = getImplementation();
if (ele != null) {
return ele.hasAttribute(ATTR_AMOUNT);
}
return false;
}
public boolean hasPolarAngle() {
Element ele = getImplementation();
if (ele != null)
return ele.hasAttribute(ATTR_ANGLE);
return false;
}
public void resetPolarAmount() {
removeAttribute(ATTR_AMOUNT);
}
public void resetPolarAngle() {
removeAttribute(ATTR_ANGLE);
}
private void removeAttribute(String attrName) {
Element ele = getImplementation();
if (ele != null) {
ele.removeAttribute(attrName);
if (!ele.hasAttributes() && !ele.hasChildNodes()) {
ele.getParentNode().removeChild(ele);
}
}
}
private Element ensureImplementation() {
Element cps = DOMUtils.ensureChildElement(getRelElement(),
TAG_CONTROL_POINTS);
Element cp = findImplementation(cps);
if (cp == null) {
cp = DOMUtils.createElement(cps, TAG_CONTROL_POINT);
cp.setAttribute(ATTR_INDEX, String.valueOf(index));
}
return cp;
}
public void setPolarAmount(double amount) {
Element ele = ensureImplementation();
DOMUtils.setAttribute(ele, ATTR_AMOUNT, String.valueOf(amount));
}
public void setPolarAngle(double angle) {
Element ele = ensureImplementation();
DOMUtils.setAttribute(ele, ATTR_ANGLE, String.valueOf(angle));
}
public Point getPosition() {
Element implementation = getImplementation();
if (implementation == null)
return null;
Element e = DOMUtils.getFirstChildElementByTag(implementation,
TAG_POSITION);
if (e == null)
return null;
String x = DOMUtils.getAttribute(e, ATTR_X);
String y = DOMUtils.getAttribute(e, ATTR_Y);
if (x == null && y == null)
return null;
return new Point(safeParseInt(x, 0), safeParseInt(y, 0));
}
public boolean hasPosition() {
Element implementation = getImplementation();
if (implementation == null)
return false;
Element e = DOMUtils.getFirstChildElementByTag(implementation,
TAG_POSITION);
if (e == null)
return false;
return e.hasAttribute(ATTR_X) && e.hasAttribute(ATTR_Y);
}
public void setPosition(int x, int y) {
Element implementation = ensureImplementation();
Point oldValue = getPosition();
Element e = DOMUtils.ensureChildElement(implementation, TAG_POSITION);
DOMUtils.setAttribute(e, ATTR_X, Integer.toString(x));
DOMUtils.setAttribute(e, ATTR_Y, Integer.toString(y));
Point newValue = getPosition();
fireValueChange(Core.Position, oldValue, newValue);
}
protected void removePosition() {
Element implementation = getImplementation();
if (implementation == null)
return;
Point oldValue = getPosition();
Element e = DOMUtils.getFirstChildElementByTag(implementation,
TAG_POSITION);
if (e != null)
implementation.removeChild(e);
Point newValue = getPosition();
fireValueChange(Core.Position, oldValue, newValue);
}
public void setPosition(Point position) {
if (position == null)
removePosition();
else
setPosition(position.x, position.y);
}
protected void fireValueChange(String type, Object oldValue,
Object newValue) {
getCoreEventSupport().dispatchValueChange(this, type, oldValue,
newValue);
}
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 parent.getCoreEventSupport();
}
public ICoreEventRegistration registerCoreEventListener(String type,
ICoreEventListener listener) {
return getCoreEventSupport().registerCoreEventListener(this, type,
listener);
}
}