This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 143633
Collapse All | Expand All

(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java (-1 / +3 lines)
Lines 294-299 Link Here
294
        FileEncodingQueryImplementation encodingQuery = QuerySupport.createFileEncodingQuery(evaluator(), J2SEProjectProperties.SOURCE_ENCODING);
294
        FileEncodingQueryImplementation encodingQuery = QuerySupport.createFileEncodingQuery(evaluator(), J2SEProjectProperties.SOURCE_ENCODING);
295
        @SuppressWarnings("deprecation") Object cpe = new org.netbeans.modules.java.api.common.classpath.ClassPathExtender(
295
        @SuppressWarnings("deprecation") Object cpe = new org.netbeans.modules.java.api.common.classpath.ClassPathExtender(
296
            cpMod, ProjectProperties.JAVAC_CLASSPATH, null);
296
            cpMod, ProjectProperties.JAVAC_CLASSPATH, null);
297
        J2SESources srcs = new J2SESources(this, helper, eval, getSourceRoots(), getTestSourceRoots());
297
        final Lookup base = Lookups.fixed(
298
        final Lookup base = Lookups.fixed(
298
            J2SEProject.this,
299
            J2SEProject.this,
299
            new Info(),
300
            new Info(),
Lines 313-319 Link Here
313
            UILookupMergerSupport.createProjectOpenHookMerger(new ProjectOpenedHookImpl()),
314
            UILookupMergerSupport.createProjectOpenHookMerger(new ProjectOpenedHookImpl()),
314
            QuerySupport.createUnitTestForSourceQuery(getSourceRoots(), getTestSourceRoots()),
315
            QuerySupport.createUnitTestForSourceQuery(getSourceRoots(), getTestSourceRoots()),
315
            QuerySupport.createSourceLevelQuery(evaluator()),
316
            QuerySupport.createSourceLevelQuery(evaluator()),
316
            new J2SESources(this, helper, evaluator(), getSourceRoots(), getTestSourceRoots()),
317
            srcs,
318
            srcs.getSourceGroupModifierImplementation(),
317
            QuerySupport.createSharabilityQuery(helper, evaluator(), getSourceRoots(), getTestSourceRoots()),
319
            QuerySupport.createSharabilityQuery(helper, evaluator(), getSourceRoots(), getTestSourceRoots()),
318
            new CoSAwareFileBuiltQueryImpl(QuerySupport.createFileBuiltQuery(helper, evaluator(), getSourceRoots(), getTestSourceRoots()), this),
320
            new CoSAwareFileBuiltQueryImpl(QuerySupport.createFileBuiltQuery(helper, evaluator(), getSourceRoots(), getTestSourceRoots()), this),
319
            new RecommendedTemplatesImpl (this.updateHelper),
321
            new RecommendedTemplatesImpl (this.updateHelper),
(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SESources.java (-8 / +18 lines)
Lines 56-61 Link Here
56
import org.netbeans.api.project.Project;
56
import org.netbeans.api.project.Project;
57
import org.netbeans.modules.java.api.common.SourceRoots;
57
import org.netbeans.modules.java.api.common.SourceRoots;
58
import org.netbeans.modules.java.api.common.project.ProjectProperties;
58
import org.netbeans.modules.java.api.common.project.ProjectProperties;
59
import org.netbeans.spi.project.SourceGroupModifierImplementation;
59
import org.netbeans.spi.project.support.GenericSources;
60
import org.netbeans.spi.project.support.GenericSources;
60
import org.netbeans.spi.project.support.ant.SourcesHelper;
61
import org.netbeans.spi.project.support.ant.SourcesHelper;
61
import org.netbeans.spi.project.support.ant.AntProjectHelper;
62
import org.netbeans.spi.project.support.ant.AntProjectHelper;
Lines 81-86 Link Here
81
    private boolean dirty;
82
    private boolean dirty;
82
    private Sources delegate;
83
    private Sources delegate;
83
    private final ChangeSupport changeSupport = new ChangeSupport(this);
84
    private final ChangeSupport changeSupport = new ChangeSupport(this);
85
    private SourceGroupModifierImplementation sgmi;
84
86
85
    J2SESources(Project project, AntProjectHelper helper, PropertyEvaluator evaluator,
87
    J2SESources(Project project, AntProjectHelper helper, PropertyEvaluator evaluator,
86
                SourceRoots sourceRoots, SourceRoots testRoots) {
88
                SourceRoots sourceRoots, SourceRoots testRoots) {
Lines 151-168 Link Here
151
        } 
153
        } 
152
        return null;
154
        return null;
153
    }
155
    }
156
157
    SourceGroupModifierImplementation getSourceGroupModifierImplementation() {
158
        return sgmi;
159
    }
154
    
160
    
155
    private Sources initSources() {
161
    private Sources initSources() {
156
        SourcesHelper sourcesHelper = new SourcesHelper(project, helper, evaluator);   //Safe to pass APH
162
        final SourcesHelper sourcesHelper = new SourcesHelper(project, helper, evaluator);   //Safe to pass APH
157
        register(sourcesHelper, sourceRoots);
163
        register(sourcesHelper, sourceRoots, JavaProjectConstants.SOURCES_HINT_MAIN);
158
        register(sourcesHelper, testRoots);
164
        register(sourcesHelper, testRoots, JavaProjectConstants.SOURCES_HINT_TEST);
159
        sourcesHelper.addNonSourceRoot(BUILD_DIR_PROP);
165
        sourcesHelper.addNonSourceRoot(BUILD_DIR_PROP);
160
        sourcesHelper.addNonSourceRoot(DIST_DIR_PROP);
166
        sourcesHelper.addNonSourceRoot(DIST_DIR_PROP);
161
        sourcesHelper.registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT, false);
167
        sourcesHelper.registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT, false);
162
        return sourcesHelper.createSources();
168
        final Sources srcs = sourcesHelper.createSources();
169
        sgmi = sourcesHelper.createSourceGroupModifierImplementation(srcs);
170
        return srcs;
163
    }
171
    }
