diff --git a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java --- a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java +++ b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java @@ -294,6 +294,7 @@ FileEncodingQueryImplementation encodingQuery = QuerySupport.createFileEncodingQuery(evaluator(), J2SEProjectProperties.SOURCE_ENCODING); @SuppressWarnings("deprecation") Object cpe = new org.netbeans.modules.java.api.common.classpath.ClassPathExtender( cpMod, ProjectProperties.JAVAC_CLASSPATH, null); + J2SESources srcs = new J2SESources(this, helper, eval, getSourceRoots(), getTestSourceRoots()); final Lookup base = Lookups.fixed( J2SEProject.this, new Info(), @@ -313,7 +314,8 @@ UILookupMergerSupport.createProjectOpenHookMerger(new ProjectOpenedHookImpl()), QuerySupport.createUnitTestForSourceQuery(getSourceRoots(), getTestSourceRoots()), QuerySupport.createSourceLevelQuery(evaluator()), - new J2SESources(this, helper, evaluator(), getSourceRoots(), getTestSourceRoots()), + srcs, + srcs.getSourceGroupModifierImplementation(), QuerySupport.createSharabilityQuery(helper, evaluator(), getSourceRoots(), getTestSourceRoots()), new CoSAwareFileBuiltQueryImpl(QuerySupport.createFileBuiltQuery(helper, evaluator(), getSourceRoots(), getTestSourceRoots()), this), new RecommendedTemplatesImpl (this.updateHelper), diff --git a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SESources.java b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SESources.java --- a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SESources.java +++ b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SESources.java @@ -56,6 +56,7 @@ import org.netbeans.api.project.Project; import org.netbeans.modules.java.api.common.SourceRoots; import org.netbeans.modules.java.api.common.project.ProjectProperties; +import org.netbeans.spi.project.SourceGroupModifierImplementation; import org.netbeans.spi.project.support.GenericSources; import org.netbeans.spi.project.support.ant.SourcesHelper; import org.netbeans.spi.project.support.ant.AntProjectHelper; @@ -81,6 +82,7 @@ private boolean dirty; private Sources delegate; private final ChangeSupport changeSupport = new ChangeSupport(this); + private SourceGroupModifierImplementation sgmi; J2SESources(Project project, AntProjectHelper helper, PropertyEvaluator evaluator, SourceRoots sourceRoots, SourceRoots testRoots) { @@ -151,18 +153,24 @@ } return null; } + + SourceGroupModifierImplementation getSourceGroupModifierImplementation() { + return sgmi; + } private Sources initSources() { - SourcesHelper sourcesHelper = new SourcesHelper(project, helper, evaluator); //Safe to pass APH - register(sourcesHelper, sourceRoots); - register(sourcesHelper, testRoots); + final SourcesHelper sourcesHelper = new SourcesHelper(project, helper, evaluator); //Safe to pass APH + register(sourcesHelper, sourceRoots, JavaProjectConstants.SOURCES_HINT_MAIN); + register(sourcesHelper, testRoots, JavaProjectConstants.SOURCES_HINT_TEST); sourcesHelper.addNonSourceRoot(BUILD_DIR_PROP); sourcesHelper.addNonSourceRoot(DIST_DIR_PROP); sourcesHelper.registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT, false); - return sourcesHelper.createSources(); + final Sources srcs = sourcesHelper.createSources(); + sgmi = sourcesHelper.createSourceGroupModifierImplementation(srcs); + return srcs; } - private void register(SourcesHelper sourcesHelper, SourceRoots roots) { + private void register(SourcesHelper sourcesHelper, SourceRoots roots, String hint) { String[] propNames = roots.getRootProperties(); String[] rootNames = roots.getRootNames(); for (int i = 0; i < propNames.length; i++) { @@ -171,8 +179,8 @@ String loc = "${" + prop + "}"; // NOI18N String includes = "${" + ProjectProperties.INCLUDES + "}"; // NOI18N String excludes = "${" + ProjectProperties.EXCLUDES + "}"; // NOI18N - sourcesHelper.addPrincipalSourceRoot(loc, includes, excludes, displayName, null, null); // NOI18N - sourcesHelper.addTypedSourceRoot(loc, includes, excludes, JavaProjectConstants.SOURCES_TYPE_JAVA, displayName, null, null); // NOI18N + sourcesHelper.addPrincipalSourceRoot(loc, includes, excludes, hint, displayName, null, null); // NOI18N + sourcesHelper.addTypedSourceRoot(loc, includes, excludes, JavaProjectConstants.SOURCES_TYPE_JAVA, hint, displayName, null, null); // NOI18N } } @@ -193,7 +201,9 @@ public void propertyChange(PropertyChangeEvent evt) { String propName = evt.getPropertyName(); - if (SourceRoots.PROP_ROOT_PROPERTIES.equals(propName) || + // was listening to PROP_ROOT_PROPERTIES, changed to PROP_ROOTS in #143633 as changes + // from SourceGroupModifierImplementation need refresh too + if (SourceRoots.PROP_ROOTS.equals(propName) || J2SEProjectProperties.BUILD_DIR.equals(propName) || J2SEProjectProperties.DIST_DIR.equals(propName)) { this.fireChange(); diff --git a/project.ant/apichanges.xml b/project.ant/apichanges.xml --- a/project.ant/apichanges.xml +++ b/project.ant/apichanges.xml @@ -104,6 +104,25 @@ + + + + Added SourceGroupModifierImplementation implementation for Ant-based projects + + + + + +

+ Added method SourcesHelper.createSourceGroupModifierImplementation creating SourceGroupModifierImplementation + implementation for Ant-based projects. Also added new versions of SourcesHelper.addPrincipalSourceRoot + and SourcesHelper.addTypedSourceRoot with additional parameter hint, which is required + for the implementation to work. +

+
+ + +
diff --git a/project.ant/manifest.mf b/project.ant/manifest.mf --- a/project.ant/manifest.mf +++ b/project.ant/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.project.ant/1 -OpenIDE-Module-Specification-Version: 1.32 +OpenIDE-Module-Specification-Version: 1.33 OpenIDE-Module-Layer: org/netbeans/modules/project/ant/resources/mf-layer.xml OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/project/ant/Bundle.properties OpenIDE-Module-Install: org/netbeans/modules/project/ant/AntProjectModule.class diff --git a/project.ant/src/org/netbeans/spi/project/support/ant/SourcesHelper.java b/project.ant/src/org/netbeans/spi/project/support/ant/SourcesHelper.java --- a/project.ant/src/org/netbeans/spi/project/support/ant/SourcesHelper.java +++ b/project.ant/src/org/netbeans/spi/project/support/ant/SourcesHelper.java @@ -57,6 +57,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.Icon; import javax.swing.event.ChangeListener; import org.netbeans.api.project.FileOwnerQuery; @@ -64,9 +66,11 @@ import org.netbeans.api.project.ProjectManager; import org.netbeans.api.project.ProjectUtils; import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.SourceGroupModifier; import org.netbeans.api.project.Sources; import org.netbeans.api.queries.SharabilityQuery; import org.netbeans.modules.project.ant.AntBasedProjectFactorySingleton; +import org.netbeans.spi.project.SourceGroupModifierImplementation; import org.openide.filesystems.FileAttributeEvent; import org.openide.filesystems.FileChangeListener; import org.openide.filesystems.FileEvent; @@ -75,6 +79,7 @@ import org.openide.filesystems.FileStateInvalidException; import org.openide.filesystems.FileUtil; import org.openide.util.ChangeSupport; +import org.openide.util.Exceptions; import org.openide.util.Parameters; import org.openide.util.WeakListeners; @@ -125,19 +130,31 @@ private final Icon openedIcon; private final String includes; private final String excludes; + private final String hint; + private boolean removed; // just for sanity checking - public SourceRoot(String location, String includes, String excludes, String displayName, Icon icon, Icon openedIcon) { + public SourceRoot(String location, String includes, String excludes, String hint, String displayName, Icon icon, Icon openedIcon) { super(location); this.displayName = displayName; this.icon = icon; this.openedIcon = openedIcon; this.includes = includes; this.excludes = excludes; + this.hint = hint; + removed = false; } public final SourceGroup toGroup(FileObject loc) { assert loc != null; return new Group(loc); + } + + public String getHint() { + return hint; + } + + public boolean isRemoved() { + return removed; } @Override @@ -291,8 +308,8 @@ private final class TypedSourceRoot extends SourceRoot { private final String type; - public TypedSourceRoot(String type, String location, String includes, String excludes, String displayName, Icon icon, Icon openedIcon) { - super(location, includes, excludes, displayName, icon, openedIcon); + public TypedSourceRoot(String type, String hint, String location, String includes, String excludes, String displayName, Icon icon, Icon openedIcon) { + super(location, includes, excludes, hint, displayName, icon, openedIcon); this.type = type; } public final String getType() { @@ -371,6 +388,9 @@ addPrincipalSourceRoot(location, null, null, displayName, icon, openedIcon); } + // no code hint for source root, group cannot be created from it via SourceGroupModifier + private static final String HINT_NONE = "none"; + /** * Add a possible principal source root, or top-level folder which may * contain sources that should be considered part of the project, with @@ -409,9 +429,89 @@ if (lastRegisteredRoots != null) { throw new IllegalStateException("registerExternalRoots was already called"); // NOI18N } - principalSourceRoots.add(new SourceRoot(location, includes, excludes, displayName, icon, openedIcon)); + principalSourceRoots.add(new SourceRoot(location, includes, excludes, HINT_NONE, displayName, icon, openedIcon)); } - + + /** + * Add a possible principal source root, or top-level folder which may + * contain sources that should be considered part of the project. + *

+ * If the actual value of the location is inside the project directory, + * this is simply ignored; so it safe to configure principal source roots + * for any source directory which might be set to use an external path, even + * if the common location is internal. + *

+ * Location need not to exist physically, when hint is specified + * and {@link SourceGroupModifier} created by this helper is added to project + * lookup, source root can be created on demand. + *

+ * @param location a project-relative or absolute path giving the location + * of a source tree; may contain Ant property substitutions + * @param hint Hint for {@link SourceGroupModifier} allowing creation of this + * source root on demand + * @param displayName a display name (for {@link SourceGroup#getDisplayName}) + * @param icon a regular icon for the source root, or null + * @param openedIcon an opened variant icon for the source root, or null + * @throws IllegalStateException if this method is called after either + * {@link #createSources} or {@link #registerExternalRoots} + * was called + * @see #registerExternalRoots + * @see Sources#TYPE_GENERIC + * @see #createSourceGroupModifierImplementation() + * @since org.netbeans.modules.project.ant/1 1.33 + */ + public void addPrincipalSourceRoot(String location, String hint, String displayName, Icon icon, Icon openedIcon) throws IllegalStateException { + addPrincipalSourceRoot(location, null, null, hint, displayName, icon, openedIcon); + } + + /** + * Add a possible principal source root, or top-level folder which may + * contain sources that should be considered part of the project, with + * optional include and exclude lists. + *

+ * If an include or exclude string is given as null, then it is skipped. A non-null value is + * evaluated and then treated as a comma- or space-separated pattern list, + * as detailed in the Javadoc for {@link PathMatcher}. + * (As a special convenience, a value consisting solely of an Ant property reference + * which cannot be evaluated, e.g. ${undefined}, is treated like null.) + * {@link SourceGroup#contains} will then reflect the includes and excludes for files, but note that the + * semantics of that method requires that a folder be "contained" in case any folder or file + * beneath it is contained, and in particular the root folder is always contained. + *

+ * Location need not to exist physically, when hint is specified + * and {@link SourceGroupModifier} created by this helper is added to project + * lookup, source root can be created on demand. + *

+ * @param location a project-relative or absolute path giving the location + * of a source tree; may contain Ant property substitutions + * @param includes Ant-style includes; may contain Ant property substitutions; + * if not null, only files and folders + * matching the pattern (or patterns), and not specified in the excludes list, + * will be {@link SourceGroup#contains included} + * @param excludes Ant-style excludes; may contain Ant property substitutions; + * if not null, files and folders + * matching the pattern (or patterns) will not be {@link SourceGroup#contains included}, + * even if specified in the includes list + * @param hint Hint for {@link SourceGroupModifier} allowing creation of this + * source root on demand + * @param displayName a display name (for {@link SourceGroup#getDisplayName}) + * @param icon a regular icon for the source root, or null + * @param openedIcon an opened variant icon for the source root, or null + * @throws IllegalStateException if this method is called after either + * {@link #createSources} or {@link #registerExternalRoots} + * was called + * @see #registerExternalRoots + * @see Sources#TYPE_GENERIC + * @see #createSourceGroupModifierImplementation() + * @since org.netbeans.modules.project.ant/1 1.33 + */ + public void addPrincipalSourceRoot(String location, String includes, String excludes, String hint, String displayName, Icon icon, Icon openedIcon) throws IllegalStateException { + if (lastRegisteredRoots != null) { + throw new IllegalStateException("registerExternalRoots was already called"); // NOI18N + } + principalSourceRoots.add(new SourceRoot(location, includes, excludes, hint, displayName, icon, openedIcon)); + } + /** * Similar to {@link #addPrincipalSourceRoot} but affects only * {@link #registerExternalRoots} and not {@link #createSources}. @@ -493,7 +593,64 @@ if (lastRegisteredRoots != null) { throw new IllegalStateException("registerExternalRoots was already called"); // NOI18N } - typedSourceRoots.add(new TypedSourceRoot(type, location, includes, excludes, displayName, icon, openedIcon)); + typedSourceRoots.add(new TypedSourceRoot(type, HINT_NONE, location, includes, excludes, displayName, icon, openedIcon)); + } + + /** + * Add a typed source root which will be considered only in certain contexts. + *

+ * Location need not to exist physically, when hint is specified + * and {@link SourceGroupModifier} created by this helper is added to project + * lookup, source root can be created on demand. + *

+ * @param location a project-relative or absolute path giving the location + * of a source tree; may contain Ant property substitutions + * @param type a source root type such as JavaProjectConstants.SOURCES_TYPE_JAVA + * @param hint Hint for {@link SourceGroupModifier} allowing creation of this + * source root on demand + * @param displayName a display name (for {@link SourceGroup#getDisplayName}) + * @param icon a regular icon for the source root, or null + * @param openedIcon an opened variant icon for the source root, or null + * @throws IllegalStateException if this method is called after either + * {@link #createSources} or {@link #registerExternalRoots} + * was called + * @see #createSourceGroupModifierImplementation() + * @since org.netbeans.modules.project.ant/1 1.33 + */ + public void addTypedSourceRoot(String location, String type, String hint, String displayName, Icon icon, Icon openedIcon) throws IllegalStateException { + addTypedSourceRoot(location, null, null, type, hint, displayName, icon, openedIcon); + } + + /** + * Add a typed source root with optional include and exclude lists. + * See {@link #addPrincipalSourceRoot(String,String,String,String,String,Icon,Icon)} + * for details on semantics of includes and excludes. + *

+ * Location need not to exist physically, when hint is specified + * and {@link SourceGroupModifier} created by this helper is added to project + * lookup, source root can be created on demand. + *

+ * @param location a project-relative or absolute path giving the location + * of a source tree; may contain Ant property substitutions + * @param includes an optional list of Ant-style includes + * @param excludes an optional list of Ant-style excludes + * @param type a source root type such as JavaProjectConstants.SOURCES_TYPE_JAVA + * @param hint Hint for {@link SourceGroupModifier} allowing creation of this + * source root on demand + * @param displayName a display name (for {@link SourceGroup#getDisplayName}) + * @param icon a regular icon for the source root, or null + * @param openedIcon an opened variant icon for the source root, or null + * @throws IllegalStateException if this method is called after either + * {@link #createSources} or {@link #registerExternalRoots} + * was called + * @see #createSourceGroupModifierImplementation() + * @since org.netbeans.modules.project.ant/1 1.33 + */ + public void addTypedSourceRoot(String location, String includes, String excludes, String type, String hint, String displayName, Icon icon, Icon openedIcon) throws IllegalStateException { + if (lastRegisteredRoots != null) { + throw new IllegalStateException("registerExternalRoots was already called"); // NOI18N + } + typedSourceRoots.add(new TypedSourceRoot(type, hint, location, includes, excludes, displayName, icon, openedIcon)); } private Project getProject() { @@ -725,7 +882,7 @@ if (type.equals(Sources.TYPE_GENERIC)) { List roots = new ArrayList(principalSourceRoots); // Always include the project directory itself as a default: - roots.add(new SourceRoot("", null, null, ProjectUtils.getInformation(getProject()).getDisplayName(), null, null)); // NOI18N + roots.add(new SourceRoot("", null, null, HINT_NONE, ProjectUtils.getInformation(getProject()).getDisplayName(), null, null)); // NOI18N Map rootsByDir = new LinkedHashMap(); // First collect all non-redundant existing roots. for (SourceRoot r : roots) { @@ -751,6 +908,7 @@ while (parent != null) { if (rootsByDir.containsKey(parent)) { // This is a subroot of something, so skip it. + rootsByDir.get(loc).removed = true; it.remove(); break; } @@ -866,7 +1024,87 @@ maybeFireChange(); } } - + + /** + * Creates new {@link SourceGroupModifierImplementation} that can be put into project lookup. + *

+ * Only source roots added with "hint-ed" variant of addPrincipalSourceRoot + * or AddTypedSourceRoot can be created with this SourceGroupModifierImplementation. + *

+ * @param sources Sources object to which creatable source roots has been added. Must be created + * by {@link #createSources()}. + * @return SourceGroupModifierImplementation implementation for given sources. + * @throws java.lang.IllegalArgumentException When passed sources were not created with {@link #createSources()}. + * @see #addPrincipalSourceRoot(java.lang.String, java.lang.String, java.lang.String, javax.swing.Icon, javax.swing.Icon) + * @see #addPrincipalSourceRoot(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, javax.swing.Icon, javax.swing.Icon) + * @see #addTypedSourceRoot(java.lang.String, java.lang.String, java.lang.String, java.lang.String, javax.swing.Icon, javax.swing.Icon) + * @see #addTypedSourceRoot(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, javax.swing.Icon, javax.swing.Icon) + * @since org.netbeans.modules.project.ant/1 1.33 + */ + public SourceGroupModifierImplementation createSourceGroupModifierImplementation(Sources sources) throws IllegalArgumentException { + if (!(sources instanceof SourcesImpl)) + throw new IllegalArgumentException("Sources object must be created by " + + "org.netbeans.spi.project.support.ant.SourcesHelper#createSources(), got " + + sources.getClass().getName()); + return new SourceGroupModifierImpl((SourcesImpl) sources); + } + + private class SourceGroupModifierImpl implements SourceGroupModifierImplementation { + private Logger logger = Logger.getLogger(SourcesHelper.class.getName()); + private SourcesImpl sources; + + private SourceGroupModifierImpl(SourcesImpl sources) { + this.sources = sources; + } + + public SourceGroup createSourceGroup(String type, String hint) { + SourceRoot root = findRoot(type, hint); + if (root == null) + return null; + if (root.isRemoved()) + return null; // getSourceGroups wouldn't return it, neither will we + + File loc = root.getActualLocation(); + FileObject foloc; + if (! loc.exists()) { + try { + foloc = FileUtil.createFolder(loc); + } catch (IOException ex) { + logger.log(Level.WARNING, "Failed to create folder " + loc, ex); + return null; + } + } else { + foloc = FileUtil.toFileObject(loc); + } + SourceGroup sg = root.toGroup(foloc); + assert sg != null; + sources.maybeFireChange(); + return sg; + } + + public boolean canCreateSourceGroup(String type, String hint) { + return findRoot(type, hint) != null; + } + private SourceRoot findRoot(String type, String hint) { + if (Sources.TYPE_GENERIC.equals(type)) { + for (SourceRoot root : principalSourceRoots) { + if (root.getHint().equals(hint) + && ! root.getHint().equals(HINT_NONE) + && ! root.isRemoved()) + return root; + } + } else { + for (TypedSourceRoot root : typedSourceRoots) { + if (root.getType().equals(type) + && root.getHint().equals(hint) + && ! root.getHint().equals(HINT_NONE)) + return root; + } + } + return null; + } + } + private final class PropChangeL implements PropertyChangeListener { public PropChangeL() {} diff --git a/project.ant/test/unit/src/org/netbeans/spi/project/support/ant/SourcesHelperTest.java b/project.ant/test/unit/src/org/netbeans/spi/project/support/ant/SourcesHelperTest.java --- a/project.ant/test/unit/src/org/netbeans/spi/project/support/ant/SourcesHelperTest.java +++ b/project.ant/test/unit/src/org/netbeans/spi/project/support/ant/SourcesHelperTest.java @@ -41,6 +41,8 @@ package org.netbeans.spi.project.support.ant; +import java.io.IOException; +import javax.swing.event.ChangeListener; import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectManager; @@ -49,6 +51,7 @@ import org.netbeans.junit.NbTestCase; import org.netbeans.api.project.SourceGroup; import org.netbeans.api.project.Sources; +import org.netbeans.spi.project.SourceGroupModifierImplementation; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.test.MockChangeListener; @@ -614,7 +617,82 @@ assertEquals("Packages #1", g1.getDisplayName()); assertEquals(project, FileOwnerQuery.getOwner(src1dir)); } - + + public void testSourceGroupModifierImplementation() throws Exception { + scratch = TestUtil.makeScratchDir(this); // have our own setup + projdir = scratch.createFolder("proj-dir"); + src1dir = projdir.createFolder("src1"); + src4dir = FileUtil.createFolder(projdir, "test/src2"); + FileUtil.createData(src1dir, "org/test/Main.java"); + + h = ProjectGenerator.createProject(projdir, "test"); + project = ProjectManager.getDefault().findProject(projdir); + EditableProperties p = h.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); + p.setProperty("src1.dir", "src1"); + p.setProperty("src2.dir", "src2"); + p.setProperty("test1.dir", "test/src1"); + p.setProperty("test2.dir", "test/src2"); // without a hint + + h.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, p); + ProjectManager.getDefault().saveProject(project); + + sh = new SourcesHelper(project, h, h.getStandardPropertyEvaluator()); + sh.addPrincipalSourceRoot("${src1.dir}", null, null, "main", "Sources #1", null, null); // existing with a hint + sh.addTypedSourceRoot("${src1.dir}", null, null, "java", "main", "Packages #1", null, null); + sh.addPrincipalSourceRoot("${src2.dir}", null, null, "Sources #2", null, null); // non-existent, without a hint + sh.addTypedSourceRoot("${src2.dir}", null, null, "java", "Packages #2", null, null); + sh.addPrincipalSourceRoot("${test1.dir}", null, null, "test", "Test Sources #1", null, null); // non-existent, should be created + sh.addTypedSourceRoot("${test1.dir}", null, null, "java", "test", "Test Packages #1", null, null); + sh.addPrincipalSourceRoot("${test2.dir}", null, null, "Test Sources #2", null, null); // existing without a hint + sh.addTypedSourceRoot("${test2.dir}", null, null, "java", "Test Packages #2", null, null); + sh.registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT, true); + Sources s = sh.createSources(); + SourceGroup[] groups = s.getSourceGroups("java"); + assertEquals("Only source groups for existing folders should be returned", 2, groups.length); + assertEquals("Packages #1", groups[0].getDisplayName()); + assertEquals("Test Packages #2", groups[1].getDisplayName()); + + SourceGroupModifierImplementation sgmi = sh.createSourceGroupModifierImplementation(s); + assertTrue(sgmi.canCreateSourceGroup("java", "main")); + SourceGroup g1 = sgmi.createSourceGroup("java", "main"); + assertEquals("Should return source group equal to existing one.", groups[0].toString(), g1.toString()); + + assertTrue("Should create group for known type/hint", sgmi.canCreateSourceGroup("java", "test")); + SourceGroup g2 = sgmi.createSourceGroup("java", "test"); + assertNotNull(g2.getRootFolder()); // folder physically created + PropertyEvaluator e = h.getStandardPropertyEvaluator(); + assertEquals(h.resolveFileObject(e.getProperty("test1.dir")), g2.getRootFolder()); + + assertFalse("Should not create group for unknown hint", sgmi.canCreateSourceGroup("java", "unknown")); + assertNull(sgmi.createSourceGroup("java", "unknown")); + } + + public void testSGMIMustHaveCorrectSources() throws IOException { + // there is a constraint: Sources passed to SourcesHelper.createSourceGroupModifierImplementation must + // be previously created by SourcesHelper.createSources() + try { + scratch = TestUtil.makeScratchDir(this); // have our own setup + projdir = scratch.createFolder("proj-dir"); + h = ProjectGenerator.createProject(projdir, "test"); + project = ProjectManager.getDefault().findProject(projdir); + ProjectManager.getDefault().saveProject(project); + sh = new SourcesHelper(project, h, h.getStandardPropertyEvaluator()); + Sources bogusSources = new Sources() { + public SourceGroup[] getSourceGroups(String type) { + return null; + } + public void addChangeListener(ChangeListener listener) { + } + public void removeChangeListener(ChangeListener listener) { + } + }; + sh.createSourceGroupModifierImplementation(bogusSources); + } catch (IllegalArgumentException ex) { + return; // ok + } + fail("IllegalArgumentException should have been thrown."); + } + private static void assertIncluded(String message, SourceGroup g, String resource) { FileObject f = g.getRootFolder().getFileObject(resource); assertNotNull(resource, f);