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 @@ -153,7 +153,7 @@ private final AuxiliaryConfiguration aux; private final AntProjectHelper helper; - private final PropertyEvaluator eval; + private final J2SESources.SourcesUpdatingEvaluator eval; private final ReferenceHelper refHelper; private final GeneratedFilesHelper genFilesHelper; private Lookup lookup; @@ -222,7 +222,7 @@ return "J2SEProject[" + FileUtil.getFileDisplayName(getProjectDirectory()) + "]"; // NOI18N } - private PropertyEvaluator createEvaluator() { + private J2SESources.SourcesUpdatingEvaluator createEvaluator() { // It is currently safe to not use the UpdateHelper for PropertyEvaluator; UH.getProperties() delegates to APH // Adapted from APH.getStandardPropertyEvaluator (delegates to ProjectProperties): PropertyEvaluator baseEval1 = PropertyUtils.sequentialPropertyEvaluator( @@ -231,7 +231,7 @@ PropertyEvaluator baseEval2 = PropertyUtils.sequentialPropertyEvaluator( helper.getStockPropertyPreprovider(), helper.getPropertyProvider(AntProjectHelper.PRIVATE_PROPERTIES_PATH)); - return PropertyUtils.sequentialPropertyEvaluator( + PropertyEvaluator baseEval3 = PropertyUtils.sequentialPropertyEvaluator( helper.getStockPropertyPreprovider(), helper.getPropertyProvider(J2SEConfigurationProvider.CONFIG_PROPS_PATH), new ConfigPropertyProvider(baseEval1, "nbproject/private/configs", helper), // NOI18N @@ -241,6 +241,7 @@ "user.properties.file", FileUtil.toFile(getProjectDirectory())), // NOI18N new ConfigPropertyProvider(baseEval1, "nbproject/configs", helper), // NOI18N helper.getPropertyProvider(AntProjectHelper.PROJECT_PROPERTIES_PATH)); + return new J2SESources.SourcesUpdatingEvaluator(baseEval3); } private static final class ConfigPropertyProvider extends FilterPropertyProvider implements PropertyChangeListener { private final PropertyEvaluator baseEval; @@ -294,6 +295,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 +315,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), @@ -338,7 +341,7 @@ lookup = base; // in case LookupProvider's call Project.getLookup return LookupProviderSupport.createCompositeLookup(base, "Projects/org-netbeans-modules-java-j2seproject/Lookup"); //NOI18N } - + public ClassPathProviderImpl getClassPathProvider () { return this.cpProvider; } @@ -381,7 +384,7 @@ } return this.testRoots; } - + File getTestClassesDirectory() { String testClassesDir = evaluator().getProperty(ProjectProperties.BUILD_TEST_CLASSES_DIR); if (testClassesDir == null) { 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 @@ -43,7 +43,9 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeSupport; import java.io.File; +import java.util.Map; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.netbeans.modules.java.j2seproject.ui.customizer.J2SEProjectProperties; @@ -56,6 +58,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; @@ -64,6 +67,7 @@ import org.openide.filesystems.FileUtil; import org.openide.util.ChangeSupport; import org.openide.util.NbBundle; +import org.openide.util.WeakListeners; /** * Implementation of {@link Sources} interface for J2SEProject. @@ -75,14 +79,15 @@ private final Project project; private final AntProjectHelper helper; - private final PropertyEvaluator evaluator; + private final SourcesUpdatingEvaluator evaluator; private final SourceRoots sourceRoots; private final SourceRoots testRoots; private boolean dirty; private Sources delegate; private final ChangeSupport changeSupport = new ChangeSupport(this); + private SourceGroupModifierImplementation sgmi; - J2SESources(Project project, AntProjectHelper helper, PropertyEvaluator evaluator, + J2SESources(Project project, AntProjectHelper helper, SourcesUpdatingEvaluator evaluator, SourceRoots sourceRoots, SourceRoots testRoots) { this.project = project; this.helper = helper; @@ -151,18 +156,44 @@ } 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 = new SourceGroupModifierImplementation() { + SourceGroupModifierImplementation delegate = sourcesHelper.createSourceGroupModifierImplementation(srcs); + + public SourceGroup createSourceGroup(String type, String hint) { + SourceGroup group = delegate.createSourceGroup(type, hint); + if (JavaProjectConstants.SOURCES_TYPE_JAVA.equals(type)) { + // update source roots so that getting test src classpath succeeds in AbstractTestGenerator + SourceRoots roots = JavaProjectConstants.SOURCES_HINT_TEST.equals(hint) ? testRoots : sourceRoots; + for (String prop : roots.getRootProperties()) { + evaluator.propertyChange(new PropertyChangeEvent(evaluator, prop, null, null)); + } + // update sources so that Test Packages node appears in project window + J2SESources.this.fireChange(); + } + return group; + } + + public boolean canCreateSourceGroup(String type, String hint) { + return delegate.canCreateSourceGroup(type, hint); + } + }; + 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 +202,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 } } @@ -204,4 +235,37 @@ this.fireChange(); } + static class SourcesUpdatingEvaluator implements PropertyEvaluator, PropertyChangeListener { + private PropertyEvaluator delegate; + private PropertyChangeSupport pcs; + + SourcesUpdatingEvaluator(PropertyEvaluator delegate) { + this.delegate = delegate; + delegate.addPropertyChangeListener(WeakListeners.propertyChange(this, delegate)); + pcs = new PropertyChangeSupport(delegate); + } + public String getProperty(String prop) { + return delegate.getProperty(prop); + } + + public String evaluate(String text) { + return delegate.evaluate(text); + } + + public Map getProperties() { + return delegate.getProperties(); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void propertyChange(PropertyChangeEvent evt) { + pcs.firePropertyChange(evt); + } + } }