164
172
165
    private void register(SourcesHelper sourcesHelper, SourceRoots roots) {
173
    private void register(SourcesHelper sourcesHelper, SourceRoots roots, String hint) {
166
        String[] propNames = roots.getRootProperties();
174
        String[] propNames = roots.getRootProperties();
167
        String[] rootNames = roots.getRootNames();
175
        String[] rootNames = roots.getRootNames();
168
        for (int i = 0; i < propNames.length; i++) {
176
        for (int i = 0; i < propNames.length; i++) {
Lines 171-178 Link Here
171
            String loc = "${" + prop + "}"; // NOI18N
179
            String loc = "${" + prop + "}"; // NOI18N
172
            String includes = "${" + ProjectProperties.INCLUDES + "}"; // NOI18N
180
            String includes = "${" + ProjectProperties.INCLUDES + "}"; // NOI18N
173
            String excludes = "${" + ProjectProperties.EXCLUDES + "}"; // NOI18N
181
            String excludes = "${" + ProjectProperties.EXCLUDES + "}"; // NOI18N
174
            sourcesHelper.addPrincipalSourceRoot(loc, includes, excludes, displayName, null, null); // NOI18N
182
            sourcesHelper.addPrincipalSourceRoot(loc, includes, excludes, hint, displayName, null, null); // NOI18N
175
            sourcesHelper.addTypedSourceRoot(loc, includes, excludes, JavaProjectConstants.SOURCES_TYPE_JAVA, displayName, null, null); // NOI18N
183
            sourcesHelper.addTypedSourceRoot(loc, includes, excludes, JavaProjectConstants.SOURCES_TYPE_JAVA, hint, displayName, null, null); // NOI18N
176
        }
184
        }
177
    }
185
    }
