Package org.eclipse.wst.html.core.internal.htmlcss

Source Code of org.eclipse.wst.html.core.internal.htmlcss.StyleElementAdapter

/*******************************************************************************
* Copyright (c) 2004, 2010 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
*    
*       Masaki Saitoh (MSAITOH@jp.ibm.com)
*    See Bug 153000  Style Adapters should be lazier
*    https://bugs.eclipse.org/bugs/show_bug.cgi?id=153000
*
********************************************************************************/
package org.eclipse.wst.html.core.internal.htmlcss;



import org.eclipse.wst.css.core.internal.provisional.adapters.IModelProvideAdapter;
import org.eclipse.wst.css.core.internal.provisional.adapters.IStyleSheetListAdapter;
import org.eclipse.wst.css.core.internal.provisional.document.ICSSModel;
import org.eclipse.wst.html.core.internal.provisional.HTML40Namespace;
import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier;
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.xml.core.internal.provisional.document.IDOMModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
*/
public class StyleElementAdapter extends AbstractStyleSheetAdapter implements IStructuredDocumentListener {

  private boolean replaceModel = true;
  private boolean ignoreNotification = false;

  /**
   */
  protected StyleElementAdapter() {
    super();
  }

  /**
   * Preparation of applying changes from CSS sub-model to HTML model
   */
  private void changeStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
    if (flatNode == null)
      return;
    Element element = getElement();
    if (element == null)
      return;
    ICSSModel model = getExistingModel();
    if (model == null)
      return;
    IStructuredDocument structuredDocument = model.getStructuredDocument();
    if (structuredDocument == null)
      return;

    // get old content length
    Node child = element.getFirstChild();
    if (child == null || child.getNodeType() != Node.TEXT_NODE)
      return;
    IDOMNode content = (IDOMNode) child;
    int oldLength = content.getEndOffset() - content.getStartOffset();

    // get new content length
    int newLength = 0;
    IStructuredDocumentRegionList flatNodes = structuredDocument.getRegionList();
    if (flatNodes != null) {
      int count = flatNodes.getLength();
      if (count > 0) {
        IStructuredDocumentRegion last = flatNodes.item(count - 1);
        if (last != null)
          newLength = last.getEnd();
      }
    }

    int offset = flatNode.getStart();
    int end = flatNode.getEnd();
    int diff = oldLength - newLength;
    int length = end - offset + diff;
    String data = flatNode.getText();

