blob: 76b5908bee07298c2d71ebd061c26ff58bee356c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - Initial API and implementation
*******************************************************************************/
package org.eclipse.wst.xsd.ui.internal.text;
import org.eclipse.swt.widgets.Display;
import org.eclipse.wst.sse.core.internal.provisional.INodeAdapter;
import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier;
import org.eclipse.wst.xsd.ui.internal.util.XSDDOMHelper;
import org.eclipse.xsd.XSDConcreteComponent;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.util.XSDConstants;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
public class XSDModelReconcileAdapter extends DocumentAdapter
{
INodeNotifier currentNotifier;
int currentEventType;
XSDSchema schema;
public XSDModelReconcileAdapter(Document document, XSDSchema schema)
{
super(document);
this.schema = schema;
}
boolean handlingNotifyChanged = false;
public void notifyChanged(INodeNotifier notifier, int eventType, Object feature, Object oldValue, Object newValue, int index)
{
if (!handlingNotifyChanged)
{
handlingNotifyChanged = true;
try
{
// delay handle events only in the source view
//if (getCurrentPageType() == XSDEditorPlugin.SOURCE_PAGE &&
// !(getActivePart() instanceof PropertySheet) &&
// !(getActivePart() instanceof org.eclipse.ui.views.contentoutline.ContentOutline)) {
// startDelayedEvent(notifier, eventType, feature, oldValue, newValue, index);
//}
//else // all other views, just handle the events right away
{
handleNotifyChange(notifier, eventType, feature, oldValue, newValue, index);
}
}
catch (Exception e)
{
// XSDEditorPlugin.getPlugin().getMsgLogger().write(e);
}
handlingNotifyChanged = false;
}
}
public void handleNotifyChange(INodeNotifier notifier, int eventType, Object feature, Object oldValue, Object newValue, int index)
{
// System.out.println(eventType + " : HandleNotifyChange " + notifier.hashCode() + " notifier " + notifier);
switch (eventType)
{
case INodeNotifier.ADD:
{
if (newValue instanceof Element)
{
adapt((Element)newValue);
// Add updateParentForDerivation(node, listener);
}
break;
}
case INodeNotifier.REMOVE:
{
Node node = (Node)notifier;
XSDConcreteComponent listener = schema.getCorrespondingComponent(node);
if (listener instanceof XSDSchema)
{
// we want to reset the schema's external elements when the directive is deleted
if (feature instanceof Element)
{
Element elem = (Element)feature;
if (XSDDOMHelper.inputEquals(elem, XSDConstants.INCLUDE_ELEMENT_TAG, false) ||
XSDDOMHelper.inputEquals(elem, XSDConstants.IMPORT_ELEMENT_TAG, false) ||
XSDDOMHelper.inputEquals(elem, XSDConstants.REDEFINE_ELEMENT_TAG, false))
{
schema.reset();
schema.update();
}
}
}
}
case INodeNotifier.CHANGE:
{
Node node = (Node)notifier;
XSDConcreteComponent listener = schema.getCorrespondingComponent(node);
if (node.getNodeType() == Node.ELEMENT_NODE)
{
listener.elementAttributesChanged((Element)node);
listener.elementChanged((Element)node);
}
else if (node.getNodeType() == Node.DOCUMENT_NODE)
{
listener.elementAttributesChanged(((Document)node).getDocumentElement());
listener.elementChanged(((Document)node).getDocumentElement());
}
break;
}
case INodeNotifier.STRUCTURE_CHANGED:
case INodeNotifier.CONTENT_CHANGED:
{
Node node = (Node)notifier;
XSDConcreteComponent listener = schema.getCorrespondingComponent(node);
if (node.getNodeType() == Node.ELEMENT_NODE)
{
listener.elementContentsChanged((Element)node);
break;
}
else if (node.getNodeType() == Node.DOCUMENT_NODE)
{
Element docElement = ((Document)node).getDocumentElement();
// Need to add check if doc element is being edited in the source
if (docElement != null)
{
String prefix = docElement.getPrefix();
String xmlnsString = prefix == null? "xmlns" : "xmlns:" + prefix;
Attr attr = docElement.getAttributeNode(xmlnsString);
boolean doParse = false;
if (attr != null)
{
if (attr.getValue().equals(XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001) && docElement.getLocalName().equals("schema"))
{
// We have a viable schema so parse it
doParse = true;
}
}
if (doParse)
{
adapt(docElement);
schema.setElement(docElement);
}
}
}
break;
}
}
}
protected DelayedEvent delayedTask;
protected void startDelayedEvent(INodeNotifier notifier, int eventType, Object feature, Object oldValue, Object newValue, int index)
{
// System.out.println("start delayed event");
// check if there is already a delayed task for the same notifier and eventType
// if (delayedTask != null)
// {
// Notifier aNotifier = delayedTask.getNotifier();
// int anEventType = delayedTask.getEventType();
// if (notifier == aNotifier && anEventType == eventType)
// {
// // same event, just different data, delay new event
// delayedTask.setCancel(true);
// }
// }
delayedTask = new DelayedEvent();
delayedTask.setNotifier(notifier);
delayedTask.setEventType(eventType);
delayedTask.setFeature(feature);
delayedTask.setOldValue(oldValue);
delayedTask.setNewValue(newValue);
delayedTask.setIndex(index);
Display.getDefault().timerExec(400,delayedTask);
}
class DelayedEvent implements Runnable
{
INodeNotifier notifier;
int eventType;
Object feature;
Object oldValue;
Object newValue;
int index;
boolean cancelEvent = false;
/*
* @see Runnable#run()
*/
public void run()
{
if (!cancelEvent)
{
handleNotifyChange(notifier, eventType, feature, oldValue, newValue, index);
if (delayedTask == this)
{
delayedTask = null;
}
}
}
public void setCancel(boolean flag)
{
cancelEvent = flag;
}
public void setNotifier(INodeNotifier notifier)
{
this.notifier = notifier;
}
public void setEventType(int eventType)
{
this.eventType = eventType;
}
public void setFeature(Object feature)
{
this.feature = feature;
}
public void setOldValue(Object oldValue)
{
this.oldValue = oldValue;
}
public void setNewValue(Object newValue)
{
this.newValue = newValue;
}
public void setIndex(int index)
{
this.index = index;
}
public INodeNotifier getNotifier()
{
return notifier;
}
public int getEventType()
{
return eventType;
}
public Object getNewValue()
{
return newValue;
}
public Object getOldValue()
{
return oldValue;
}
}
}
abstract class DocumentAdapter implements INodeAdapter
{
Document document;
public DocumentAdapter(Document document)
{
this.document = document;
((INodeNotifier)document).addAdapter(this);
adapt(document.getDocumentElement());
}
public void adapt(Element element)
{
if (((INodeNotifier)element).getExistingAdapter(this) == null)
{
((INodeNotifier)element).addAdapter(this);
for (Node child = element.getFirstChild(); child != null; child = child.getNextSibling())
{
if (child.getNodeType() == Node.ELEMENT_NODE)
{
adapt((Element)child);
}
}
}
}
public boolean isAdapterForType(Object type)
{
return type == this;
}
abstract public void notifyChanged
(INodeNotifier notifier, int eventType, Object feature, Object oldValue, Object newValue, int index);
}