/* ******************************************************************************
* 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_ID;
import static org.xmind.core.internal.dom.DOMConstants.ATTR_RANGE;
import static org.xmind.core.internal.dom.DOMConstants.ATTR_STYLE_ID;
import static org.xmind.core.internal.dom.DOMConstants.TAG_BOUNDARIES;
import static org.xmind.core.internal.dom.DOMConstants.TAG_TITLE;
import static org.xmind.core.internal.dom.DOMConstants.TAG_TOPIC;
import java.util.Iterator;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xmind.core.Core;
import org.xmind.core.ISheet;
import org.xmind.core.ITopic;
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.Boundary;
import org.xmind.core.util.DOMUtils;
public class BoundaryImpl extends Boundary implements ICoreEventSource {
private WorkbookImpl ownedWorkbook;
private Element implementation;
public BoundaryImpl(Element implementation, WorkbookImpl ownedWorkbook) {
super();
this.implementation = DOMUtils.addIdAttribute(implementation);
this.ownedWorkbook = ownedWorkbook;
}
public Element getImplementation() {
return 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);
}
public boolean equals(Object obj) {
if (obj == this)
return true;
if (obj == null || !(obj instanceof BoundaryImpl))
return false;
BoundaryImpl that = (BoundaryImpl) obj;
return this.implementation == that.implementation;
}
public int hashCode() {
return implementation.hashCode();
}
public String toString() {
return "BND#" + getId() + "(" + getTitleText() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
public String getId() {
return implementation.getAttribute(ATTR_ID);
}
protected String getLocalTitleText() {
return DOMUtils.getTextContentByTag(implementation, TAG_TITLE);
}
public void setTitleText(String titleText) {
String oldText = getLocalTitleText();
DOMUtils.setText(implementation, TAG_TITLE, titleText);
String newText = getLocalTitleText();
fireValueChange(Core.TitleText, oldText, newText);
updateModificationInfo();
}
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 ISheet getOwnedSheet() {
ITopic parent = getParent();
return parent == null ? null : parent.getOwnedSheet();
}
public IWorkbook getOwnedWorkbook() {
return ownedWorkbook;
}
public boolean isOrphan() {
return DOMUtils.isOrphanNode(implementation);
}
public ITopic getParent() {
Element t = getParentTopicElement();
if (t != null)
return (ITopic) ownedWorkbook.getAdaptableRegistry()
.getAdaptable(t);
return null;
}
private Element getParentTopicElement() {
Node p = implementation.getParentNode();
if (DOMUtils.isElementByTag(p, TAG_BOUNDARIES)) {
p = p.getParentNode();
if (DOMUtils.isElementByTag(p, TAG_TOPIC))
return (Element) p;
}
return null;
}
protected ITopic getTopic(int index) {
if (index < 0)
return null;
Element p = getParentTopicElement();
if (p == null)
return null;
Element ts = TopicImpl.findSubtopicsElement(p, ITopic.ATTACHED);
if (ts == null)
return null;
Iterator<Element> it = DOMUtils.childElementIterByTag(ts, TAG_TOPIC);
int i = 0;
while (it.hasNext()) {
Element t = it.next();
if (i == index) {
return (ITopic) ownedWorkbook.getAdaptableRegistry()
.getAdaptable(t);
}
i++;
}
return null;
}
public int getEndIndex() {
return InternalDOMUtils
.getEndIndex(DOMUtils.getAttribute(implementation, ATTR_RANGE));
// return safeParseInt(getAttribute(implementation, ATTR_END_INDEX), -1);
}
public int getStartIndex() {
return InternalDOMUtils.getStartIndex(
DOMUtils.getAttribute(implementation, ATTR_RANGE));
// return safeParseInt(getAttribute(implementation, ATTR_START_INDEX), -1);
}
// private Integer getIndex(String attrName) {
// if (implementation.hasAttribute(attrName)) {
// try {
// return Integer.valueOf(implementation.getAttribute(attrName));
// } catch (NumberFormatException e) {
// return null;
// }
// }
// return null;
// }
private Integer toIndexValue(int index) {
return index < 0 ? null : Integer.valueOf(index);
}
public void setEndIndex(int index) {
String oldValue = DOMUtils.getAttribute(implementation, ATTR_RANGE);
Integer oldIndexValue = toIndexValue(getEndIndex());
DOMUtils.setAttribute(implementation, ATTR_RANGE,
InternalDOMUtils.toRangeValue(getStartIndex(), index));
Integer newIndexValue = toIndexValue(getEndIndex());
String newValue = DOMUtils.getAttribute(implementation, ATTR_RANGE);
fireValueChange(Core.EndIndex, oldIndexValue, newIndexValue);
fireValueChange(Core.Range, oldValue, newValue);
updateModificationInfo();
}
public void setStartIndex(int index) {
String oldValue = DOMUtils.getAttribute(implementation, ATTR_RANGE);
Integer oldIndexValue = toIndexValue(getStartIndex());
DOMUtils.setAttribute(implementation, ATTR_RANGE,
InternalDOMUtils.toRangeValue(index, getEndIndex()));
Integer newIndexValue = toIndexValue(getStartIndex());
String newValue = DOMUtils.getAttribute(implementation, ATTR_RANGE);
fireValueChange(Core.StartIndex, oldIndexValue, newIndexValue);
fireValueChange(Core.Range, oldValue, newValue);
updateModificationInfo();
}
public boolean isMasterBoundary() {
return DOMConstants.VAL_MASTER
.equals(DOMUtils.getAttribute(implementation, ATTR_RANGE));
}
public void setMasterBoundary(boolean overall) {
String oldValue = DOMUtils.getAttribute(implementation, ATTR_RANGE);
String value = overall ? DOMConstants.VAL_MASTER : null;
DOMUtils.setAttribute(implementation, ATTR_RANGE, value);
String newValue = DOMUtils.getAttribute(implementation, ATTR_RANGE);
fireValueChange(Core.Range, oldValue, newValue);
updateModificationInfo();
}
protected WorkbookImpl getRealizedWorkbook() {
ITopic parent = getParent();
if (parent instanceof TopicImpl) {
return ((TopicImpl) parent).getRealizedWorkbook();
}
return null;
}
protected void addNotify(WorkbookImpl workbook, TopicImpl parent) {
getImplementation().setIdAttribute(DOMConstants.ATTR_ID, true);
workbook.getAdaptableRegistry().registerById(this, getId(),
getImplementation().getOwnerDocument());
WorkbookUtilsImpl.increaseStyleRef(workbook, this);
}
protected void removeNotify(WorkbookImpl workbook, TopicImpl 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);
ITopic parent = getParent();
if (parent != null) {
((TopicImpl) parent).updateModificationInfo();
}
}
}