Package processing.plugin.core.builder

Source Code of processing.plugin.core.builder.SketchProject

/**
* Copyright (c) 2010 Ben Fry and Casey Reas
*
* 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.opensource.org/licenses/eclipse-1.0.php
*
* Contributors:
*     Chris Lonnen - initial API and implementation
*/
package processing.plugin.core.builder;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;

import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.JavaRuntime;

import processing.plugin.core.ProcessingCore;

/**
* A nature indicating that the project is a Processing sketch.
* <p>
* This handles all the setup and config for the sketch builder
* and the JDT JavaProject that underlies a Processing sketch.
* Attempts to muck about with the sketch settings should do so
* through methods presented in this nature to prevent things
* from turning ugly. Actually, any mucking about will probably
* mess things up.
* <p>
* This also holds state information about the sketch itself
* that is generated and collected from the sketch files, the
* builder, a thorough background check, and maybe a little
* dumpster diving. It acts as an ad-hoc model of a sketch project. 
*/
public class SketchProject implements IProjectNature {

  /** value: <code>"processing.plugin.core.sketchNature"</code> */
  public static final String NATURE_ID = ProcessingCore.PLUGIN_ID + ".sketchNature";

  // TODO make these a preference
  public static final int DEFAULT_WIDTH = 100;
  public static final int DEFAULT_HEIGHT = 100;
 
  /** The basic project entry being managed */
  protected IProject project;

  protected int sketch_width = -1;
  protected int sketch_height = -1;

  protected String renderer = "";
 
  protected boolean wasLastBuildSuccessful = false;
 
  protected ArrayList<IPath> libraryPaths = new ArrayList<IPath>();
 
  /**
   * Return the SketchProject associated with the given IProject, or null
   * if the project is not associated with a SketchProject.
   */
  public static SketchProject forProject(IProject project) {
    IProjectNature nature = null;
    try{
      nature = project.getNature(NATURE_ID);
    } catch (CoreException e){
      return null;
    }
    return (SketchProject) nature;
  }

  /** True if the project has the SketchProject nature, false otherwise. */
  public static boolean isSketchProject(IProject project) {
    return SketchProject.forProject(project) != null;
  }

  /**
   * Add the Sketch Project and Java Project natures to the nature list of the project.
   * <p>
   * The order they are added determines the order they are configured, so the Sketch
   * Project nature is added second to ensure the builders are configured in the correct
   * order.
   */
  public static void addSketchNature(IProject project) throws CoreException {
    if (!project.isOpen())
      return;

    if (SketchProject.isSketchProject(project)) return;

    IProjectDescription description = project.getDescription();

    List<String> newIds = new ArrayList<String>();
    newIds.add(JavaCore.NATURE_ID);
    newIds.add(SketchProject.NATURE_ID);
    newIds.addAll(Arrays.asList(description.getNatureIds()));
    description.setNatureIds(newIds.toArray(new String[newIds.size()]));

    project.setDescription(description, null);
  }

  /** Removes the sketch and java natures from a project */
  public static void removeSketchNature(IProject project) throws CoreException {
    if (!project.isOpen())  return;
    if (!SketchProject.isSketchProject(project)) return;

    IProjectDescription description = project.getDescription();

    List<String> newIds = new ArrayList<String>();
    newIds.addAll(Arrays.asList(description.getNatureIds()));
    newIds.remove(newIds.indexOf(NATURE_ID));
    if (newIds.contains(JavaCore.NATURE_ID))
      newIds.remove(newIds.indexOf(JavaCore.NATURE_ID));
    description.setNatureIds(newIds.toArray(new String[newIds.size()]));

    project.setDescription(description,null);
  }

  /** Access method for this nature's project */
  public IProject getProject() {
    return project;
  }
 
  /**
   * Should not be triggered by clients.
   * Sent by the NatureManager when the nature is added to a project.
   */
  public void setProject(IProject project) {
    this.project = project;
  }

  /** Access method for this nature's java project */
  public IJavaProject getJavaProject() {
    return JavaCore.create(project);
  }

