--- a/apisupport.project/nbproject/project.xml +++ a/apisupport.project/nbproject/project.xml @@ -196,7 +196,7 @@ 1 - 1.21 + 1.28 --- a/apisupport.project/src/org/netbeans/modules/apisupport/project/NbModuleProjectType.java +++ a/apisupport.project/src/org/netbeans/modules/apisupport/project/NbModuleProjectType.java @@ -42,16 +42,18 @@ package org.netbeans.modules.apisupport.project; import java.io.IOException; +import javax.swing.Icon; import org.netbeans.api.project.Project; -import org.netbeans.spi.project.support.ant.AntBasedProjectType; +import org.netbeans.spi.project.support.ant.AntBasedProjectType2; import org.netbeans.spi.project.support.ant.AntProjectHelper; +import org.openide.util.ImageUtilities; /** * Factory for NetBeans module projects. * @author Jesse Glick */ @org.openide.util.lookup.ServiceProvider(service=org.netbeans.spi.project.support.ant.AntBasedProjectType.class) -public final class NbModuleProjectType implements AntBasedProjectType { +public final class NbModuleProjectType implements AntBasedProjectType2 { static final String TYPE = "org.netbeans.modules.apisupport.project"; // NOI18N static final String NAME_SHARED = "data"; // NOI18N @@ -78,5 +80,9 @@ public String getPrimaryConfigurationDataElementNamespace(boolean shared) { return shared ? NAMESPACE_SHARED : NAMESPACE_PRIVATE; } + + public Icon getIcon() { + return ImageUtilities.image2Icon(ImageUtilities.loadImage("org/netbeans/modules/apisupport/project/resources/module.png", true)); + } } --- a/apisupport.project/src/org/netbeans/modules/apisupport/project/suite/SuiteProjectType.java +++ a/apisupport.project/src/org/netbeans/modules/apisupport/project/suite/SuiteProjectType.java @@ -42,16 +42,18 @@ package org.netbeans.modules.apisupport.project.suite; import java.io.IOException; +import javax.swing.Icon; import org.netbeans.api.project.Project; -import org.netbeans.spi.project.support.ant.AntBasedProjectType; +import org.netbeans.spi.project.support.ant.AntBasedProjectType2; import org.netbeans.spi.project.support.ant.AntProjectHelper; +import org.openide.util.ImageUtilities; /** * Factory for NetBeans module suite projects. * @author Jesse Glick */ @org.openide.util.lookup.ServiceProvider(service=org.netbeans.spi.project.support.ant.AntBasedProjectType.class) -public final class SuiteProjectType implements AntBasedProjectType { +public final class SuiteProjectType implements AntBasedProjectType2 { public static final String TYPE = "org.netbeans.modules.apisupport.project.suite"; // NOI18N static final String NAME_SHARED = "data"; // NOI18N @@ -77,5 +79,9 @@ public String getPrimaryConfigurationDataElementNamespace(boolean shared) { return shared ? NAMESPACE_SHARED : NAMESPACE_PRIVATE; } + + public Icon getIcon() { + return ImageUtilities.image2Icon(ImageUtilities.loadImage("org/netbeans/modules/apisupport/project/suite/resources/suite.png", true)); + } } --- a/java.j2seproject/nbproject/project.xml +++ a/java.j2seproject/nbproject/project.xml @@ -180,7 +180,7 @@ 1 - 1.26 + 1.28 --- a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProjectType.java +++ a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProjectType.java @@ -42,16 +42,18 @@ package org.netbeans.modules.java.j2seproject; import java.io.IOException; +import javax.swing.Icon; import org.netbeans.api.project.Project; -import org.netbeans.spi.project.support.ant.AntBasedProjectType; +import org.netbeans.spi.project.support.ant.AntBasedProjectType2; import org.netbeans.spi.project.support.ant.AntProjectHelper; +import org.openide.util.ImageUtilities; /** * Factory for simple J2SE projects. * @author Jesse Glick */ @org.openide.util.lookup.ServiceProvider(service=org.netbeans.spi.project.support.ant.AntBasedProjectType.class) -public final class J2SEProjectType implements AntBasedProjectType { +public final class J2SEProjectType implements AntBasedProjectType2 { public static final String TYPE = "org.netbeans.modules.java.j2seproject"; // NOI18N private static final String PROJECT_CONFIGURATION_NAME = "data"; // NOI18N @@ -77,5 +79,9 @@ public String getPrimaryConfigurationDataElementNamespace(boolean shared) { return shared ? PROJECT_CONFIGURATION_NAMESPACE : PRIVATE_CONFIGURATION_NAMESPACE; } + + public Icon getIcon() { + return ImageUtilities.image2Icon(ImageUtilities.loadImage("org/netbeans/modules/java/j2seproject/ui/resources/j2seProject.png", true)); + } } --- a/maven.spring/src/org/netbeans/modules/maven/spring/layer.xml +++ a/maven.spring/src/org/netbeans/modules/maven/spring/layer.xml @@ -52,5 +52,4 @@ - --- a/maven/nbproject/project.xml +++ a/maven/nbproject/project.xml @@ -194,7 +194,7 @@ 1 - 1.18 + 1.22 --- a/maven/src/org/netbeans/modules/maven/NbMavenProjectFactory.java +++ a/maven/src/org/netbeans/modules/maven/NbMavenProjectFactory.java @@ -43,11 +43,13 @@ import java.io.File; import java.io.IOException; import org.netbeans.api.project.Project; -import org.netbeans.spi.project.ProjectFactory; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.spi.project.ProjectFactory2; import org.netbeans.spi.project.ProjectState; import org.openide.ErrorManager; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; +import org.openide.util.ImageUtilities; /** @@ -55,7 +57,7 @@ * @author Milos Kleint */ @org.openide.util.lookup.ServiceProvider(service=org.netbeans.spi.project.ProjectFactory.class, position=666) -public class NbMavenProjectFactory implements ProjectFactory { +public class NbMavenProjectFactory implements ProjectFactory2 { /** Creates a new instance of NbMavenProjectFactory */ public NbMavenProjectFactory() { @@ -76,6 +78,14 @@ } return project.isFile() && !"nbproject".equalsIgnoreCase(projectDir.getName()); //NOI18N } + + public ProjectManager.Result isProject2(FileObject projectDirectory) { + if (isProject(projectDirectory)) { + return new ProjectManager.Result(ImageUtilities.image2Icon(ImageUtilities.loadImage("org/netbeans/modules/maven/Maven2Icon.gif", true))); //NOI18N + } + return null; + } + public Project loadProject(FileObject fileObject, ProjectState projectState) throws IOException { @@ -110,7 +120,5 @@ public void saveProject(Project project) throws IOException { // what to do here?? - } - - + } } --- a/project.ant/apichanges.xml +++ a/project.ant/apichanges.xml @@ -104,6 +104,25 @@ + + + + Provide project icon without actually loading the project type + + + + + +

+ Introducing AntBasedProjectType2 that extends AntBasedProjectType + and adds geticon() method to allow showing the icon without actually loading the + project. Related to org.netbeans.spi.project.ProjectFactory2 changes in the Project API module. +

+
+ + +
+ Added method SourcesHelper.registerExternalRoots with minimalSubfolders parameter --- a/project.ant/nbproject/project.xml +++ a/project.ant/nbproject/project.xml @@ -78,7 +78,7 @@ 1 - 1.17 + 1.22
--- a/project.ant/src/org/netbeans/modules/project/ant/AntBasedProjectFactorySingleton.java +++ a/project.ant/src/org/netbeans/modules/project/ant/AntBasedProjectFactorySingleton.java @@ -63,9 +63,13 @@ import java.util.prefs.Preferences; import java.util.zip.CRC32; import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.api.project.ProjectManager.Result; import org.netbeans.spi.project.ProjectFactory; +import org.netbeans.spi.project.ProjectFactory2; import org.netbeans.spi.project.ProjectState; import org.netbeans.spi.project.support.ant.AntBasedProjectType; +import org.netbeans.spi.project.support.ant.AntBasedProjectType2; import org.netbeans.spi.project.support.ant.AntProjectHelper; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; @@ -87,7 +91,7 @@ * @author Jesse Glick */ @org.openide.util.lookup.ServiceProvider(service=org.netbeans.spi.project.ProjectFactory.class, position=100) -public final class AntBasedProjectFactorySingleton implements ProjectFactory { +public final class AntBasedProjectFactorySingleton implements ProjectFactory2 { public static final String PROJECT_XML_PATH = "nbproject/project.xml"; // NOI18N @@ -159,6 +163,47 @@ File projectXmlF = new File(new File(dirF, "nbproject"), "project.xml"); // NOI18N return projectXmlF.isFile(); } + + public Result isProject2(FileObject projectDirectory) { + if (FileUtil.toFile(projectDirectory) == null) { + return null; + } + FileObject projectFile = projectDirectory.getFileObject(PROJECT_XML_PATH); + //#54488: Added check for virtual + if (projectFile == null || !projectFile.isData() || projectFile.isVirtual()) { + return null; + } + File projectDiskFile = FileUtil.toFile(projectFile); + //#63834: if projectFile exists and projectDiskFile does not, do nothing: + if (projectDiskFile == null) { + return null; + } + try { + Document projectXml = loadProjectXml(projectDiskFile); + if (projectXml != null) { + Element typeEl = Util.findElement(projectXml.getDocumentElement(), "type", PROJECT_NS); // NOI18N + if (typeEl != null) { + String type = Util.findText(typeEl); + if (type != null) { + AntBasedProjectType provider = findAntBasedProjectType(type); + if (provider != null) { + if (provider instanceof AntBasedProjectType2) { + return new ProjectManager.Result(((AntBasedProjectType2)provider).getIcon()); + } else { + //put special icon? + return new ProjectManager.Result(null); + } + } + } + } + } + } catch (IOException ex) { + Logger.getLogger(AntBasedProjectFactorySingleton.class.getName()).log(Level.FINE, "Failed to load the project.xml file.", ex); + } + // better have false positives than false negatives (according to the ProjectManager.isProject/isProject2 javadoc. + return new ProjectManager.Result(null); + } + public Project loadProject(FileObject projectDirectory, ProjectState state) throws IOException { if (FileUtil.toFile(projectDirectory) == null) { @@ -321,6 +366,7 @@ return helperRef != null ? helperRef.get() : null; } + /** * Callback to create and access AntProjectHelper objects from outside its package. */ --- a/project.ant/src/org/netbeans/spi/project/support/ant/AntBasedProjectType2.java +++ a/project.ant/src/org/netbeans/spi/project/support/ant/AntBasedProjectType2.java @@ -0,0 +1,60 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.spi.project.support.ant; + +import javax.swing.Icon; + +/** + * extension of {@link org.netbeans.spi.project.support.ant.AntBasedProjectType} + * that provides an icon for the project without actually creating an project instance for it. + * @author mkleint + * @since org.netbeans.modules.project.ant 1.28 + */ +public interface AntBasedProjectType2 extends AntBasedProjectType { + + /** + * icon of the project type represented by the given implementation of the interface. + * @return + */ + public Icon getIcon(); + +} --- a/projectapi/apichanges.xml +++ a/projectapi/apichanges.xml @@ -104,6 +104,26 @@ + + + + Provide project icon without actually loading the project + + + + + +

+ Introducing ProjectFactory2 that extends ProjectFactory + and return ProjectManager.Result instead of a simple boolean value. + Also add ProjectManager.isProject2(FileObject) method that can be used by + 3rd party modules that need a fast (yet not 100% reliable) way of finding the project icon for a folder. +

+
+ + + +
--- a/projectapi/manifest.mf +++ a/projectapi/manifest.mf @@ -1,7 +1,7 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.projectapi/1 OpenIDE-Module-Install: org/netbeans/modules/projectapi/Installer.class -OpenIDE-Module-Specification-Version: 1.21 +OpenIDE-Module-Specification-Version: 1.22 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/projectapi/Bundle.properties OpenIDE-Module-Layer: org/netbeans/modules/projectapi/layer.xml --- a/projectapi/src/org/netbeans/api/project/ProjectManager.java +++ a/projectapi/src/org/netbeans/api/project/ProjectManager.java @@ -50,21 +50,22 @@ import java.util.Map; import java.util.Set; import java.util.WeakHashMap; -import java.util.concurrent.Executor; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; +import javax.swing.Icon; import org.netbeans.modules.projectapi.SimpleFileOwnerQueryImplementation; import org.netbeans.modules.projectapi.TimedWeakReference; import org.netbeans.spi.project.FileOwnerQueryImplementation; import org.netbeans.spi.project.ProjectFactory; +import org.netbeans.spi.project.ProjectFactory2; import org.netbeans.spi.project.ProjectState; import org.openide.filesystems.FileChangeAdapter; import org.openide.filesystems.FileChangeListener; import org.openide.filesystems.FileEvent; import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileSystem; import org.openide.filesystems.FileUtil; +import org.openide.util.ImageUtilities; import org.openide.util.Lookup; import org.openide.util.LookupEvent; import org.openide.util.LookupListener; @@ -388,6 +389,37 @@ * @throws IllegalArgumentException if the supplied file object is null or not a folder */ public boolean isProject(final FileObject projectDirectory) throws IllegalArgumentException { + return isProject2(projectDirectory, false) != null; + } + + /** + * Check whether a given directory is likely to contain a project without + * actually loading it. The returned {@link org.netbeans.api.project.ProjectManager.Result} object contains additional + * information about the found project. + * Should be faster and use less memory than {@link #findProject} when called + * on a large number of directories. + *

The result is not guaranteed to be accurate; there may be false positives + * (directories for which isProject is true but {@link #findProject} + * will return false), for example if there is trouble loading the project. + * False negatives are possible only if there are bugs in the project factory.

+ *

Acquires read access.

+ *

+ * You do not need to call this method if you just plan to call {@link #findProject} + * afterwards. It is intended for only those clients which would discard the + * result of {@link #findProject} other than to check for null, and which + * can also tolerate false positives. + *

+ * @param projectDirectory a directory which may be some project's top directory + * @return Result object if the directory is likely to contain a project according to + * some registered {@link ProjectFactory}, or null if not a project folder. + * @throws IllegalArgumentException if the supplied file object is null or not a folder + * @since org.netbeans.modules.projectapi 1.22 + */ + public Result isProject2(final FileObject projectDirectory) throws IllegalArgumentException { + return isProject2(projectDirectory, true); + } + + private Result isProject2(final FileObject projectDirectory, final boolean preferResult) throws IllegalArgumentException { if (projectDirectory == null) { throw new IllegalArgumentException("Attempted to pass a null directory to isProject"); // NOI18N } @@ -397,11 +429,11 @@ if (projectDirectory.isValid()) { throw new IllegalArgumentException("Attempted to pass a non-directory to isProject: " + projectDirectory); // NOI18N } else { - return false; + return null; } } - return mutex().readAccess(new Mutex.Action() { - public Boolean run() { + return mutex().readAccess(new Mutex.Action() { + public Result run() { synchronized (dir2Proj) { Union2,LoadStatus> o; do { @@ -416,26 +448,27 @@ } while (LoadStatus.LOADING_PROJECT.is(o)); assert !LoadStatus.LOADING_PROJECT.is(o); if (LoadStatus.NO_SUCH_PROJECT.is(o)) { - return false; + return null; } else if (o != null) { // Reference or SOME_SUCH_PROJECT - return true; + // rather check for result than load project and lookup projectInformation for icon. + return checkForProject(projectDirectory, preferResult); } // Not in cache. dir2Proj.put(projectDirectory, LoadStatus.LOADING_PROJECT.wrap()); } boolean resetLP = false; try { - boolean p = checkForProject(projectDirectory); + Result p = checkForProject(projectDirectory, preferResult); synchronized (dir2Proj) { resetLP = true; dir2Proj.notifyAll(); - if (p) { + if (p != null) { dir2Proj.put(projectDirectory, LoadStatus.SOME_SUCH_PROJECT.wrap()); - return true; + return p; } else { dir2Proj.put(projectDirectory, LoadStatus.NO_SUCH_PROJECT.wrap()); - return false; + return null; } } } finally { @@ -448,19 +481,33 @@ } }); } - - private boolean checkForProject(FileObject dir) { + + /** + * + * @param dir + * @param preferResult, if false will not actually call the factory methods with populated Results, but + * create dummy ones and use the Result as boolean flag only. + * @return + */ + private Result checkForProject(FileObject dir, boolean preferResult) { assert dir != null; assert dir.isFolder() : dir; assert mutex().isReadAccess(); - Iterator it = factories.allInstances().iterator(); + Iterator it = factories.allInstances().iterator(); while (it.hasNext()) { - ProjectFactory factory = (ProjectFactory)it.next(); - if (factory.isProject(dir)) { - return true; + ProjectFactory factory = it.next(); + if (factory instanceof ProjectFactory2 && preferResult) { + Result res = ((ProjectFactory2)factory).isProject2(dir); + if (res != null) { + return res; + } + } else { + if (factory.isProject(dir)) { + return new Result((Icon)null); + } } } - return false; + return null; } /** @@ -671,5 +718,28 @@ } } + + /** + * A result (immutable) object returned from {@link org.netbeans.api.project.ProjectManager#isProject2} method. + * To be created by {@link org.netbeans.spi.project.ProjectFactory2} project factories. + * @since org.netbeans.modules.projectapi 1.22 + */ + public static final class Result { + private Icon icon; + + + public Result(Icon icon) { + this.icon = icon; + } + + /** + * Get the project icon. + * @return project type icon for the result or null if the icon cannot be found this way. + */ + public Icon getIcon() { + return icon; + } + } + } --- a/projectapi/src/org/netbeans/spi/project/ProjectFactory2.java +++ a/projectapi/src/org/netbeans/spi/project/ProjectFactory2.java @@ -0,0 +1,69 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2008 Sun Microsystems, Inc. + */ + +package org.netbeans.spi.project; + +import org.netbeans.api.project.ProjectManager; +import org.openide.filesystems.FileObject; + +/** + * Create in-memory projects from disk directories. + * Instances should be registered into default lookup as ProjectFactory instances. + * @author mkleint + * @since org.netbeans.modules.projectapi 1.22 + * + */ +public interface ProjectFactory2 extends ProjectFactory { + + /** + * Test whether a given directory probably refers to a project recognized by this factory + * without actually trying to create it. + *

Should be as fast as possible as it might be called sequentially on a + * lot of directories.

+ *

Need not be definite; it is permitted to return null or throw an exception + * from {@link #loadProject} even when returning Result instance from this + * method, in case the directory looked like a project directory but in fact + * had something wrong with it.

+ *

Will be called inside read access.

+ * @param projectDirectory a directory which might refer to a project + * @return Result instance if this factory recognizes it, or null if the directory is not recognized + */ + ProjectManager.Result isProject2(FileObject projectDirectory); + +} --- a/projectui/src/org/netbeans/modules/project/ui/ProjectChooserAccessory.java +++ a/projectui/src/org/netbeans/modules/project/ui/ProjectChooserAccessory.java @@ -388,6 +388,16 @@ return OpenProjectList.fileToProject( dir ); } + private static ProjectManager.Result getProjectResult(File dir) { + FileObject fo = FileUtil.toFileObject(dir); + if (fo != null && /* #60518 */ fo.isFolder()) { + return ProjectManager.getDefault().isProject2(fo); + } else { + return null; + } + + } + private void setAccessoryEnablement( boolean enable, int numberOfProjects ) { jLabelProjectName.setEnabled( enable ); jTextFieldProjectName.setEnabled( enable ); @@ -606,10 +616,19 @@ } public void run() { - Project p = OpenProjectList.fileToProject(lookingForIcon); + ProjectManager.Result r = getProjectResult(lookingForIcon); Icon icon; - if (p != null) { - icon = ProjectUtils.getInformation(p).getIcon(); + if (r != null) { + icon = r.getIcon(); + if (icon == null) { + Project p = getProject(lookingForIcon); + if (p != null) { + icon = ProjectUtils.getInformation(p).getIcon(); + } else { + // Could also badge with an error icon: + icon = chooser.getFileSystemView().getSystemIcon(lookingForIcon); + } + } } else { // Could also badge with an error icon: icon = chooser.getFileSystemView().getSystemIcon(lookingForIcon); --- a/projectui/src/org/netbeans/modules/project/ui/actions/OpenProject.java +++ a/projectui/src/org/netbeans/modules/project/ui/actions/OpenProject.java @@ -49,7 +49,6 @@ import javax.swing.SwingUtilities; import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; -import org.netbeans.api.project.ui.OpenProjects; import org.netbeans.modules.project.ui.OpenProjectList; import org.netbeans.modules.project.ui.OpenProjectListSettings; import org.netbeans.modules.project.ui.ProjectChooserAccessory; --- a/web.project/src/org/netbeans/modules/web/project/WebProjectType.java +++ a/web.project/src/org/netbeans/modules/web/project/WebProjectType.java @@ -43,14 +43,16 @@ import java.io.IOException; import java.util.Collection; +import javax.swing.Icon; import org.netbeans.api.project.Project; import org.netbeans.modules.web.project.spi.WebProjectImplementationFactory; -import org.netbeans.spi.project.support.ant.AntBasedProjectType; +import org.netbeans.spi.project.support.ant.AntBasedProjectType2; import org.netbeans.spi.project.support.ant.AntProjectHelper; +import org.openide.util.ImageUtilities; import org.openide.util.Lookup; @org.openide.util.lookup.ServiceProvider(service=org.netbeans.spi.project.support.ant.AntBasedProjectType.class) -public final class WebProjectType implements AntBasedProjectType { +public final class WebProjectType implements AntBasedProjectType2 { public static final String TYPE = "org.netbeans.modules.web.project"; private static final String PROJECT_CONFIGURATION_NAME = "data"; @@ -91,4 +93,8 @@ private Collection getProjectFactories() { return Lookup.getDefault().lookupAll(WebProjectImplementationFactory.class); } + + public Icon getIcon() { + return ImageUtilities.image2Icon(ImageUtilities.loadImage("org/netbeans/modules/web/project/ui/resources/webProjectIcon.gif", true)); + } }