Package org.eclipse.wst.xml.core.internal.document

Source Code of org.eclipse.wst.xml.core.internal.document.DOMModelImpl

/*******************************************************************************
* Copyright (c) 2001, 2011 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
*     Jens Lukowski/Innoopract - initial renaming/restructuring
*    
*******************************************************************************/
package org.eclipse.wst.xml.core.internal.document;

import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.model.AbstractStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
import org.eclipse.wst.sse.core.internal.provisional.events.IStructuredDocumentListener;
import org.eclipse.wst.sse.core.internal.provisional.events.NewDocumentEvent;
import org.eclipse.wst.sse.core.internal.provisional.events.NoChangeEvent;
import org.eclipse.wst.sse.core.internal.provisional.events.RegionChangedEvent;
import org.eclipse.wst.sse.core.internal.provisional.events.RegionsReplacedEvent;
import org.eclipse.wst.sse.core.internal.provisional.events.StructuredDocumentRegionsReplacedEvent;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegionList;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
import org.eclipse.wst.xml.core.internal.Logger;
import org.eclipse.wst.xml.core.internal.provisional.IXMLNamespace;
import org.eclipse.wst.xml.core.internal.provisional.NameValidator;
import org.eclipse.wst.xml.core.internal.provisional.contenttype.ContentTypeIdForXML;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.eclipse.wst.xml.core.internal.provisional.document.ISourceGenerator;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;


/**
* XMLModelImpl class
*/
public class DOMModelImpl extends AbstractStructuredModel implements IStructuredDocumentListener, IDOMModel, DOMImplementation {
  private static String TRACE_PARSER_MANAGEMENT_EXCEPTION = "parserManagement"; //$NON-NLS-1$
  private Object active = null;
  private DocumentImpl document = null;
  private ISourceGenerator generator = null;
  private XMLModelNotifier notifier = null;
  private XMLModelParser parser = null;
  private boolean refresh = false;
  private XMLModelUpdater updater = null;

  /**
   * XMLModelImpl constructor
   */
  public DOMModelImpl() {
    super();
    this.document = (DocumentImpl) internalCreateDocument();
  }

  /**
   * This API allows clients to declare that they are about to make a
   * "large" change to the model. This change might be in terms of content
   * or it might be in terms of the model id or base location.
   *
   * Note that in the case of embedded calls, notification to listeners is
   * sent only once.
   *
   * Note that the client who is making these changes has the responsibility
   * to restore the models state once finished with the changes. See
   * getMemento and restoreState.
   *
   * The method isModelStateChanging can be used by a client to determine if
   * the model is already in a change sequence.
   */
  public void aboutToChangeModel() {
    super.aboutToChangeModel();
    // technically, no need to call beginChanging so often,
    // since aboutToChangeModel can be nested.
    // but will leave as is for this release.
    // see modelChanged, and be sure stays coordinated there.
    getModelNotifier().beginChanging();
  }

  public void aboutToReinitializeModel() {
    XMLModelNotifier notifier = getModelNotifier();
    notifier.cancelPending();
    super.aboutToReinitializeModel();
  }

  /**
   * attrReplaced method
   *
   * @param element
   *            org.w3c.dom.Element
   * @param newAttr
   *            org.w3c.dom.Attr
   * @param oldAttr
   *            org.w3c.dom.Attr
   */
  protected void attrReplaced(Element element, Attr newAttr, Attr oldAttr) {
    if (element == null)
      return;
    if (getActiveParser() == null) {
      XMLModelUpdater updater = getModelUpdater();
      setActive(updater);
      updater.initialize();
      updater.replaceAttr(element, newAttr, oldAttr);
      setActive(null);
    }
    getModelNotifier().attrReplaced(element, newAttr, oldAttr);
  }