  /** Associate the sketch builder with this nature's project */
  public void configure() throws CoreException {
    if (!project.isOpen()) return;
   
    /* When the workspace is out of date after an import,
     * but before the background refresh is finished these will
     * fail iff the folder already exists, so we expect a logged
     * error but no real negative consequences. The first build
     * after the refresh is finished will align everything
     * properly again.
     */
    getCodeFolder();
    getDataFolder();
    getBuildFolder();
    getJavaBuildFolder();

    // Check the description to see if it already has the builder
    IProjectDescription description = project.getDescription();
    List<ICommand> newCmds = new ArrayList<ICommand>();
    newCmds.addAll(Arrays.asList(description.getBuildSpec()));

    ICommand command = description.newCommand();
    command.setBuilderName(SketchBuilder.BUILDER_ID);
   
    int ploc = newCmds.lastIndexOf(SketchBuilder.BUILDER_ID);

    // remove it if it does
    if (ploc != -1) newCmds.remove(ploc);
   
    newCmds.add(0, command);
   
    //  Now that we're sure it's gone, add a single instance to the front of the list
    description.setBuildSpec(
      (ICommand[]) newCmds.toArray(new ICommand[newCmds.size()])
    );
    project.setDescription(description,null);
   
    updateClasspathEntries(null, null);
  }

  /**
   * Dissociate the processing sketch builder from this nature's
   * project and remove the markers it generated.
   */
  public void deconfigure() throws CoreException {
    if (!project.isOpen()) return;
   
    SketchBuilder.deleteP5ProblemMarkers(project); // clean up annotations

    IProjectDescription description = project.getDescription();
    ICommand[] cmds = description.getBuildSpec();
    for (int i=0; i<cmds.length; i++){
      if (cmds[i].getBuilderName().equals(SketchBuilder.BUILDER_ID)){
        List<ICommand> newCmds = new ArrayList<ICommand>();
        newCmds.addAll(Arrays.asList(cmds));
        newCmds.remove(i);
        description.setBuildSpec(newCmds.toArray(new ICommand[newCmds.size()]));
      }
    }
  }

  /** Returns a qualified name for the property relative to this plug-in */
  public QualifiedName getPropertyName(String localName) {
    return new QualifiedName(ProcessingCore.PLUGIN_ID, localName);
  }

  /**
   * Sets a persistent property in the poject's property store
   * If there is an exception it will be reported and the project
   * will not persist.
   **/
  public void setPersistentProperty(String localName, String value) {
    try{
      this.project.setPersistentProperty(this.getPropertyName(localName), value);
    } catch (CoreException e){
      ProcessingCore.logError(e);
    }   
  }

  /** Trigger a full build of the project being managed */
  public void fullBuild(IProgressMonitor monitor) throws CoreException {
    project.build(IncrementalProjectBuilder.FULL_BUILD, monitor);
  }
 
  /** Return the sketch's code folder or null if it cannot be retrieved. */
  public IFolder getCodeFolder(){
    try{
      IFolder code = project.getFolder("code");
      if(!code.exists())
        code.create(IResource.NONE, true, null);
      return code;
    } catch (Exception e){
      ProcessingCore.logError("Code folder could not be created.", e);
      return null;
    }
  }

  /** Return the sketch's code folder or null if it cannot be retrieved */
  public IFolder getDataFolder() {
    try{
      IFolder data = project.getFolder("data");
      if(!data.exists())
        data.create(IResource.NONE, true, null);
      return data;
    } catch (Exception e){
      ProcessingCore.logError("Data folder could not be created.", e);
      return null;
    }
  }
 
  public IFolder getAppletFolder() {
    return getAppletFolder(false);
  }
 
  /** Return the sketch's code folder or null if it cannot be retrieved. */
  public IFolder getAppletFolder(boolean delete) {
    try{
      IFolder applet = project.getFolder("applet");
      if(delete && applet.exists()) applet.delete(true, null);
      if(!applet.exists()) applet.create(IResource.NONE, true, null);
      return project.getFolder("applet");
    } catch (Exception e){
      ProcessingCore.logError("Applet folder could not be created.", e);
      return null;
    }
  }

  /**
   * Return a vanilla File handle to the output folder for the Java compiler or null if it cannot be created.
   * <p>
   * Users shouldn't be messing with this folder unless they know what they're doing.
   * Unfortunately, JDT requires the build folder to be in the project file system
   * somewhere, so we can't hide it in a system temp folder like the PDE does.
   */
  public IFolder getJavaBuildFolder() {
    try {
      IFolder preproc = getBuildFolder();
      if(preproc != null){
        IFolder parent = (IFolder) preproc.getParent();
        IFolder compile = parent.getFolder("compiler");
        if(!compile.exists())
          compile.create(IResource.NONE, true, null);
        return compile;
      }
    } catch (Exception e) {
      ProcessingCore.logError("Compiler folder could not be created.", e);
    }
    return null;
  }
 
