/** Observe the changes of the JSDT "Include Path" to synchronize tern script paths. */
 @Override
 public void elementChanged(ElementChangedEvent event) {
   IJavaScriptElementDelta delta = event.getDelta();
   if (delta.getKind() == IJavaScriptElementDelta.CHANGED) {
     // retrieve the JSDT Project if delta is about "Includes Path"
     // changes.
     IJavaScriptProject jsProject = getJavaScriptProjectIfClassPathChanged(delta);
     if (jsProject != null) {
       Job configJob = new ConfigureJob(jsProject);
       configJob.setRule(jsProject.getProject());
       configJob.schedule();
     }
   }
 }
 /**
  * Retrieve the JSDT Project from the delta, if delta is about "Includes Path" changes.
  *
  * @param delta the JSDT delta.
  * @return
  */
 private IJavaScriptProject getJavaScriptProjectIfClassPathChanged(IJavaScriptElementDelta delta) {
   if (delta.getKind() != IJavaScriptElementDelta.CHANGED) {
     return null;
   }
   IJavaScriptElement element = delta.getElement();
   switch (element.getElementType()) {
     case IJavaScriptElement.JAVASCRIPT_MODEL:
       IJavaScriptElementDelta[] children = delta.getAffectedChildren();
       for (int i = 0, length = children.length; i < length; i++) {
         IJavaScriptElementDelta child = children[i];
         IJavaScriptProject project = getJavaScriptProjectIfClassPathChanged(child);
         if (project != null) {
           return project;
         }
       }
       return null;
     case IJavaScriptElement.JAVASCRIPT_PROJECT:
       int kind = delta.getKind();
       switch (kind) {
         case IJavaScriptElementDelta.ADDED:
         case IJavaScriptElementDelta.REMOVED:
           return null;
         case IJavaScriptElementDelta.CHANGED:
           int flags = delta.getFlags();
           if ((flags & IJavaScriptElementDelta.F_CLOSED) != 0
               || (flags & IJavaScriptElementDelta.F_OPENED) != 0) {
             return null;
           } else {
             children = delta.getAffectedChildren();
             for (int i = 0, length = children.length; i < length; i++) {
               IJavaScriptElementDelta child = children[i];
               IJavaScriptProject project = getJavaScriptProjectIfClassPathChanged(child);
               if (project != null) {
                 return project;
               }
             }
           }
           return null;
       }
       return null;
     case IJavaScriptElement.PACKAGE_FRAGMENT_ROOT:
       kind = delta.getKind();
       switch (kind) {
         case IJavaScriptElementDelta.ADDED:
         case IJavaScriptElementDelta.REMOVED:
           return null;
         case IJavaScriptElementDelta.CHANGED:
           int flags = delta.getFlags();
           if ((flags & IJavaScriptElementDelta.F_ADDED_TO_CLASSPATH) > 0
               || (flags & IJavaScriptElementDelta.F_REMOVED_FROM_CLASSPATH) > 0) {
             // "Include Path" has changed, returns the JSDT project.
             return element.getJavaScriptProject();
           }
           return null;
       }
       break;
   }
   return null;
 }
  /**
   * Processes a delta recursively. When more than two children are affected the tree is fully
   * refreshed starting at this node. The delta is processed in the current thread but the viewer
   * updates are posted to the UI thread.
   */
  protected void processDelta(IJavaScriptElementDelta delta) throws JavaScriptModelException {
    int kind = delta.getKind();
    int flags = delta.getFlags();
    final IJavaScriptElement element = delta.getElement();
    final boolean isElementValidForView = fBrowsingPart.isValidElement(element);

    if (!getProvideWorkingCopy()
        && element instanceof IJavaScriptUnit
        && ((IJavaScriptUnit) element).isWorkingCopy()) return;

    if (element != null
        && element.getElementType() == IJavaScriptElement.JAVASCRIPT_UNIT
        && !isOnClassPath((IJavaScriptUnit) element)) return;

    // handle open and closing of a solution or project
    if (((flags & IJavaScriptElementDelta.F_CLOSED) != 0)
        || ((flags & IJavaScriptElementDelta.F_OPENED) != 0)) {
      postRefresh(null);
      return;
    }

    if (kind == IJavaScriptElementDelta.REMOVED) {
      Object parent = internalGetParent(element);
      if (isElementValidForView) {
        if (element instanceof IClassFile) {
          postRemove(((IClassFile) element).getType());
        } else if (element instanceof IJavaScriptUnit
            && !((IJavaScriptUnit) element).isWorkingCopy()) {
          postRefresh(null);
        } else if (element instanceof IJavaScriptUnit
            && ((IJavaScriptUnit) element).isWorkingCopy()) {
          if (getProvideWorkingCopy()) postRefresh(null);
        } else if (parent instanceof IJavaScriptUnit
            && getProvideWorkingCopy()
            && !((IJavaScriptUnit) parent).isWorkingCopy()) {
          if (element instanceof IJavaScriptUnit && ((IJavaScriptUnit) element).isWorkingCopy()) {
            // working copy removed from system - refresh
            postRefresh(null);
          }
        } else if (element instanceof IJavaScriptUnit
            && ((IJavaScriptUnit) element).isWorkingCopy()
            && parent != null
            && parent.equals(fInput))
          // closed editor - removing working copy
          postRefresh(null);
        else postRemove(element);
      }

      if (fBrowsingPart.isAncestorOf(element, fInput)) {
        if (element instanceof IJavaScriptUnit && ((IJavaScriptUnit) element).isWorkingCopy()) {
          postAdjustInputAndSetSelection(((IJavaScriptElement) fInput).getPrimaryElement());
        } else postAdjustInputAndSetSelection(null);
      }

      if (fInput != null && fInput.equals(element)) postRefresh(null);

      if (parent instanceof IPackageFragment && fBrowsingPart.isValidElement(parent)) {
        // refresh if package gets empty (might be filtered)
        if (isPackageFragmentEmpty((IPackageFragment) parent)
            && fViewer.testFindItem(parent) != null) postRefresh(null);
      }

      return;
    }
    if (kind == IJavaScriptElementDelta.ADDED
        && delta.getMovedFromElement() != null
        && element instanceof IJavaScriptUnit) return;

    if (kind == IJavaScriptElementDelta.ADDED) {
      if (isElementValidForView) {
        Object parent = internalGetParent(element);
        if (element instanceof IClassFile) {
          postAdd(parent, ((IClassFile) element).getType());
        } else if (element instanceof IJavaScriptUnit
            && !((IJavaScriptUnit) element).isWorkingCopy()) {
          postAdd(parent, ((IJavaScriptUnit) element).getTypes());
        } else if (parent instanceof IJavaScriptUnit
            && getProvideWorkingCopy()
            && !((IJavaScriptUnit) parent).isWorkingCopy()) {
          //	do nothing
        } else if (element instanceof IJavaScriptUnit
            && ((IJavaScriptUnit) element).isWorkingCopy()) {
          // new working copy comes to live
          postRefresh(null);
        } else postAdd(parent, element);
      } else if (fInput == null) {
        IJavaScriptElement newInput = fBrowsingPart.findInputForJavaElement(element);
        if (newInput != null) postAdjustInputAndSetSelection(element);
      } else if (element instanceof IType && fBrowsingPart.isValidInput(element)) {
        IJavaScriptElement cu1 = element.getAncestor(IJavaScriptElement.JAVASCRIPT_UNIT);
        IJavaScriptElement cu2 =
            ((IJavaScriptElement) fInput).getAncestor(IJavaScriptElement.JAVASCRIPT_UNIT);
        if (cu1 != null && cu2 != null && cu1.equals(cu2)) postAdjustInputAndSetSelection(element);
      }
      return;
    }

    if (kind == IJavaScriptElementDelta.CHANGED) {
      if (fInput != null
          && fInput.equals(element)
          && (flags & IJavaScriptElementDelta.F_CHILDREN) != 0
          && (flags & IJavaScriptElementDelta.F_FINE_GRAINED) != 0) {
        postRefresh(null, true);
        return;
      }
      if (isElementValidForView && (flags & IJavaScriptElementDelta.F_MODIFIERS) != 0) {
        postUpdateIcon(element);
      }
    }

    if (isClassPathChange(delta))
      // throw the towel and do a full refresh
      postRefresh(null);

    if ((flags & IJavaScriptElementDelta.F_ARCHIVE_CONTENT_CHANGED) != 0
        && fInput instanceof IJavaScriptElement) {
      IPackageFragmentRoot pkgRoot = (IPackageFragmentRoot) element;
      IJavaScriptElement inputsParent =
          ((IJavaScriptElement) fInput).getAncestor(IJavaScriptElement.PACKAGE_FRAGMENT_ROOT);
      if (pkgRoot.equals(inputsParent)) postRefresh(null);
    }

    // the source attachment of a JAR has changed
    if (element instanceof IPackageFragmentRoot
        && (((flags & IJavaScriptElementDelta.F_SOURCEATTACHED) != 0
            || ((flags & IJavaScriptElementDelta.F_SOURCEDETACHED)) != 0))) postUpdateIcon(element);

    IJavaScriptElementDelta[] affectedChildren = delta.getAffectedChildren();
    if (affectedChildren.length > 1) {
      // a package fragment might become non empty refresh from the parent
      if (element instanceof IPackageFragment) {
        IJavaScriptElement parent = (IJavaScriptElement) internalGetParent(element);
        // avoid posting a refresh to an invisible parent
        if (element.equals(fInput)) {
          postRefresh(element);
        } else {
          postRefresh(parent);
        }
      }
      // more than one child changed, refresh from here downwards
      if (element instanceof IPackageFragmentRoot && isElementValidForView) {
        postRefresh(skipProjectPackageFragmentRoot((IPackageFragmentRoot) element));
        return;
      }
    }
    for (int i = 0; i < affectedChildren.length; i++) {
      processDelta(affectedChildren[i]);
    }
  }