  /**
   * This API allows a client controlled way of notifying all ModelEvent
   * listners that the model has been changed. This method is a matched pair
   * to aboutToChangeModel, and must be called after aboutToChangeModel ...
   * or some listeners could be left waiting indefinitely for the changed
   * event. So, its suggested that changedModel always be in a finally
   * clause. Likewise, a client should never call changedModel without
   * calling aboutToChangeModel first.
   *
   * In the case of embedded calls, the notification is just sent once.
   *
   */
  public void changedModel() {
    // NOTE: the order of 'changedModel' and 'endChanging' is significant.
    // By calling changedModel first, this basically decrements the
    // "isChanging" counter
    // in super class and when zero all listeners to model state events
    // will be notified
    // that the model has been changed. 'endChanging' will notify all
    // deferred adapters.
    // So, the significance of order is that adapters (and methods they
    // call)
    // can count on the state of model "isChanging" to be accurate.
    // But, remember, that this means the "modelChanged" event can be
    // received before all
    // adapters have finished their processing.
    // NOTE NOTE: The above note is obsolete in fact (though still states
    // issue correctly).
    // Due to popular demand, the order of these calls were reversed and
    // behavior
    // changed on 07/22/2004.
    //
    // see also
    // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=4302
    // for motivation for this 'on verge of' call.
    // this could be improved in future if notifier also used counting
    // flag to avoid nested calls. If/when changed be sure to check if
    // aboutToChangeModel needs any changes too.
    if (isModelChangeStateOnVergeOfEnding()) {
      // end lock before noticiation loop, since directly or indirectly
      // we may be "called from foriegn code" during notification.
      endLock();
      // we null out here to avoid spurious"warning" message while debug
      // tracing is enabled
      fLockObject = null;
      // the notifier is what controls adaper notification, which
      // should be sent out before the 'modelChanged' event.
      getModelNotifier().endChanging();
    }
    // changedModel handles 'nesting', so only one event sent out
    // when mulitple calls to 'aboutToChange/Changed'.
    super.changedModel();
    handleRefresh();
  }

  /**
   * childReplaced method
   *
   * @param parentNode
   *            org.w3c.dom.Node
   * @param newChild
   *            org.w3c.dom.Node
   * @param oldChild
   *            org.w3c.dom.Node
   */
  protected void childReplaced(Node parentNode, Node newChild, Node oldChild) {
    if (parentNode == null)
      return;
    if (getActiveParser() == null) {
      XMLModelUpdater updater = getModelUpdater();
      setActive(updater);
      updater.initialize();
      updater.replaceChild(parentNode, newChild, oldChild);
      setActive(null);
    }
    getModelNotifier().childReplaced(parentNode, newChild, oldChild);
  }