  /**
   * Returns a handle to the project specific build folder or null if it doesn't exist
   * <p>
   * Users shouldn't be messing with this unless they know what they're doing.
   * Unfortunately, JDT requires the build folder to be in the project file system
   * somewhere, so we can't hide this in a system temp folder like the PDE does.
   */
  public IFolder getBuildFolder() {
    try {
      IFolder tempBuildFolder = project.getFolder("generated");
      if(!tempBuildFolder.exists())
        tempBuildFolder.create(IResource.NONE, true, null);
      IFolder preprocBuildFolder = tempBuildFolder.getFolder("preproc");
      if(!preprocBuildFolder.exists())
        preprocBuildFolder.create(IResource.NONE, true, null);
      return preprocBuildFolder;
    } catch (Exception e) {
      ProcessingCore.logError("Preproc folder could not be created.", e);
    }
    return null;
  }
 
  /**
   * Returns a handle to the main file for the sketch.
   * <p>
   * The main file being the *.pde file that shares the name of the sketch.
   * 
   */
  public IFile getMainFile() {
    IFile main = project.getFile(project.getName()+".pde");
    return (main.isAccessible()) ? main : null;
  }

  /**
   * Register a new set of class path entries from the provided source folder list and library jars.
   * This method completely replaces the old class path.
   *
   * @param srcFolderPathList A list of absolute paths to source folders
   * @param libraryJarPathList A list of absolute paths to source folders
   */
  public void updateClasspathEntries( IPath[] srcFolderPathList,  IPath[] libraryJarPathList) throws JavaModelException {
    IJavaProject jproject = this.getJavaProject();
   
    // Get a default VM to toss in the mix
    IPath containerPath = new Path(JavaRuntime.JRE_CONTAINER);
    IVMInstall vm = JavaRuntime.getDefaultVMInstall();
    IPath vmPath = containerPath.append(vm.getVMInstallType().getId()).append(vm.getName());

    // Duplicate entries cause errors, so prep them with a set
    HashSet<IClasspathEntry> entries = new HashSet<IClasspathEntry>();
   
    // VM
    entries.add(JavaCore.newContainerEntry(vmPath.makeAbsolute())); // JVM
   
    // Processing Libraries
    IPath plibs = new Path(ProcessingCore.getCore().getCoreJarFile().getAbsolutePath());
    entries.add(JavaCore.newLibraryEntry( plibs, null, null, false ));
   
    // if we were given a list of source folders, add them to the list
    // this should include the build folder and the code folder, if it was necessary
    if(srcFolderPathList != null){
      for( IPath p : srcFolderPathList){
        if (p!=null){
//          System.out.println(p.toOSString());
          entries.add(JavaCore.newSourceEntry(p.makeAbsolute()));
        }
      }
    }
   
    if(libraryJarPathList != null){
      for(IPath p : libraryJarPathList){
        if (p != null){
//          System.out.println(p.toString());
          entries.add(
            JavaCore.newLibraryEntry(p.makeAbsolute(),
              null, // no source
              null, // no source
              false // not exported
            )
          );
        }
      }
    }

    // things are added in no particular order   
    IClasspathEntry[] classpathEntries = new IClasspathEntry[entries.size()];
   
    int i = 0;
    for (IClasspathEntry cpe : entries){
      classpathEntries[i++] = cpe;
//      System.out.println(cpe.toString());
    }
   
//    for(IClasspathEntry cpe : entries){
//      try{
//        //System.out.println("Trying: " + cpe.toString());
//        jproject.setRawClasspath(new IClasspathEntry[] {cpe}, null);
//      } catch (Exception e){
//        System.out.println("It was broken. Ugh.");
//      }
//    }   
   
    jproject.setOutputLocation( getJavaBuildFolder().getFullPath(), null);
    jproject.setRawClasspath(classpathEntries, null);
//    jproject.setRawClasspath(new IClasspathEntry[0], null);
   
    ignoreWarnings();
  }
 