    replaceData(offset, length, data);
  }

  /**
   * Apply changes from HTML model to CSS sub-model
   */
  private void contentChanged() {
    Element element = getElement();
    if (element == null)
      return;
    ICSSModel model = getExistingModel();
    if (model == null)
      return;
    IStructuredDocument structuredDocument = model.getStructuredDocument();
    if (structuredDocument == null)
      return;

    String data = null;
    Node child = element.getFirstChild();
    if (child != null && child.getNodeType() == Node.TEXT_NODE && child.getNextSibling() == null) {
      data = child.getNodeValue();
    }
    if (data == null)
      data = "";//$NON-NLS-1$

    // minimize replace range
    int start = 0, end = 0;
    String oldData = structuredDocument.get();
    if (oldData == null)
      oldData = "";//$NON-NLS-1$

    // search differenct character position from first
    for (; start < oldData.length() && start < data.length(); start++)
      if (oldData.charAt(start) != data.charAt(start))
        break;

    if (start == oldData.length() && start == data.length())
      return; // no change
    else if (start == oldData.length()) {
      structuredDocument.replaceText(getRequesterH2C(), start, 0, data.substring(start)); // append text to last
    }
    else if (start == data.length()) {
      structuredDocument.replaceText(getRequesterH2C(), start, oldData.length() - start, ""); // remove text of last //$NON-NLS-1$
    }
    else {
      // search differenct character position from last
      for (; start < oldData.length() - end && start < data.length() - end; end++) {
        if (oldData.charAt(oldData.length() - end - 1) != data.charAt(data.length() - end - 1))
          break;
      }
      structuredDocument.replaceText(getRequesterH2C(), start, oldData.length() - end - start, data.substring(start, data.length() - end));
    }

  }

  /**
   */
  public ICSSModel getModel() {
    ICSSModel model = getExistingModel();
    if (this.replaceModel) {
      ICSSModel oldModel = model;
      model = createModel(false);

      setModel(model, false); // need to set before contentChanged()
      contentChanged();

      // from super.createModel()
      // get ModelProvideAdapter
      IModelProvideAdapter modelProvideAdapter = (IModelProvideAdapter) ((INodeNotifier) getElement()).getAdapterFor(IModelProvideAdapter.class);
      // notify adapter
      if (modelProvideAdapter != null)
        modelProvideAdapter.modelProvided(model);

      // from createModel()
      IStructuredDocument structuredDocument = null;
      if (model != null)
        structuredDocument = model.getStructuredDocument();
      if (structuredDocument == null)
        return null;
      structuredDocument.addDocumentChangedListener(this);

      // from setModel()
      if (oldModel != null)
        oldModel.removeStyleListener(this);
      if (model != null)
        model.addStyleListener(this);

      if (oldModel != null) {
        // get ModelProvideAdapter
        IModelProvideAdapter adapter = (IModelProvideAdapter) ((INodeNotifier) getElement()).getAdapterFor(IModelProvideAdapter.class);
        if (adapter != null) {
          adapter.modelRemoved(oldModel);
        }
      }

      this.replaceModel = false;
    }
    return model;
  }

  /**
   */
  protected boolean isValidAttribute() {
    Element element = getElement();
    if (element == null) {
      return false;
    }
    String type = element.getAttribute(HTML40Namespace.ATTR_NAME_TYPE);
    if (element.hasAttribute(HTML40Namespace.ATTR_NAME_TYPE) && type.length() > 0 && !type.equalsIgnoreCase("text/css")) { //$NON-NLS-1$
      return false;
    }
    return true;
  }

  /**
   */
  protected ICSSModel createModel() {
    return createModel(true);
  }

  /**
   */
  protected ICSSModel createModel(boolean addListener) {
    if (!isValidAttribute()) {
      return null;
    }

    ICSSModel model = super.createModel(addListener);

    if (!addListener)
      return model;

    IStructuredDocument structuredDocument = model.getStructuredDocument();
    if (structuredDocument == null)
      return null;
    structuredDocument.addDocumentChangedListener(this);

    return model;
  }

  /**
   */
  //  public ICSSModel getModel() {
  //    ICSSModel model = getExistingModel();
  //    if (model == null) {
  //      model = createModel();
  //      if (model == null) return null;
  //      IStructuredDocument structuredDocument = model.getStructuredDocument();
  //      if (structuredDocument == null) return null;
  //      structuredDocument.addModelChangedListener(this);
  //      setModel(model); // need to set before contentChanged()
  //      contentChanged();
  //    }
  //    return model;
  //  }
  /**
   */
  private Object getRequesterH2C() {
    return (getElement() != null && ((IDOMNode) getElement()).getModel() != null) ? (Object) ((IDOMNode) getElement()).getModel() : this;
  }

  /**
   */
  private Object getRequesterC2H() {
    return (getModel() != null) ? (Object) getModel() : this;
  }

  /**
   * Implementing IStructuredDocumentListener's method
   * Event from CSS Flat Model
   */
  public void newModel(NewDocumentEvent event) {
    if (event == null)
      return;
    if (event.getOriginalRequester() == getRequesterH2C())
      return;
    IStructuredDocument structuredDocument = event.getStructuredDocument();
    if (structuredDocument == null)
      return;
    IStructuredDocumentRegionList flatNodes = structuredDocument.getRegionList();
    if (flatNodes == null)
      return;

    replaceStructuredDocumentRegions(flatNodes, null);
  }

  /**
   * Implementing IStructuredDocumentListener's method
   * Event from CSS Flat Model
   */
  public void noChange(NoChangeEvent structuredDocumentEvent) {
  }

  /**
   * Implementing IStructuredDocumentListener's method
   * Event from CSS Flat Model
   */
  public void nodesReplaced(StructuredDocumentRegionsReplacedEvent event) {
    if (event == null)
      return;
    if (event.getOriginalRequester() == getRequesterH2C())
      return;
    IStructuredDocumentRegionList oldStructuredDocumentRegions = event.getOldStructuredDocumentRegions();
    IStructuredDocumentRegionList newStructuredDocumentRegions = event.getNewStructuredDocumentRegions();
    if (oldStructuredDocumentRegions == null && newStructuredDocumentRegions == null)
      return;

    replaceStructuredDocumentRegions(newStructuredDocumentRegions, oldStructuredDocumentRegions);
  }

  /**
   * Overriding INodeAdapter's method
   * Event from <STYLE> element
   */
  public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) {
    if (this.ignoreNotification)
      return;

    if (eventType == INodeNotifier.ADD || eventType == INodeNotifier.REMOVE || eventType == INodeNotifier.CONTENT_CHANGED) {
      contentChanged();
    }
    else if (eventType == INodeNotifier.CHANGE) {
      Attr attr = (Attr) changedFeature;
      if (attr == null)
        return;
      String name = attr.getName();
      if (name.equalsIgnoreCase("type")) { //$NON-NLS-1$
        this.replaceModel = true;

        Element element = getElement();
        if (element == null) {
          return;
        }
        Document document = element.getOwnerDocument();
        if (document == null) {
          return;
        }
        HTMLDocumentAdapter adapter = (HTMLDocumentAdapter) ((INodeNotifier) document).getAdapterFor(IStyleSheetListAdapter.class);
        if (adapter != null) {
          adapter.childReplaced();
        }
      }
    }
  }

  /**
   * Implementing IStructuredDocumentListener's method
   * Event from CSS Flat Model
   */
  public void regionChanged(RegionChangedEvent event) {
    if (event == null)
      return;
    if (event.getOriginalRequester() == getRequesterH2C())
      return;
    IStructuredDocumentRegion flatNode = event.getStructuredDocumentRegion();
    if (flatNode == null)
      return;

    changeStructuredDocumentRegion(flatNode);
  }

  /**
   * Implementing IStructuredDocumentListener's method
   * Event from CSS Flat Model
   */
  public void regionsReplaced(RegionsReplacedEvent event) {
    if (event == null)
      return;
    if (event.getOriginalRequester() == getRequesterH2C())
      return;
    IStructuredDocumentRegion flatNode = event.getStructuredDocumentRegion();
    if (flatNode == null)
      return;

    changeStructuredDocumentRegion(flatNode);
  }

  /**
   * Apply changes from CSS sub-model to HTML model
   */
  private void replaceData(int offset, int length, String data) {
    IDOMNode element = (IDOMNode) getElement();
    if (element == null)
      return;
    IDOMModel ownerModel = element.getModel();
    if (ownerModel == null)
      return;
    IStructuredDocument structuredDocument = ownerModel.getStructuredDocument();
    if (structuredDocument == null)
      return;
    IStructuredDocumentRegion flatNode = element.getStartStructuredDocumentRegion();
    if (flatNode == null)
      return;

    int contentOffset = flatNode.getEndOffset();
    if (data == null)
      data = "";//$NON-NLS-1$

    this.ignoreNotification = true;
    structuredDocument.replaceText(getRequesterC2H(), contentOffset + offset, length, data);
    this.ignoreNotification = false;
  }

  /**
   * Preparation of applying changes from CSS sub-model to HTML model
   */
  private void replaceStructuredDocumentRegions(IStructuredDocumentRegionList newStructuredDocumentRegions, IStructuredDocumentRegionList oldStructuredDocumentRegions) {
    int offset = 0;
    int length = 0;
    if (oldStructuredDocumentRegions != null) {
      int count = oldStructuredDocumentRegions.getLength();
      if (count > 0) {
        IStructuredDocumentRegion first = oldStructuredDocumentRegions.item(0);
        if (first != null)
          offset = first.getStart();
        IStructuredDocumentRegion last = oldStructuredDocumentRegions.item(count - 1);
        if (last != null)
          length = last.getEnd() - offset;
      }
    }
    String data = null;
    if (newStructuredDocumentRegions != null) {
      int count = newStructuredDocumentRegions.getLength();
      if (count > 0) {
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < count; i++) {
          IStructuredDocumentRegion flatNode = newStructuredDocumentRegions.item(i);
          if (flatNode == null)
            continue;
          buffer.append(flatNode.getText());
          if (i == 0)
            offset = flatNode.getStart();
        }
        data = buffer.toString();
      }
    }

    replaceData(offset, length, data);
  }

  /**
   */
  protected void setModel(ICSSModel model) {
    setModel(model, true);
  }

  /**
   */
  protected void setModel(ICSSModel model, boolean setupListener) {
    ICSSModel oldModel = getExistingModel();
    if (model == oldModel)
      return;
    super.setModel(model);
    if (!setupListener)
      return;
    if (oldModel != null)
      oldModel.removeStyleListener(this);
    if (model != null)
      model.addStyleListener(this);
  }
}
TOP

Related Classes of org.eclipse.wst.html.core.internal.htmlcss.StyleElementAdapter

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.