private static boolean hasReadOnlyResourcesAndSubResources(IJavaScriptElement javaElement)
      throws CoreException {
    switch (javaElement.getElementType()) {
      case IJavaScriptElement.CLASS_FILE:
        // if this assert fails, it means that a precondition is missing
        Assert.isTrue(((IClassFile) javaElement).getResource() instanceof IFile);
        // fall thru
      case IJavaScriptElement.JAVASCRIPT_UNIT:
        IResource resource = ReorgUtils.getResource(javaElement);
        return (resource != null && Resources.isReadOnly(resource));
      case IJavaScriptElement.PACKAGE_FRAGMENT:
        IResource packResource = ReorgUtils.getResource(javaElement);
        if (packResource == null) return false;
        IPackageFragment pack = (IPackageFragment) javaElement;
        if (Resources.isReadOnly(packResource)) return true;
        Object[] nonJava = pack.getNonJavaScriptResources();
        for (int i = 0; i < nonJava.length; i++) {
          Object object = nonJava[i];
          if (object instanceof IResource
              && hasReadOnlyResourcesAndSubResources((IResource) object)) return true;
        }
        return hasReadOnlyResourcesAndSubResources(pack.getChildren());
      case IJavaScriptElement.PACKAGE_FRAGMENT_ROOT:
        IPackageFragmentRoot root = (IPackageFragmentRoot) javaElement;
        if (root.isArchive()) return false;
        IResource pfrResource = ReorgUtils.getResource(javaElement);
        if (pfrResource == null) return false;
        if (Resources.isReadOnly(pfrResource)) return true;
        Object[] nonJava1 = root.getNonJavaScriptResources();
        for (int i = 0; i < nonJava1.length; i++) {
          Object object = nonJava1[i];
          if (object instanceof IResource
              && hasReadOnlyResourcesAndSubResources((IResource) object)) return true;
        }
        return hasReadOnlyResourcesAndSubResources(root.getChildren());

      case IJavaScriptElement.FIELD:
      case IJavaScriptElement.IMPORT_CONTAINER:
      case IJavaScriptElement.IMPORT_DECLARATION:
      case IJavaScriptElement.INITIALIZER:
      case IJavaScriptElement.METHOD:
      case IJavaScriptElement.TYPE:
        return false;
      default:
        Assert.isTrue(false); // not handled here
        return false;
    }
  }
  protected Object[] getPackageFragmentRoots(IJavaScriptProject project)
      throws JavaScriptModelException {
    if (!project.getProject().isOpen()) return NO_CHILDREN;

    IPackageFragmentRoot[] roots = project.getPackageFragmentRoots();
    List list = new ArrayList(roots.length);
    // filter out package fragments that correspond to projects and
    // replace them with the package fragments directly
    for (int i = 0; i < roots.length; i++) {
      IPackageFragmentRoot root = roots[i];
      if (!root.isExternal()) {
        Object[] children = root.getChildren();
        for (int k = 0; k < children.length; k++) list.add(children[k]);
      } else if (hasChildren(root)) {
        list.add(root);
      }
    }
    return concatenate(list.toArray(), project.getNonJavaScriptResources());
  }
 /** Adds all of the openables defined within this package fragment root to the list. */
 private void injectAllOpenablesForPackageFragmentRoot(
     IPackageFragmentRoot root, ArrayList openables) {
   try {
     IJavaScriptElement[] packFrags = root.getChildren();
     for (int k = 0; k < packFrags.length; k++) {
       IPackageFragment packFrag = (IPackageFragment) packFrags[k];
       injectAllOpenablesForPackageFragment(packFrag, openables);
     }
   } catch (JavaScriptModelException e) {
     return;
   }
 }
  /** Adds all of the openables defined within this package fragment to the list. */
  private void injectAllOpenablesForPackageFragment(
      IPackageFragment packFrag, ArrayList openables) {

    try {
      IPackageFragmentRoot root = (IPackageFragmentRoot) packFrag.getParent();
      int kind = root.getKind();
      if (kind != 0) {
        boolean isSourcePackageFragment = (kind == IPackageFragmentRoot.K_SOURCE);
        if (isSourcePackageFragment) {
          IJavaScriptUnit[] cus = packFrag.getJavaScriptUnits();
          for (int i = 0, length = cus.length; i < length; i++) {
            openables.add(cus[i]);
          }
        } else {
          IClassFile[] classFiles = packFrag.getClassFiles();
          for (int i = 0, length = classFiles.length; i < length; i++) {
            openables.add(classFiles[i]);
          }
        }
      }
    } catch (JavaScriptModelException e) {
      // ignore
    }
  }
  /**
   * 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]);
    }
  }