  /**
   * Creates an XML <code>Document</code> object of the specified type
   * with its document element. HTML-only DOM implementations do not need to
   * implement this method.
   *
   * @param namespaceURIThe
   *            namespace URI of the document element to create.
   * @param qualifiedNameThe
   *            qualified name of the document element to be created.
   * @param doctypeThe
   *            type of document to be created or <code>null</code>. When
   *            <code>doctype</code> is not <code>null</code>, its
   *            <code>Node.ownerDocument</code> attribute is set to the
   *            document being created.
   * @return A new <code>Document</code> object.
   * @exception DOMException
   *                INVALID_CHARACTER_ERR: Raised if the specified qualified
   *                name contains an illegal character. <br>
   *                NAMESPACE_ERR: Raised if the <code>qualifiedName</code>
   *                is malformed, if the <code>qualifiedName</code> has a
   *                prefix and the <code>namespaceURI</code> is
   *                <code>null</code>, or if the
   *                <code>qualifiedName</code> has a prefix that is "xml"
   *                and the <code>namespaceURI</code> is different from "
   *                http://www.w3.org/XML/1998/namespace" .<br>
   *                WRONG_DOCUMENT_ERR: Raised if <code>doctype</code> has
   *                already been used with a different document or was
   *                created from a different implementation.
   * @see DOM Level 2
   */
  public Document createDocument(String namespaceURI, String qualifiedName, DocumentType doctype) throws DOMException {
    final DocumentImpl document = new DocumentImpl();
    if (namespaceURI == null && qualifiedName == null && doctype == null)
      return document;

    if (qualifiedName != null) {

      final int idx = qualifiedName.indexOf(':');
      if (idx > 0) {
        if (namespaceURI == null)
          throw new DOMException(DOMException.NAMESPACE_ERR, null);
        final String prefix = qualifiedName.substring(0, idx);
        if (prefix.equals(IXMLNamespace.XML) && !namespaceURI.equals(IXMLNamespace.XML_URI))
          throw new DOMException(DOMException.NAMESPACE_ERR, null);

        // Check if the qualifiedName is malformed
        if (idx == qualifiedName.length() - 1) // No local name
          throw new DOMException(DOMException.NAMESPACE_ERR, null);

        String localName = qualifiedName.substring(idx + 1);
        final int length = localName.length();
        if (length == 0)
          throw new DOMException(DOMException.NAMESPACE_ERR, null);

        switch (localName.charAt(0)) {
          case '-':
          case '.':
            throw new DOMException(DOMException.NAMESPACE_ERR, null);
        }

        final int qualifiedLength = qualifiedName.length();
        for (int i = 0; i < qualifiedLength; i++) {
          final char c = qualifiedName.charAt(i);
          if (Character.isWhitespace(c))
            throw new DOMException(DOMException.INVALID_CHARACTER_ERR, null);
          else if (c == ':' && i != idx)
            throw new DOMException(DOMException.NAMESPACE_ERR, null);
        }
      }
      if (!NameValidator.isValid(qualifiedName))
        throw new DOMException(DOMException.INVALID_CHARACTER_ERR, null);
    }
    else if (namespaceURI != null){
        throw new DOMException(DOMException.NAMESPACE_ERR, null);
    }

    final DOMModelImpl model = (DOMModelImpl) StructuredModelManager.getModelManager().createUnManagedStructuredModelFor(ContentTypeIdForXML.ContentTypeID_XML);
    if (model != null) {
      document.setModel(model);
      model.document = document;
    }

    if (doctype != null) {
      if (doctype.getOwnerDocument() != null)
        throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, null);
      document.appendChild(doctype);
    }

    final ElementImpl root = new ElementImpl();
    document.appendChild(root);
    root.setNamespaceURI(namespaceURI);
    root.setTagName(qualifiedName);