  /**
   * Sets the Java options to ignore all of the warnings because the Processing build chain
   * doesn't acknowledge or deal with compiler warnings.
   * <p>
   * Unlike the batch compiler, the JavaCore has no direct way of passing something simple,
   * like -nowarn, so each preference that could set a warning is explicitly set to ignore.
   * If there is a way to simplify this, please file a bug and suggest a fix!
   */
  public void ignoreWarnings() {
    Hashtable options = JavaCore.getOptions();
    options.put(JavaCore.COMPILER_PB_ANNOTATION_SUPER_INTERFACE, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_AUTOBOXING, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_CHAR_ARRAY_IN_STRING_CONCATENATION, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_DEPRECATION, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_EMPTY_STATEMENT, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_ENUM_IDENTIFIER, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_FALLTHROUGH_CASE, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_FIELD_HIDING, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_FINAL_PARAMETER_BOUND, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_FINALLY_BLOCK_NOT_COMPLETING, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_HIDDEN_CATCH_BLOCK, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_INCOMPATIBLE_NON_INHERITED_INTERFACE_METHOD, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_INCOMPLETE_ENUM_SWITCH, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_INDIRECT_STATIC_ACCESS, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_INVALID_JAVADOC, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_INVALID_JAVADOC_TAGS, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_INVALID_JAVADOC_TAGS__DEPRECATED_REF, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_LOCAL_VARIABLE_HIDING, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_METHOD_WITH_CONSTRUCTOR_NAME, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_MISSING_DEPRECATED_ANNOTATION, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_MISSING_JAVADOC_COMMENTS, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_MISSING_JAVADOC_TAGS, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_MISSING_JAVADOC_TAGS_VISIBILITY, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_MISSING_OVERRIDE_ANNOTATION, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_MISSING_SERIAL_VERSION, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_NO_EFFECT_ASSIGNMENT, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_NON_NLS_STRING_LITERAL, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_NULL_REFERENCE, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_OVERRIDING_PACKAGE_DEFAULT_METHOD, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_PARAMETER_ASSIGNMENT, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_POSSIBLE_ACCIDENTAL_BOOLEAN_ASSIGNMENT, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_RAW_TYPE_REFERENCE, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_SPECIAL_PARAMETER_HIDING_FIELD, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_STATIC_ACCESS_RECEIVER, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_SUPPRESS_WARNINGS, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_SYNTHETIC_ACCESS_EMULATION, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_TYPE_PARAMETER_HIDING, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNCHECKED_TYPE_OPERATION, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNDOCUMENTED_EMPTY_BLOCK, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNHANDLED_WARNING_TOKEN, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNNECESSARY_ELSE, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNNECESSARY_TYPE_CHECK, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNQUALIFIED_FIELD_ACCESS, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNUSED_DECLARED_THROWN_EXCEPTION, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNUSED_LABEL, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNUSED_DECLARED_THROWN_EXCEPTION_WHEN_OVERRIDING, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNUSED_IMPORT, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNUSED_LOCAL, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNUSED_PARAMETER, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNUSED_PARAMETER_WHEN_IMPLEMENTING_ABSTRACT, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNUSED_PARAMETER_WHEN_OVERRIDING_CONCRETE, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNUSED_PARAMETER_INCLUDE_DOC_COMMENT_REFERENCE, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_UNUSED_PRIVATE_MEMBER, JavaCore.IGNORE);
    options.put(JavaCore.COMPILER_PB_VARARGS_ARGUMENT_NEED_CAST, JavaCore.IGNORE);
    // its finally over! yeah!
   
    JavaCore.setOptions(options)
  }

  /** Getter for classes outside of this package */
  public boolean wasLastBuildSuccessful() {
    return wasLastBuildSuccessful;
  }
 
  public String getRenderer() {
    return renderer;
  }
 
  /** Return the sketch's height, or the default height if size() has not been specified */
  public int getHeight() {
    return (sketch_height == -1) ? DEFAULT_HEIGHT : sketch_height;
  }
 
  /** Return the sketch's width, or the default width if size() has not been specified */
  public int getWidth() {
    return (sketch_width == -1) ? DEFAULT_WIDTH : sketch_width;
  }

  /** Returns the name of the main type of the compiled sketch*/
  public String getMainType() {
    return project.getName();
  }
 
  public ArrayList<IPath> getLibraryPaths() {
    return libraryPaths;
  }
   
}
TOP

Related Classes of processing.plugin.core.builder.SketchProject

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.