Package org.eclipse.core.internal.resources

Source Code of org.eclipse.core.internal.resources.ProjectContentTypes$ProjectContentTypeSelectionPolicy

/*******************************************************************************
* Copyright (c) 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.core.internal.resources;

import java.util.*;
import org.eclipse.core.internal.utils.Cache;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.content.*;
import org.eclipse.core.runtime.content.IContentTypeManager.ISelectionPolicy;
import org.eclipse.core.runtime.preferences.*;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;

/**
* Manages project-specific content type behavior.
*
* @see ContentDescriptionManager
* @see IContentTypeManager.ISelectionPolicy
* @since 3.1
*/
public class ProjectContentTypes {

  /**
   * A project-aware content type selection policy.
   * This class is also a dynamic scope context that will delegate to either
   * project or instance scope depending on whether project specific settings were enabled
   * for the project in question.   
   */
  private class ProjectContentTypeSelectionPolicy implements ISelectionPolicy, IScopeContext {
    // corresponding project
    private Project project;
    // cached project scope
    private IScopeContext projectScope;

    public ProjectContentTypeSelectionPolicy(Project project) {
      this.project = project;
      this.projectScope = new ProjectScope(project);
    }

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public boolean equals(Object obj) {
      if (this == obj)
        return true;
      if (!(obj instanceof IScopeContext))
        return false;
      IScopeContext other = (IScopeContext) obj;
      if (!getName().equals(other.getName()))
        return false;
      IPath location = getLocation();
      return location == null ? other.getLocation() == null : location.equals(other.getLocation());
    }

    private IScopeContext getDelegate() {
      if (!usesContentTypePreferences(project.getName()))
        return ProjectContentTypes.INSTANCE_SCOPE;
      return projectScope;
    }

    public IPath getLocation() {
      return getDelegate().getLocation();
    }

    public String getName() {
      return getDelegate().getName();
    }

    public IEclipsePreferences getNode(String qualifier) {
      return getDelegate().getNode(qualifier);
    }

    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    public int hashCode() {
      return getName().hashCode();
    }

    public IContentType[] select(IContentType[] candidates, boolean fileName, boolean content) {
      return ProjectContentTypes.this.select(project, candidates, fileName, content);
    }
  }

  private static final String CONTENT_TYPE_PREF_NODE = "content-types"; //$NON-NLS-1$

  static final InstanceScope INSTANCE_SCOPE = new InstanceScope();

  private static final String PREF_LOCAL_CONTENT_TYPE_SETTINGS = "enabled"; //$NON-NLS-1$
  private static final Preferences PROJECT_SCOPE = Platform.getPreferencesService().getRootNode().node(ProjectScope.SCOPE);
  private Cache contentTypesPerProject;
  private Workspace workspace;

  static boolean usesContentTypePreferences(String projectName) {
    try {
      // be careful looking up for our node so not to create any nodes as side effect
      Preferences node = PROJECT_SCOPE;
      //TODO once bug 90500 is fixed, should be simpler
      // for now, take the long way
      if (!node.nodeExists(projectName))
        return false;
      node = node.node(projectName);
      if (!node.nodeExists(Platform.PI_RUNTIME))
        return false;
      node = node.node(Platform.PI_RUNTIME);
      if (!node.nodeExists(CONTENT_TYPE_PREF_NODE))
        return false;
      node = node.node(CONTENT_TYPE_PREF_NODE);
      return node.getBoolean(PREF_LOCAL_CONTENT_TYPE_SETTINGS, false);
    } catch (BackingStoreException e) {
      // exception treated when retrieving the project preferences
    }
    return false;
  }

  public ProjectContentTypes(Workspace workspace) {
    this.workspace = workspace;
    // keep cache small
    this.contentTypesPerProject = new Cache(5, 30, 0.4);
  }