    return document;
  }

  /**
   * Creates an empty <code>DocumentType</code> node. Entity declarations
   * and notations are not made available. Entity reference expansions and
   * default attribute additions do not occur. It is expected that a future
   * version of the DOM will provide a way for populating a
   * <code>DocumentType</code>.<br>
   * HTML-only DOM implementations do not need to implement this method.
   *
   * @param qualifiedNameThe
   *            qualified name of the document type to be created.
   * @param publicIdThe
   *            external subset public identifier.
   * @param systemIdThe
   *            external subset system identifier.
   * @return A new <code>DocumentType</code> node with
   *         <code>Node.ownerDocument</code> set to <code>null</code>.
   * @exception DOMException
   *                INVALID_CHARACTER_ERR: Raised if the specified qualified
   *                name contains an illegal character. <br>
   *                NAMESPACE_ERR: Raised if the <code>qualifiedName</code>
   *                is malformed.
   * @see DOM Level 2
   */
  public DocumentType createDocumentType(String qualifiedName, String publicId, String systemId) throws DOMException {
    DocumentTypeImpl documentType = new DocumentTypeImpl();
    documentType.setName(qualifiedName);
    documentType.setPublicId(publicId);
    documentType.setSystemId(systemId);
    return documentType;
  }

  /**
   */
  protected void documentTypeChanged() {
    if (this.refresh)
      return;
    // unlike 'resfresh', 'reinitialize' finishes loop
    // and flushes remaining notification que before
    // actually reinitializing.
    // ISSUE: should reinit be used instead of handlerefresh?
    // this.setReinitializeNeeded(true);
    if (this.active != null || getModelNotifier().isChanging())
      return; // defer
    handleRefresh();
  }

  protected void editableChanged(Node node) {
    if (node != null) {
      getModelNotifier().editableChanged(node);
    }
  }

  /**
   */
  protected void endTagChanged(Element element) {
    if (element == null)
      return;
    if (getActiveParser() == null) {
      XMLModelUpdater updater = getModelUpdater();
      setActive(updater);
      updater.initialize();
      updater.changeEndTag(element);
      setActive(null);
    }
    getModelNotifier().endTagChanged(element);
  }

  /**
   */
  private XMLModelParser getActiveParser() {
    if (this.parser == null)
      return null;
    if (this.parser != this.active)
      return null;
    return this.parser;
  }

  /**
   */
  private XMLModelUpdater getActiveUpdater() {
    if (this.updater == null)
      return null;
    if (this.updater != this.active)
      return null;
    return this.updater;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
   */
  public Object getAdapter(Class adapter) {
    if (Document.class.equals(adapter))
      return getDocument();
    return super.getAdapter(adapter);
  }

  /**
   * getDocument method
   *
   * @return XMLDocument
   */
  public IDOMDocument getDocument() {
    return this.document;
  }

  public ISourceGenerator getGenerator() {
    if (this.generator == null) {
      this.generator = XMLGeneratorImpl.getInstance();
    }
    return this.generator;
  }

  /**
   * getNode method
   *
   * @param offset
   *            int
   */
  public IndexedRegion getIndexedRegion(int offset) {
    if (this.document == null)
      return null;
    // search in document children
    IDOMNode parent = null;
    int length = this.document.getEndOffset();
    if (offset * 2 < length) {
      // search from the first
      IDOMNode child = (IDOMNode) this.document.getFirstChild();
      while (child != null) {
        if (child.getEndOffset() <= offset) {
          child = (IDOMNode) child.getNextSibling();
          continue;
        }
        if (child.getStartOffset() > offset) {
          break;
        }
        IStructuredDocumentRegion startStructuredDocumentRegion = child.getStartStructuredDocumentRegion();
        if (startStructuredDocumentRegion != null) {
          if (startStructuredDocumentRegion.getEnd() > offset)
            return child;
        }
        IStructuredDocumentRegion endStructuredDocumentRegion = child.getEndStructuredDocumentRegion();
        if (endStructuredDocumentRegion != null) {
          if (endStructuredDocumentRegion.getStart() <= offset)
            return child;
        }
        // dig more
        parent = child;
        child = (IDOMNode) parent.getFirstChild();
      }
    }
    else {
      // search from the last
      IDOMNode child = (IDOMNode) this.document.getLastChild();
      while (child != null) {
        if (child.getStartOffset() > offset) {
          child = (IDOMNode) child.getPreviousSibling();
          continue;
        }
        if (child.getEndOffset() <= offset) {
          break;
        }
        IStructuredDocumentRegion startStructuredDocumentRegion = child.getStartStructuredDocumentRegion();
        if (startStructuredDocumentRegion != null) {
          if (startStructuredDocumentRegion.getEnd() > offset)
            return child;
        }
        IStructuredDocumentRegion endStructuredDocumentRegion = child.getEndStructuredDocumentRegion();
        if (endStructuredDocumentRegion != null) {
          if (endStructuredDocumentRegion.getStart() <= offset)
            return child;
        }
        // dig more
        parent = child;
        child = (IDOMNode) parent.getLastChild();
      }
    }
    return parent;
  }

  /**
   */
  public XMLModelNotifier getModelNotifier() {
    if (this.notifier == null) {
      this.notifier = new XMLModelNotifierImpl();
    }
    return this.notifier;
  }

  /**
   */
  private XMLModelParser getModelParser() {
    if (this.parser == null) {
      this.parser = createModelParser();
    }
    return this.parser;
  }

  protected XMLModelParser createModelParser() {
    return new XMLModelParser(this);
  }

  /**
   */
  private XMLModelUpdater getModelUpdater() {
    if (this.updater == null) {
      this.updater = createModelUpdater();
    }
    return this.updater;
  }

  protected XMLModelUpdater createModelUpdater() {
    return new XMLModelUpdater(this);
  }

  /**
   */
  private void handleRefresh() {
    if (!this.refresh)
      return;
    XMLModelNotifier notifier = getModelNotifier();
    boolean isChanging = notifier.isChanging();
    if (!isChanging)
      notifier.beginChanging(true);
    XMLModelParser parser = getModelParser();
    setActive(parser);
    this.document.removeChildNodes();
    try {
      this.refresh = false;
      parser.replaceStructuredDocumentRegions(getStructuredDocument().getRegionList(), null);
    }
    catch (Exception ex) {
      Logger.logException(ex);
    }
    finally {
      setActive(null);
      if (!isChanging)
        notifier.endChanging();
    }
  }

  /**
   * Test if the DOM implementation implements a specific feature.
   *
   * @param featureThe
   *            name of the feature to test (case-insensitive). The values
   *            used by DOM features are defined throughout the DOM Level 2
   *            specifications and listed in the section. The name must be
   *            an XML name. To avoid possible conflicts, as a convention,
   *            names referring to features defined outside the DOM
   *            specification should be made unique by reversing the name of
   *            the Internet domain name of the person (or the organization
   *            that the person belongs to) who defines the feature,
   *            component by component, and using this as a prefix. For
   *            instance, the W3C SVG Working Group defines the feature
   *            "org.w3c.dom.svg".
   * @param versionThis
   *            is the version number of the feature to test. In Level 2,
   *            the string can be either "2.0" or "1.0". If the version is
   *            not specified, supporting any version of the feature causes
   *            the method to return <code>true</code>.
   * @return <code>true</code> if the feature is implemented in the
   *         specified version, <code>false</code> otherwise.
   */
  public boolean hasFeature(String feature, String version) {
    if (feature == null)
      return false;
    if (version != null) {
      if (!version.equals("1.0") && !version.equals("2.0")) { //$NON-NLS-2$//$NON-NLS-1$
        return false;
      }
    }
    if (feature.equalsIgnoreCase("Core")) //$NON-NLS-1$
      return true; //$NON-NLS-1$
    if (feature.equalsIgnoreCase("XML")) //$NON-NLS-1$
      return true; //$NON-NLS-1$
    return false;
  }

  /**
   * createDocument method
   *
   * @return org.w3c.dom.Document
   */
  protected Document internalCreateDocument() {
    DocumentImpl document = new DocumentImpl();
    document.setModel(this);
    return document;
  }

  boolean isReparsing() {
    return (active != null);
  }

  /**
   * nameChanged method
   *
   * @param node
   *            org.w3c.dom.Node
   */
  protected void nameChanged(Node node) {
    if (node == null)
      return;
    if (getActiveParser() == null) {
      XMLModelUpdater updater = getModelUpdater();
      setActive(updater);
      updater.initialize();
      updater.changeName(node);
      setActive(null);
    }
    // notification is already sent
  }

  /**
   * newModel method
   *
   */
  public void newModel(NewDocumentEvent structuredDocumentEvent) {
    if (structuredDocumentEvent == null)
      return;
    IStructuredDocument structuredDocument = structuredDocumentEvent.getStructuredDocument();
    if (structuredDocument == null)
      return;
    // this should not happen, but for the case
    if (fStructuredDocument != null && fStructuredDocument != structuredDocument)
      setStructuredDocument(structuredDocument);

    internalSetNewDocument(structuredDocument);
  }

  private void internalSetNewDocument(IStructuredDocument structuredDocument) {
    if (structuredDocument == null)
      return;
    IStructuredDocumentRegionList flatNodes = structuredDocument.getRegionList();
    if ((flatNodes == null) || (flatNodes.getLength() == 0)) {
      return;
    }
    if (this.document == null)
      return; // being constructed
    XMLModelUpdater updater = getActiveUpdater();
    if (updater != null) { // being updated
      try {
        updater.replaceStructuredDocumentRegions(flatNodes, null);
      }
      catch (Exception ex) {
        Logger.logException(ex);
        this.refresh = true;
        handleRefresh();
      }
      finally {
        setActive(null);
      }
      // // for new model, we might need to
      // // re-init, e.g. if someone calls setText
      // // on an existing model
      // checkForReinit();
      return;
    }
    XMLModelNotifier notifier = getModelNotifier();
    boolean isChanging = notifier.isChanging();
    // call even if changing to notify doing new model
    getModelNotifier().beginChanging(true);
    XMLModelParser parser = getModelParser();
    setActive(parser);
    this.document.removeChildNodes();
    try {
      parser.replaceStructuredDocumentRegions(flatNodes, null);
    }
    catch (Exception ex) {
      Logger.logException(ex);
      // meaningless to refresh, because the result might be the same
    }
    finally {
      setActive(null);
      if (!isChanging) {
        getModelNotifier().endChanging();
      }
      // ignore refresh
      this.refresh = false;
    }
  }

  /**
   */
  public void noChange(NoChangeEvent event) {
    XMLModelUpdater updater = getActiveUpdater();
    if (updater != null) { // being updated
      // cleanup updater staffs
      try {
        updater.replaceStructuredDocumentRegions(null, null);
      }
      catch (Exception ex) {
        Logger.logException(ex);
        this.refresh = true;
        handleRefresh();
      }
      finally {
        setActive(null);
      }
      // I guess no chanage means the model could not need re-init
      // checkForReinit();
      return;
    }
  }

  /**
   * nodesReplaced method
   *
   */
  public void nodesReplaced(StructuredDocumentRegionsReplacedEvent event) {
    if (event == null)
      return;
    IStructuredDocumentRegionList oldStructuredDocumentRegions = event.getOldStructuredDocumentRegions();
    IStructuredDocumentRegionList newStructuredDocumentRegions = event.getNewStructuredDocumentRegions();
    XMLModelUpdater updater = getActiveUpdater();
    if (updater != null) { // being updated
      try {
        updater.replaceStructuredDocumentRegions(newStructuredDocumentRegions, oldStructuredDocumentRegions);
      }
      catch (Exception ex) {
        if (ex.getClass().equals(StructuredDocumentRegionManagementException.class)) {
          Logger.traceException(TRACE_PARSER_MANAGEMENT_EXCEPTION, ex);
        }
        else {
          Logger.logException(ex);
        }
        this.refresh = true;
        handleRefresh();
      }
      finally {
        setActive(null);
      }
      // checkForReinit();
      return;
    }
    XMLModelNotifier notifier = getModelNotifier();
    boolean isChanging = notifier.isChanging();
    if (!isChanging)
      notifier.beginChanging();
    XMLModelParser parser = getModelParser();
    setActive(parser);
    try {
      parser.replaceStructuredDocumentRegions(newStructuredDocumentRegions, oldStructuredDocumentRegions);
    }
    catch (Exception ex) {
      Logger.logException(ex);
      this.refresh = true;
      handleRefresh();
    }
    finally {
      setActive(null);
      if (!isChanging) {
        notifier.endChanging();
        handleRefresh();
      }
    }

  }

  /**
   * regionChanged method
   *
   * @param structuredDocumentEvent
   */
  public void regionChanged(RegionChangedEvent event) {
    if (event == null)
      return;
    IStructuredDocumentRegion flatNode = event.getStructuredDocumentRegion();
    if (flatNode == null)
      return;
    ITextRegion region = event.getRegion();
    if (region == null)
      return;
    XMLModelUpdater updater = getActiveUpdater();
    if (updater != null) { // being updated
      try {
        updater.changeRegion(event, flatNode, region);
      }
      catch (Exception ex) {
        Logger.logException(ex);
        this.refresh = true;
        handleRefresh();
      }
      finally {
        setActive(null);
      }
      // checkForReinit();
      return;
    }
    XMLModelNotifier notifier = getModelNotifier();
    boolean isChanging = notifier.isChanging();
    if (!isChanging)
      notifier.beginChanging();
    XMLModelParser parser = getModelParser();
    setActive(parser);
    try {
      parser.changeRegion(event, flatNode, region);
    }
    catch (Exception ex) {
      Logger.logException(ex);
      this.refresh = true;
      handleRefresh();
    }
    finally {
      setActive(null);
      if (!isChanging) {
        notifier.endChanging();
        handleRefresh();
      }
    }
    // checkForReinit();
  }

  /**
   * regionsReplaced method
   *
   * @param event
   */
  public void regionsReplaced(RegionsReplacedEvent event) {
    if (event == null)
      return;
    IStructuredDocumentRegion flatNode = event.getStructuredDocumentRegion();
    if (flatNode == null)
      return;
    ITextRegionList oldRegions = event.getOldRegions();
    ITextRegionList newRegions = event.getNewRegions();
    if (oldRegions == null && newRegions == null)
      return;
    XMLModelUpdater updater = getActiveUpdater();
    if (updater != null) { // being updated
      try {
        updater.replaceRegions(flatNode, newRegions, oldRegions);
      }
      catch (Exception ex) {
        Logger.logException(ex);
        this.refresh = true;
        handleRefresh();
      }
      finally {
        setActive(null);
      }
      // checkForReinit();
      return;
    }
    XMLModelNotifier notifier = getModelNotifier();
    boolean isChanging = notifier.isChanging();
    if (!isChanging)
      notifier.beginChanging();
    XMLModelParser parser = getModelParser();
    setActive(parser);
    try {
      parser.replaceRegions(flatNode, newRegions, oldRegions);
    }
    catch (Exception ex) {
      Logger.logException(ex);
      this.refresh = true;
      handleRefresh();
    }
    finally {
      setActive(null);
      if (!isChanging) {
        notifier.endChanging();
        handleRefresh();
      }
    }
    // checkForReinit();
  }

  /**
   */
  public void releaseFromEdit() {
    if (!isShared()) {
      // this.document.releaseStyleSheets();
      // this.document.releaseDocumentType();
    }
    super.releaseFromEdit();
  }

  /**
   */
  public void releaseFromRead() {
    if (!isShared()) {
      // this.document.releaseStyleSheets();
      // this.document.releaseDocumentType();
    }
    super.releaseFromRead();
  }

  /**
   */
  private void setActive(Object active) {
    this.active = active;
    // side effect
    // when ever becomes active, besure tagNameCache is cleared
    // (and not used)
    if (active == null) {
      document.activateTagNameCache(true);
    }
    else {
      document.activateTagNameCache(false);
    }

  }

  /**
   */
  public void setGenerator(ISourceGenerator generator) {
    this.generator = generator;
  }

  /**
   */
  public void setModelNotifier(XMLModelNotifier notifier) {
    this.notifier = notifier;
  }

  /**
   */
  public void setModelParser(XMLModelParser parser) {
    this.parser = parser;
  }

  /**
   */
  public void setModelUpdater(XMLModelUpdater updater) {
    this.updater = updater;
  }

  /**
   * setStructuredDocument method
   *
   * @param structuredDocument
   */
  public void setStructuredDocument(IStructuredDocument structuredDocument) {
    IStructuredDocument oldStructuredDocument = super.getStructuredDocument();
    if (structuredDocument == oldStructuredDocument)
      return; // nothing to do
    if (oldStructuredDocument != null)
      oldStructuredDocument.removeDocumentChangingListener(this);
    super.setStructuredDocument(structuredDocument);
    if (structuredDocument != null) {
      internalSetNewDocument(structuredDocument);
      structuredDocument.addDocumentChangingListener(this);
    }
  }

  /**
   */
  protected void startTagChanged(Element element) {
    if (element == null)
      return;
    if (getActiveParser() == null) {
      XMLModelUpdater updater = getModelUpdater();
      setActive(updater);
      updater.initialize();
      updater.changeStartTag(element);
      setActive(null);
    }
    getModelNotifier().startTagChanged(element);
  }

  /**
   * valueChanged method
   *
   * @param node
   *            org.w3c.dom.Node
   */
  protected void valueChanged(Node node) {
    if (node == null)
      return;
    if (getActiveParser() == null) {
      XMLModelUpdater updater = getModelUpdater();
      setActive(updater);
      updater.initialize();
      updater.changeValue(node);
      setActive(null);
    }
    getModelNotifier().valueChanged(node);
  }

  /**
   * NOT IMPLEMENTED. Is defined here in preparation of DOM 3.
   */
  public Object getFeature(String feature, String version) {
    throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Not implemented in this version."); //$NON-NLS-1$
  }
}
TOP

Related Classes of org.eclipse.wst.xml.core.internal.document.DOMModelImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.