178
186
Lines 193-199 Link Here
193
201
194
    public void propertyChange(PropertyChangeEvent evt) {
202
    public void propertyChange(PropertyChangeEvent evt) {
195
        String propName = evt.getPropertyName();
203
        String propName = evt.getPropertyName();
196
        if (SourceRoots.PROP_ROOT_PROPERTIES.equals(propName) ||
204
        // was listening to PROP_ROOT_PROPERTIES, changed to PROP_ROOTS in #143633 as changes
205
        // from SourceGroupModifierImplementation need refresh too
206
        if (SourceRoots.PROP_ROOTS.equals(propName)  ||
197
            J2SEProjectProperties.BUILD_DIR.equals(propName)  ||
207
            J2SEProjectProperties.BUILD_DIR.equals(propName)  ||
198
            J2SEProjectProperties.DIST_DIR.equals(propName)) {
208
            J2SEProjectProperties.DIST_DIR.equals(propName)) {
199
            this.fireChange();
209
            this.fireChange();
(-)a/project.ant/apichanges.xml (+19 lines)
Lines 104-109 Link Here
104
    <!-- ACTUAL CHANGES BEGIN HERE: -->
104
    <!-- ACTUAL CHANGES BEGIN HERE: -->
105
105
106
    <changes>
106
    <changes>
107
108
        <change id="SourcesHelper-SourceGroupModifierImplementation">
109
            <api name="general"/>
110
            <summary>Added <code>SourceGroupModifierImplementation</code> implementation for Ant-based projects</summary>
111
            <version major="1" minor="33"/>
112
            <date day="4" month="6" year="2009"/>
113
            <author login="rmichalsky"/>
114
            <compatibility addition="yes"/>
115
            <description>
116
                <p>
117
                    Added method <code>SourcesHelper.createSourceGroupModifierImplementation</code> creating <code>SourceGroupModifierImplementation</code>
118
                    implementation for Ant-based projects. Also added new versions of <code>SourcesHelper.addPrincipalSourceRoot</code>
119
                    and <code>SourcesHelper.addTypedSourceRoot</code> with additional parameter <code>hint</code>, which is required
120
                    for the implementation to work.
121
                </p>
122
            </description>
123
            <class package="org.netbeans.spi.project.support.ant" name="SourcesHelper"/>
124
            <issue number="143633"/>
125
        </change>
107
126
108
        <change id="SourcesHelper-Project-constructor">
127
        <change id="SourcesHelper-Project-constructor">
109
            <api name="general"/>
128
            <api name="general"/>
(-)a/project.ant/manifest.mf (-1 / +1 lines)
Lines 1-6 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.modules.project.ant/1
2
OpenIDE-Module: org.netbeans.modules.project.ant/1
3
OpenIDE-Module-Specification-Version: 1.32
3
OpenIDE-Module-Specification-Version: 1.33
4
OpenIDE-Module-Layer: org/netbeans/modules/project/ant/resources/mf-layer.xml
4
OpenIDE-Module-Layer: org/netbeans/modules/project/ant/resources/mf-layer.xml
5
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/project/ant/Bundle.properties
5
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/project/ant/Bundle.properties
6
OpenIDE-Module-Install: org/netbeans/modules/project/ant/AntProjectModule.class
6
OpenIDE-Module-Install: org/netbeans/modules/project/ant/AntProjectModule.class
(-)a/project.ant/src/org/netbeans/spi/project/support/ant/SourcesHelper.java (-8 / +246 lines)
Lines 57-62 Link Here
57
import java.util.List;
57
import java.util.List;
58
import java.util.Map;
58
import java.util.Map;
59
import java.util.Set;
59
import java.util.Set;
60
import java.util.logging.Level;
61
import java.util.logging.Logger;
60
import javax.swing.Icon;
62
import javax.swing.Icon;
61
import javax.swing.event.ChangeListener;
63
import javax.swing.event.ChangeListener;
62
import org.netbeans.api.project.FileOwnerQuery;
64
import org.netbeans.api.project.FileOwnerQuery;
Lines 64-72 Link Here
64
import org.netbeans.api.project.ProjectManager;
66
import org.netbeans.api.project.ProjectManager;
65
import org.netbeans.api.project.ProjectUtils;
67
import org.netbeans.api.project.ProjectUtils;
66
import org.netbeans.api.project.SourceGroup;
68
import org.netbeans.api.project.SourceGroup;
69
import org.netbeans.api.project.SourceGroupModifier;
67
import org.netbeans.api.project.Sources;
70
import org.netbeans.api.project.Sources;
68
import org.netbeans.api.queries.SharabilityQuery;
71
import org.netbeans.api.queries.SharabilityQuery;
69
import org.netbeans.modules.project.ant.AntBasedProjectFactorySingleton;
72
import org.netbeans.modules.project.ant.AntBasedProjectFactorySingleton;
73
import org.netbeans.spi.project.SourceGroupModifierImplementation;
70
import org.openide.filesystems.FileAttributeEvent;
74
import org.openide.filesystems.FileAttributeEvent;
71
import org.openide.filesystems.FileChangeListener;
75
import org.openide.filesystems.FileChangeListener;
72
import org.openide.filesystems.FileEvent;
76
import org.openide.filesystems.FileEvent;
Lines 75-80 Link Here
75
import org.openide.filesystems.FileStateInvalidException;
79
import org.openide.filesystems.FileStateInvalidException;
76
import org.openide.filesystems.FileUtil;
80
import org.openide.filesystems.FileUtil;
77
import org.openide.util.ChangeSupport;
81
import org.openide.util.ChangeSupport;
82
import org.openide.util.Exceptions;
78
import org.openide.util.Parameters;
83
import org.openide.util.Parameters;
79
import org.openide.util.WeakListeners;
84
import org.openide.util.WeakListeners;
80
85
Lines 125-143 Link Here
125
        private final Icon openedIcon;
130
        private final Icon openedIcon;
126
        private final String includes;
131
        private final String includes;
127
        private final String excludes;
132
        private final String excludes;
133
        private final String hint;
134
        private boolean removed;    // just for sanity checking
128
135
129
        public SourceRoot(String location, String includes, String excludes, String displayName, Icon icon, Icon openedIcon) {
136
        public SourceRoot(String location, String includes, String excludes, String hint, String displayName, Icon icon, Icon openedIcon) {
130
            super(location);
137
            super(location);
131
            this.displayName = displayName;
138
            this.displayName = displayName;
132
            this.icon = icon;
139
            this.icon = icon;
133
            this.openedIcon = openedIcon;
140
            this.openedIcon = openedIcon;
134
            this.includes = includes;
141
            this.includes = includes;
135
            this.excludes = excludes;
142
            this.excludes = excludes;
143
            this.hint = hint;
144
            removed = false;
136
        }
145
        }
137
146
138
        public final SourceGroup toGroup(FileObject loc) {
147
        public final SourceGroup toGroup(FileObject loc) {
139
            assert loc != null;
148
            assert loc != null;
140
            return new Group(loc);
149
            return new Group(loc);
150
        }
151
152
        public String getHint() {
153
            return hint;
154
        }
155
156
        public boolean isRemoved() {
157
            return removed;
141
        }
158
        }
142
159
143
        @Override
160
        @Override
Lines 291-298 Link Here
291
    
308
    
292
    private final class TypedSourceRoot extends SourceRoot {
309
    private final class TypedSourceRoot extends SourceRoot {
293
        private final String type;
310
        private final String type;
294
        public TypedSourceRoot(String type, String location, String includes, String excludes, String displayName, Icon icon, Icon openedIcon) {
311
        public TypedSourceRoot(String type, String hint, String location, String includes, String excludes, String displayName, Icon icon, Icon openedIcon) {
295
            super(location, includes, excludes, displayName, icon, openedIcon);
312
            super(location, includes, excludes, hint, displayName, icon, openedIcon);
296
            this.type = type;
313
            this.type = type;
297
        }
314
        }
298
        public final String getType() {
315
        public final String getType() {
Lines 371-376 Link Here
371
        addPrincipalSourceRoot(location, null, null, displayName, icon, openedIcon);
388
        addPrincipalSourceRoot(location, null, null, displayName, icon, openedIcon);
372
    }
389
    }
373
390
391
    // no code hint for source root, group cannot be created from it via SourceGroupModifier
392
    private static final String HINT_NONE = "none";
393
374
    /**
394
    /**
375
     * Add a possible principal source root, or top-level folder which may
395
     * Add a possible principal source root, or top-level folder which may
376
     * contain sources that should be considered part of the project, with
396
     * contain sources that should be considered part of the project, with
Lines 409-417 Link Here
409
        if (lastRegisteredRoots != null) {
429
        if (lastRegisteredRoots != null) {
410
            throw new IllegalStateException("registerExternalRoots was already called"); // NOI18N
430
            throw new IllegalStateException("registerExternalRoots was already called"); // NOI18N
411
        }
431
        }
412
        principalSourceRoots.add(new SourceRoot(location, includes, excludes, displayName, icon, openedIcon));
432
        principalSourceRoots.add(new SourceRoot(location, includes, excludes, HINT_NONE, displayName, icon, openedIcon));
413
    }
433
    }
414
    
434
435
    /**
436
     * Add a possible principal source root, or top-level folder which may
437
     * contain sources that should be considered part of the project.
438
     * <p>
439
     * If the actual value of the location is inside the project directory,
440
     * this is simply ignored; so it safe to configure principal source roots
441
     * for any source directory which might be set to use an external path, even
442
     * if the common location is internal.
443
     * </p><p>
444
     * Location need not to exist physically, when <tt>hint</tt> is specified
445
     * and {@link SourceGroupModifier} created by this helper is added to project
446
     * lookup, source root can be created on demand.
447
     * </p>
448
     * @param location a project-relative or absolute path giving the location
449
     *                 of a source tree; may contain Ant property substitutions
450
     * @param hint Hint for {@link SourceGroupModifier} allowing creation of this
451
     *                 source root on demand
452
     * @param displayName a display name (for {@link SourceGroup#getDisplayName})
453
     * @param icon a regular icon for the source root, or null
454
     * @param openedIcon an opened variant icon for the source root, or null
455
     * @throws IllegalStateException if this method is called after either
456
     *                               {@link #createSources} or {@link #registerExternalRoots}
457
     *                               was called
458
     * @see #registerExternalRoots
459
     * @see Sources#TYPE_GENERIC
460
     * @see #createSourceGroupModifierImplementation()
461
     * @since org.netbeans.modules.project.ant/1 1.33
462
     */
463
    public void addPrincipalSourceRoot(String location, String hint, String displayName, Icon icon, Icon openedIcon) throws IllegalStateException {
464
        addPrincipalSourceRoot(location, null, null, hint, displayName, icon, openedIcon);
465
    }
466
467
    /**
468
     * Add a possible principal source root, or top-level folder which may
469
     * contain sources that should be considered part of the project, with
470
     * optional include and exclude lists.
471
     * <p>
472
     * If an include or exclude string is given as null, then it is skipped. A non-null value is
473
     * evaluated and then treated as a comma- or space-separated pattern list,
474
     * as detailed in the Javadoc for {@link PathMatcher}.
475
     * (As a special convenience, a value consisting solely of an Ant property reference
476
     * which cannot be evaluated, e.g. <samp>${undefined}</samp>, is treated like null.)
477
     * {@link SourceGroup#contains} will then reflect the includes and excludes for files, but note that the
478
     * semantics of that method requires that a folder be "contained" in case any folder or file
479
     * beneath it is contained, and in particular the root folder is always contained.
480
     * </p><p>
481
     * Location need not to exist physically, when <tt>hint</tt> is specified
482
     * and {@link SourceGroupModifier} created by this helper is added to project
483
     * lookup, source root can be created on demand.
484
     * </p>
485
     * @param location a project-relative or absolute path giving the location
486
     *                 of a source tree; may contain Ant property substitutions
487
     * @param includes Ant-style includes; may contain Ant property substitutions;
488
     *                 if not null, only files and folders
489
     *                 matching the pattern (or patterns), and not specified in the excludes list,
490
     *                 will be {@link SourceGroup#contains included}
491
     * @param excludes Ant-style excludes; may contain Ant property substitutions;
492
     *                 if not null, files and folders
493
     *                 matching the pattern (or patterns) will not be {@link SourceGroup#contains included},
494
     *                 even if specified in the includes list
495
     * @param hint Hint for {@link SourceGroupModifier} allowing creation of this
496
     *                 source root on demand
497
     * @param displayName a display name (for {@link SourceGroup#getDisplayName})
498
     * @param icon a regular icon for the source root, or null
499
     * @param openedIcon an opened variant icon for the source root, or null
500
     * @throws IllegalStateException if this method is called after either
501
     *                               {@link #createSources} or {@link #registerExternalRoots}
502
     *                               was called
503
     * @see #registerExternalRoots
504
     * @see Sources#TYPE_GENERIC
505
     * @see #createSourceGroupModifierImplementation()
506
     * @since org.netbeans.modules.project.ant/1 1.33
507
     */
508
    public void addPrincipalSourceRoot(String location, String includes, String excludes, String hint, String displayName, Icon icon, Icon openedIcon) throws IllegalStateException {
509
        if (lastRegisteredRoots != null) {
510
            throw new IllegalStateException("registerExternalRoots was already called"); // NOI18N
511
        }
512
        principalSourceRoots.add(new SourceRoot(location, includes, excludes, hint, displayName, icon, openedIcon));
513
    }
514
415
    /**
515
    /**
416
     * Similar to {@link #addPrincipalSourceRoot} but affects only
516
     * Similar to {@link #addPrincipalSourceRoot} but affects only
417
     * {@link #registerExternalRoots} and not {@link #createSources}.
517
     * {@link #registerExternalRoots} and not {@link #createSources}.
Lines 493-499 Link Here
493
        if (lastRegisteredRoots != null) {
593
        if (lastRegisteredRoots != null) {
494
            throw new IllegalStateException("registerExternalRoots was already called"); // NOI18N
594
            throw new IllegalStateException("registerExternalRoots was already called"); // NOI18N
495
        }
595
        }
496
        typedSourceRoots.add(new TypedSourceRoot(type, location, includes, excludes, displayName, icon, openedIcon));
596
        typedSourceRoots.add(new TypedSourceRoot(type, HINT_NONE, location, includes, excludes, displayName, icon, openedIcon));
597
    }
598
599
    /**
600
     * Add a typed source root which will be considered only in certain contexts.
601
     * <p>
602
     * Location need not to exist physically, when <tt>hint</tt> is specified
603
     * and {@link SourceGroupModifier} created by this helper is added to project
604
     * lookup, source root can be created on demand.
605
     * </p>
606
     * @param location a project-relative or absolute path giving the location
607
     *                 of a source tree; may contain Ant property substitutions
608
     * @param type a source root type such as <a href="@JAVA/PROJECT@/org/netbeans/api/java/project/JavaProjectConstants.html#SOURCES_TYPE_JAVA"><code>JavaProjectConstants.SOURCES_TYPE_JAVA</code></a>
609
     * @param hint Hint for {@link SourceGroupModifier} allowing creation of this
610
     *                 source root on demand
611
     * @param displayName a display name (for {@link SourceGroup#getDisplayName})
612
     * @param icon a regular icon for the source root, or null
613
     * @param openedIcon an opened variant icon for the source root, or null
614
     * @throws IllegalStateException if this method is called after either
615
     *                               {@link #createSources} or {@link #registerExternalRoots}
616
     *                               was called
617
     * @see #createSourceGroupModifierImplementation()
618
     * @since org.netbeans.modules.project.ant/1 1.33
619
     */
620
    public void addTypedSourceRoot(String location, String type, String hint, String displayName, Icon icon, Icon openedIcon) throws IllegalStateException {
621
        addTypedSourceRoot(location, null, null, type, hint, displayName, icon, openedIcon);
622
    }
623
624
    /**
625
     * Add a typed source root with optional include and exclude lists.
626
     * See {@link #addPrincipalSourceRoot(String,String,String,String,String,Icon,Icon)}
627
     * for details on semantics of includes and excludes.
628
     * <p>
629
     * Location need not to exist physically, when <tt>hint</tt> is specified
630
     * and {@link SourceGroupModifier} created by this helper is added to project
631
     * lookup, source root can be created on demand.
632
     * </p>
633
     * @param location a project-relative or absolute path giving the location
634
     *                 of a source tree; may contain Ant property substitutions
635
     * @param includes an optional list of Ant-style includes
636
     * @param excludes an optional list of Ant-style excludes
637
     * @param type a source root type such as <a href="@JAVA/PROJECT@/org/netbeans/api/java/project/JavaProjectConstants.html#SOURCES_TYPE_JAVA"><code>JavaProjectConstants.SOURCES_TYPE_JAVA</code></a>
638
     * @param hint Hint for {@link SourceGroupModifier} allowing creation of this
639
     *                 source root on demand
640
     * @param displayName a display name (for {@link SourceGroup#getDisplayName})
641
     * @param icon a regular icon for the source root, or null
642
     * @param openedIcon an opened variant icon for the source root, or null
643
     * @throws IllegalStateException if this method is called after either
644
     *                               {@link #createSources} or {@link #registerExternalRoots}
645
     *                               was called
646
     * @see #createSourceGroupModifierImplementation() 
647
     * @since org.netbeans.modules.project.ant/1 1.33
648
     */
649
    public void addTypedSourceRoot(String location, String includes, String excludes, String type, String hint, String displayName, Icon icon, Icon openedIcon) throws IllegalStateException {
650
        if (lastRegisteredRoots != null) {
651
            throw new IllegalStateException("registerExternalRoots was already called"); // NOI18N
652
        }
653
        typedSourceRoots.add(new TypedSourceRoot(type, hint, location, includes, excludes, displayName, icon, openedIcon));
497
    }
654
    }
498
    
655
    
499
    private Project getProject() {
656
    private Project getProject() {
Lines 725-731 Link Here
725
            if (type.equals(Sources.TYPE_GENERIC)) {
882
            if (type.equals(Sources.TYPE_GENERIC)) {
726
                List<SourceRoot> roots = new ArrayList<SourceRoot>(principalSourceRoots);
883
                List<SourceRoot> roots = new ArrayList<SourceRoot>(principalSourceRoots);
727
                // Always include the project directory itself as a default:
884
                // Always include the project directory itself as a default:
728
                roots.add(new SourceRoot("", null, null, ProjectUtils.getInformation(getProject()).getDisplayName(), null, null)); // NOI18N
885
                roots.add(new SourceRoot("", null, null, HINT_NONE, ProjectUtils.getInformation(getProject()).getDisplayName(), null, null)); // NOI18N
729
                Map<FileObject,SourceRoot> rootsByDir = new LinkedHashMap<FileObject,SourceRoot>();
886
                Map<FileObject,SourceRoot> rootsByDir = new LinkedHashMap<FileObject,SourceRoot>();
730
                // First collect all non-redundant existing roots.
887
                // First collect all non-redundant existing roots.
731
                for (SourceRoot r : roots) {
888
                for (SourceRoot r : roots) {
Lines 751-756 Link Here
751
                    while (parent != null) {
908
                    while (parent != null) {
752
                        if (rootsByDir.containsKey(parent)) {
909
                        if (rootsByDir.containsKey(parent)) {
753
                            // This is a subroot of something, so skip it.
910
                            // This is a subroot of something, so skip it.
911
                            rootsByDir.get(loc).removed = true;
754
                            it.remove();
912
                            it.remove();
755
                            break;
913
                            break;
756
                        }
914
                        }
Lines 866-872 Link Here
866
            maybeFireChange();
1024
            maybeFireChange();
867
        }
1025
        }
868
    }
1026
    }
869
    
1027
1028
    /**
1029
     * Creates new {@link SourceGroupModifierImplementation} that can be put into project lookup.
1030
     * <p>
1031
     * Only source roots added with "<tt>hint</tt>-ed" variant of <tt>addPrincipalSourceRoot</tt>
1032
     * or <tt>AddTypedSourceRoot</tt> can be created with this <tt>SourceGroupModifierImplementation</tt>.
1033
     * </p>
1034
     * @param sources Sources object to which creatable source roots has been added. Must be created
1035
     *                by {@link #createSources()}.
1036
     * @return <tt>SourceGroupModifierImplementation</tt> implementation for given sources.
1037
     * @throws java.lang.IllegalArgumentException When passed sources were not created with {@link #createSources()}.
1038
     * @see #addPrincipalSourceRoot(java.lang.String, java.lang.String, java.lang.String, javax.swing.Icon, javax.swing.Icon)
1039
     * @see #addPrincipalSourceRoot(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, javax.swing.Icon, javax.swing.Icon)
1040
     * @see #addTypedSourceRoot(java.lang.String, java.lang.String, java.lang.String, java.lang.String, javax.swing.Icon, javax.swing.Icon)
1041
     * @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)
1042
     * @since org.netbeans.modules.project.ant/1 1.33
1043
     */
1044
    public SourceGroupModifierImplementation createSourceGroupModifierImplementation(Sources sources) throws IllegalArgumentException {
1045
        if (!(sources instanceof SourcesImpl))
1046
            throw new IllegalArgumentException("Sources object must be created by "
1047
                    + "org.netbeans.spi.project.support.ant.SourcesHelper#createSources(), got "
1048
                    + sources.getClass().getName());
1049
        return new SourceGroupModifierImpl((SourcesImpl) sources);
1050
    }
1051
1052
    private class SourceGroupModifierImpl implements SourceGroupModifierImplementation {
1053
        private Logger logger = Logger.getLogger(SourcesHelper.class.getName());
1054
        private SourcesImpl sources;
1055
1056
        private SourceGroupModifierImpl(SourcesImpl sources) {
1057
            this.sources = sources;
1058
        }
1059
1060
        public SourceGroup createSourceGroup(String type, String hint) {
1061
            SourceRoot root = findRoot(type, hint);
1062
            if (root == null)
1063
                return null;
1064
            if (root.isRemoved())
1065
                return null;    // getSourceGroups wouldn't return it, neither will we
1066
1067
            File loc = root.getActualLocation();
1068
            FileObject foloc;
1069
            if (! loc.exists()) {
1070
                try {
1071
                    foloc = FileUtil.createFolder(loc);
1072
                } catch (IOException ex) {
1073
                    logger.log(Level.WARNING, "Failed to create folder " + loc, ex);
1074
                    return null;
1075
                }
1076
            } else {
1077
                foloc = FileUtil.toFileObject(loc);
1078
            }
1079
            SourceGroup sg = root.toGroup(foloc);
1080
            assert sg != null;
1081
            sources.maybeFireChange();
1082
            return sg;
1083
        }
1084
1085
        public boolean canCreateSourceGroup(String type, String hint) {
1086
            return findRoot(type, hint) != null;
1087
        }
1088
        private SourceRoot findRoot(String type, String hint) {
1089
            if (Sources.TYPE_GENERIC.equals(type)) {
1090
                for (SourceRoot root : principalSourceRoots) {
1091
                    if (root.getHint().equals(hint)
1092
                            && ! root.getHint().equals(HINT_NONE)
1093
                            && ! root.isRemoved())
1094
                        return root;
1095
                }
1096
            } else {
1097
                for (TypedSourceRoot root : typedSourceRoots) {
1098
                    if (root.getType().equals(type)
1099
                            && root.getHint().equals(hint)
1100
                            && ! root.getHint().equals(HINT_NONE))
1101
                        return root;
1102
                }
1103
            }
1104
            return null;
1105
        }
1106
    }
1107
870
    private final class PropChangeL implements PropertyChangeListener {
1108
    private final class PropChangeL implements PropertyChangeListener {
871
        
1109
        
872
        public PropChangeL() {}
1110
        public PropChangeL() {}
(-)a/project.ant/test/unit/src/org/netbeans/spi/project/support/ant/SourcesHelperTest.java (-1 / +79 lines)
Lines 41-46 Link Here
41
41
42
package org.netbeans.spi.project.support.ant;
42
package org.netbeans.spi.project.support.ant;
43
43
44
import java.io.IOException;
45
import javax.swing.event.ChangeListener;
44
import org.netbeans.api.project.FileOwnerQuery;
46
import org.netbeans.api.project.FileOwnerQuery;
45
import org.netbeans.api.project.Project;
47
import org.netbeans.api.project.Project;
46
import org.netbeans.api.project.ProjectManager;
48
import org.netbeans.api.project.ProjectManager;
Lines 49-54 Link Here
49
import org.netbeans.junit.NbTestCase;
51
import org.netbeans.junit.NbTestCase;
50
import org.netbeans.api.project.SourceGroup;
52
import org.netbeans.api.project.SourceGroup;
51
import org.netbeans.api.project.Sources;
53
import org.netbeans.api.project.Sources;
54
import org.netbeans.spi.project.SourceGroupModifierImplementation;
52
import org.openide.filesystems.FileObject;
55
import org.openide.filesystems.FileObject;
53
import org.openide.filesystems.FileUtil;
56
import org.openide.filesystems.FileUtil;
54
import org.openide.util.test.MockChangeListener;
57
import org.openide.util.test.MockChangeListener;
Lines 614-620 Link Here
614
        assertEquals("Packages #1", g1.getDisplayName());
617
        assertEquals("Packages #1", g1.getDisplayName());
615
        assertEquals(project, FileOwnerQuery.getOwner(src1dir));
618
        assertEquals(project, FileOwnerQuery.getOwner(src1dir));
616
    }
619
    }
617
    
620
621
    public void testSourceGroupModifierImplementation() throws Exception {
622
        scratch = TestUtil.makeScratchDir(this); // have our own setup
623
        projdir = scratch.createFolder("proj-dir");
624
        src1dir = projdir.createFolder("src1"); 
625
        src4dir = FileUtil.createFolder(projdir, "test/src2");
626
        FileUtil.createData(src1dir, "org/test/Main.java");
627
628
        h = ProjectGenerator.createProject(projdir, "test");
629
        project = ProjectManager.getDefault().findProject(projdir);
630
        EditableProperties p = h.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
631
        p.setProperty("src1.dir", "src1");
632
        p.setProperty("src2.dir", "src2");  
633
        p.setProperty("test1.dir", "test/src1");
634
        p.setProperty("test2.dir", "test/src2");  // without a hint
635
636
        h.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, p);
637
        ProjectManager.getDefault().saveProject(project);
638
639
        sh = new SourcesHelper(project, h, h.getStandardPropertyEvaluator());
640
        sh.addPrincipalSourceRoot("${src1.dir}", null, null, "main", "Sources #1", null, null); // existing with a hint
641
        sh.addTypedSourceRoot("${src1.dir}", null, null, "java", "main", "Packages #1", null, null);
642
        sh.addPrincipalSourceRoot("${src2.dir}", null, null, "Sources #2", null, null); // non-existent, without a hint
643
        sh.addTypedSourceRoot("${src2.dir}", null, null, "java", "Packages #2", null, null);
644
        sh.addPrincipalSourceRoot("${test1.dir}", null, null, "test", "Test Sources #1", null, null);   // non-existent, should be created
645
        sh.addTypedSourceRoot("${test1.dir}", null, null, "java", "test", "Test Packages #1", null, null);
646
        sh.addPrincipalSourceRoot("${test2.dir}", null, null, "Test Sources #2", null, null);   // existing without a hint
647
        sh.addTypedSourceRoot("${test2.dir}", null, null, "java", "Test Packages #2", null, null);
648
        sh.registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT, true);
649
        Sources s = sh.createSources();
650
        SourceGroup[] groups = s.getSourceGroups("java");
651
        assertEquals("Only source groups for existing folders should be returned", 2, groups.length);
652
        assertEquals("Packages #1", groups[0].getDisplayName());
653
        assertEquals("Test Packages #2", groups[1].getDisplayName());
654
655
        SourceGroupModifierImplementation sgmi = sh.createSourceGroupModifierImplementation(s);
656
        assertTrue(sgmi.canCreateSourceGroup("java", "main"));
657
        SourceGroup g1 = sgmi.createSourceGroup("java", "main");
658
        assertEquals("Should return source group equal to existing one.", groups[0].toString(), g1.toString());
659
        
660
        assertTrue("Should create group for known type/hint", sgmi.canCreateSourceGroup("java", "test"));
661
        SourceGroup g2 = sgmi.createSourceGroup("java", "test");
662
        assertNotNull(g2.getRootFolder());  // folder physically created
663
        PropertyEvaluator e = h.getStandardPropertyEvaluator();
664
        assertEquals(h.resolveFileObject(e.getProperty("test1.dir")), g2.getRootFolder());
665
666
        assertFalse("Should not create group for unknown hint", sgmi.canCreateSourceGroup("java", "unknown"));
667
        assertNull(sgmi.createSourceGroup("java", "unknown"));
668
    }
669
670
    public void testSGMIMustHaveCorrectSources() throws IOException {
671
        // there is a constraint: Sources passed to SourcesHelper.createSourceGroupModifierImplementation must
672
        // be previously created by SourcesHelper.createSources()
673
        try {
674
            scratch = TestUtil.makeScratchDir(this); // have our own setup
675
            projdir = scratch.createFolder("proj-dir");
676
            h = ProjectGenerator.createProject(projdir, "test");
677
            project = ProjectManager.getDefault().findProject(projdir);
678
            ProjectManager.getDefault().saveProject(project);
679
            sh = new SourcesHelper(project, h, h.getStandardPropertyEvaluator());
680
            Sources bogusSources = new Sources() {
681
                public SourceGroup[] getSourceGroups(String type) {
682
                    return null;
683
                }
684
                public void addChangeListener(ChangeListener listener) {
685
                }
686
                public void removeChangeListener(ChangeListener listener) {
687
                }
688
            };
689
            sh.createSourceGroupModifierImplementation(bogusSources);
690
        } catch (IllegalArgumentException ex) {
691
            return; // ok
692
        }
693
        fail("IllegalArgumentException should have been thrown.");
694
    }
695
618
    private static void assertIncluded(String message, SourceGroup g, String resource) {
696
    private static void assertIncluded(String message, SourceGroup g, String resource) {
619
        FileObject f = g.getRootFolder().getFileObject(resource);
697
        FileObject f = g.getRootFolder().getFileObject(resource);
620
        assertNotNull(resource, f);
698
        assertNotNull(resource, f);

Return to bug 143633