  /**
   * Collect content types associated to the natures configured for the given project.
   */
  private Set collectAssociatedContentTypes(Project project) {
    String[] enabledNatures = workspace.getNatureManager().getEnabledNatures(project);
    if (enabledNatures.length == 0)
      return Collections.EMPTY_SET;
    Set related = new HashSet(enabledNatures.length);
    for (int i = 0; i < enabledNatures.length; i++) {
      ProjectNatureDescriptor descriptor = (ProjectNatureDescriptor) workspace.getNatureDescriptor(enabledNatures[i]);
      if (descriptor == null)
        // no descriptor found for the nature, skip it
        continue;
      String[] natureContentTypes = descriptor.getContentTypeIds();
      for (int j = 0; j < natureContentTypes.length; j++)
        // collect associate content types
        related.add(natureContentTypes[j]);
    }
    return related;
  }

  public void contentTypePreferencesChanged(IProject project) {
    final ProjectInfo info = (ProjectInfo) ((Project) project).getResourceInfo(false, false);
    if (info != null)
      info.setMatcher(null);
  }

  /**
   * Creates a content type matcher for the given project. Takes natures and user settings into account.
   */
  private IContentTypeMatcher createMatcher(Project project) {
    ProjectContentTypeSelectionPolicy projectContentTypeSelectionPolicy = new ProjectContentTypeSelectionPolicy(project);
    return Platform.getContentTypeManager().getMatcher(projectContentTypeSelectionPolicy, projectContentTypeSelectionPolicy);
  }

  private Set getAssociatedContentTypes(Project project) {
    final ResourceInfo info = project.getResourceInfo(false, false);
    if (info == null)
      // the project has been deleted
      return null;
    final String projectName = project.getName();
    synchronized (contentTypesPerProject) {
      Cache.Entry entry = contentTypesPerProject.getEntry(projectName);
      if (entry != null)
        // we have an entry...
        if (entry.getTimestamp() == info.getContentId())
          // ...and it is not stale, so just return it
          return (Set) entry.getCached();
      // no cached information found, have to collect associated content types 
      Set result = collectAssociatedContentTypes(project);
      if (entry == null)
        // there was no entry before - create one
        entry = contentTypesPerProject.addEntry(projectName, result, info.getContentId());
      else {
        // just update the existing entry
        entry.setTimestamp(info.getContentId());
        entry.setCached(result);
      }
      return result;
    }
  }

  public IContentTypeMatcher getMatcherFor(Project project) throws CoreException {
    ProjectInfo info = (ProjectInfo) project.getResourceInfo(false, false);
    //fail if project has been deleted concurrently
    if (info == null)
      project.checkAccessible(project.getFlags(info));
    IContentTypeMatcher matcher = info.getMatcher();
    if (matcher != null)
      return matcher;
    matcher = createMatcher(project);
    info.setMatcher(matcher);
    return matcher;
  }

  /**
   * Implements project specific, nature-based selection policy. No content types are vetoed.
   *
   * The criteria for this policy is as follows:
   * <ol>
   * <li>associated content types should appear before non-associated content types</li>
   * <li>otherwise, relative ordering should be preserved.</li>
   * </ol>
   *
   *  @see IContentTypeManager.ISelectionPolicy
   */
  final IContentType[] select(Project project, IContentType[] candidates, boolean fileName, boolean content) {
    // since no vetoing is done here, don't go further if there is nothing to sort
    if (candidates.length < 2)
      return candidates;
    final Set associated = getAssociatedContentTypes(project);
    if (associated == null || associated.isEmpty())
      // project has no content types associated
      return candidates;
    int associatedCount = 0;
    for (int i = 0; i < candidates.length; i++)
      // is it an associated content type?
      if (associated.contains(candidates[i].getId())) {
        // need to move it to the right spot (unless all types visited so far are associated as well)
        if (associatedCount < i) {
          final IContentType promoted = candidates[i];
          // move all non-associated content types before it one one position up...
          for (int j = i; j > associatedCount; j--)
            candidates[j] = candidates[j - 1];
          // ...so there is an empty spot for the content type we are promoting
          candidates[associatedCount] = promoted;
        }
        associatedCount++;
      }
    return candidates;
  }
}
TOP

Related Classes of org.eclipse.core.internal.resources.ProjectContentTypes$ProjectContentTypeSelectionPolicy

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.