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 237548
Collapse All | Expand All

(-)a/j2me.project/nbproject/project.xml (-1 / +1 lines)
Lines 71-77 Link Here
71
                    <compile-dependency/>
71
                    <compile-dependency/>
72
                    <run-dependency>
72
                    <run-dependency>
73
                        <release-version>0-1</release-version>
73
                        <release-version>0-1</release-version>
74
                        <specification-version>1.63</specification-version>
74
                        <specification-version>1.64</specification-version>
75
                    </run-dependency>
75
                    </run-dependency>
76
                </dependency>
76
                </dependency>
77
                <dependency>
77
                <dependency>
(-)a/j2me.project/src/org/netbeans/modules/j2me/project/J2MEProject.java (-58 / +21 lines)
Lines 42-51 Link Here
42
42
43
package org.netbeans.modules.j2me.project;
43
package org.netbeans.modules.j2me.project;
44
44
45
import java.beans.PropertyChangeEvent;
46
import java.beans.PropertyChangeListener;
47
import java.util.Arrays;
45
import java.util.Arrays;
48
import java.util.Collections;
49
import java.util.List;
46
import java.util.List;
50
import java.util.concurrent.Callable;
47
import java.util.concurrent.Callable;
51
import org.netbeans.api.annotations.common.NonNull;
48
import org.netbeans.api.annotations.common.NonNull;
Lines 55-60 Link Here
55
import org.netbeans.api.project.SourceGroup;
52
import org.netbeans.api.project.SourceGroup;
56
import org.netbeans.api.project.ant.AntBuildExtender;
53
import org.netbeans.api.project.ant.AntBuildExtender;
57
import org.netbeans.modules.j2me.project.ui.customizer.CustomizerProviderImpl;
54
import org.netbeans.modules.j2me.project.ui.customizer.CustomizerProviderImpl;
55
import org.netbeans.modules.j2me.project.ui.customizer.J2MECompositeCategoryProvider;
58
import org.netbeans.modules.j2me.project.ui.customizer.J2MEProjectProperties;
56
import org.netbeans.modules.j2me.project.ui.customizer.J2MEProjectProperties;
59
import org.netbeans.modules.java.api.common.Roots;
57
import org.netbeans.modules.java.api.common.Roots;
60
import org.netbeans.modules.java.api.common.SourceRoots;
58
import org.netbeans.modules.java.api.common.SourceRoots;
Lines 62-88 Link Here
62
import org.netbeans.modules.java.api.common.classpath.ClassPathModifier;
60
import org.netbeans.modules.java.api.common.classpath.ClassPathModifier;
63
import org.netbeans.modules.java.api.common.classpath.ClassPathProviderImpl;
61
import org.netbeans.modules.java.api.common.classpath.ClassPathProviderImpl;
64
import org.netbeans.modules.java.api.common.project.BaseActionProvider;
62
import org.netbeans.modules.java.api.common.project.BaseActionProvider;
63
import org.netbeans.modules.java.api.common.project.ProjectConfigurations;
65
import org.netbeans.modules.java.api.common.project.ProjectHooks;
64
import org.netbeans.modules.java.api.common.project.ProjectHooks;
66
import org.netbeans.modules.java.api.common.project.ProjectProperties;
65
import org.netbeans.modules.java.api.common.project.ProjectProperties;
67
import org.netbeans.modules.java.api.common.project.ui.LogicalViewProviders;
66
import org.netbeans.modules.java.api.common.project.ui.LogicalViewProviders;
68
import org.netbeans.modules.java.api.common.queries.QuerySupport;
67
import org.netbeans.modules.java.api.common.queries.QuerySupport;
69
import org.netbeans.spi.java.project.support.LookupMergerSupport;
68
import org.netbeans.spi.java.project.support.LookupMergerSupport;
69
import org.netbeans.spi.project.ActionProvider;
70
import org.netbeans.spi.project.AuxiliaryConfiguration;
70
import org.netbeans.spi.project.AuxiliaryConfiguration;
71
import org.netbeans.spi.project.ant.AntBuildExtenderFactory;
71
import org.netbeans.spi.project.ant.AntBuildExtenderFactory;
72
import org.netbeans.spi.project.ant.AntBuildExtenderImplementation;
72
import org.netbeans.spi.project.ant.AntBuildExtenderImplementation;
73
import org.netbeans.spi.project.support.LookupProviderSupport;
73
import org.netbeans.spi.project.support.LookupProviderSupport;
74
import org.netbeans.spi.project.support.ant.AntBasedProjectRegistration;
74
import org.netbeans.spi.project.support.ant.AntBasedProjectRegistration;
75
import org.netbeans.spi.project.support.ant.AntProjectHelper;
75
import org.netbeans.spi.project.support.ant.AntProjectHelper;
76
import org.netbeans.spi.project.support.ant.FilterPropertyProvider;
77
import org.netbeans.spi.project.support.ant.GeneratedFilesHelper;
76
import org.netbeans.spi.project.support.ant.GeneratedFilesHelper;
78
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
77
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
79
import org.netbeans.spi.project.support.ant.PropertyProvider;
80
import org.netbeans.spi.project.support.ant.PropertyUtils;
81
import org.netbeans.spi.project.support.ant.ReferenceHelper;
78
import org.netbeans.spi.project.support.ant.ReferenceHelper;
82
import org.netbeans.spi.project.ui.support.UILookupMergerSupport;
79
import org.netbeans.spi.project.ui.support.UILookupMergerSupport;
83
import org.netbeans.spi.queries.FileEncodingQueryImplementation;
80
import org.netbeans.spi.queries.FileEncodingQueryImplementation;
84
import org.openide.filesystems.FileObject;
81
import org.openide.filesystems.FileObject;
85
import org.openide.filesystems.FileUtil;
86
import org.openide.util.ImageUtilities;
82
import org.openide.util.ImageUtilities;
87
import org.openide.util.Lookup;
83
import org.openide.util.Lookup;
88
import org.openide.util.Parameters;
84
import org.openide.util.Parameters;
Lines 131-142 Link Here
131
    private final SourceRoots sourceRoots;
127
    private final SourceRoots sourceRoots;
132
    private final SourceRoots testRoots;
128
    private final SourceRoots testRoots;
133
129
130
    @SuppressWarnings("LeakingThisInConstructor")
134
    public J2MEProject(@NonNull final AntProjectHelper helper) {
131
    public J2MEProject(@NonNull final AntProjectHelper helper) {
135
        Parameters.notNull("helper", helper);   //NOI18N
132
        Parameters.notNull("helper", helper);   //NOI18N
136
        this.helper = helper;
133
        this.helper = helper;
137
        this.updateHelper = new UpdateHelper(new J2MEProjectUpdates(helper), helper);
134
        this.updateHelper = new UpdateHelper(new J2MEProjectUpdates(helper), helper);
138
        this.auxCfg = helper.createAuxiliaryConfiguration();
135
        this.auxCfg = helper.createAuxiliaryConfiguration();
139
        this.eval = createPropertyEvaluator();
136
        this.eval = ProjectConfigurations.createPropertyEvaluator(this, helper);
140
        this.refHelper = new ReferenceHelper(helper, auxCfg, eval);
137
        this.refHelper = new ReferenceHelper(helper, auxCfg, eval);
141
        final AntBuildExtender buildExtender = AntBuildExtenderFactory.createAntExtender(
138
        final AntBuildExtender buildExtender = AntBuildExtenderFactory.createAntExtender(
142
            new J2MEExtenderImplementation(),
139
            new J2MEExtenderImplementation(),
Lines 296-301 Link Here
296
                buildExtender,
293
                buildExtender,
297
                new BuildArtifacts(helper, eval),
294
                new BuildArtifacts(helper, eval),
298
                new Templates(),
295
                new Templates(),
296
                ProjectConfigurations.createConfigurationProviderBuilder(this, eval, updateHelper).
297
                    addConfigurationsAffectActions(ActionProvider.COMMAND_RUN, ActionProvider.COMMAND_DEBUG).
298
                    setCustomizerAction(newConfigCustomizerAction()).
299
                    build(),
299
                LookupMergerSupport.createClassPathProviderMerger(cpProvider),
300
                LookupMergerSupport.createClassPathProviderMerger(cpProvider),
300
                LookupMergerSupport.createSFBLookupMerger(),
301
                LookupMergerSupport.createSFBLookupMerger(),
301
                LookupMergerSupport.createJFBLookupMerger(),
302
                LookupMergerSupport.createJFBLookupMerger(),
Lines 307-332 Link Here
307
        );
308
        );
308
        return LookupProviderSupport.createCompositeLookup(base, EXTENSION_POINT);
309
        return LookupProviderSupport.createCompositeLookup(base, EXTENSION_POINT);
309
    }
310
    }
310
311
    
311
    @NonNull
312
    private PropertyEvaluator createPropertyEvaluator() {
313
        final PropertyEvaluator baseEval1 = PropertyUtils.sequentialPropertyEvaluator(
314
                helper.getStockPropertyPreprovider(),
315
                helper.getPropertyProvider(ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG));
316
        final PropertyEvaluator baseEval2 = PropertyUtils.sequentialPropertyEvaluator(
317
                helper.getStockPropertyPreprovider(),
318
                helper.getPropertyProvider(AntProjectHelper.PRIVATE_PROPERTIES_PATH));
319
        return PropertyUtils.sequentialPropertyEvaluator(
320
                helper.getStockPropertyPreprovider(),
321
                helper.getPropertyProvider(ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG),
322
                new ConfigPropertyProvider(baseEval1, "nbproject/private/configs", helper), // NOI18N
323
                helper.getPropertyProvider(AntProjectHelper.PRIVATE_PROPERTIES_PATH),
324
                helper.getProjectLibrariesPropertyProvider(),
325
                PropertyUtils.userPropertiesProvider(baseEval2,
326
                    "user.properties.file", FileUtil.toFile(getProjectDirectory())), // NOI18N
327
                new ConfigPropertyProvider(baseEval1, "nbproject/configs", helper), // NOI18N
328
                helper.getPropertyProvider(AntProjectHelper.PROJECT_PROPERTIES_PATH));
329
    }
330
312
331
    private ClassPathModifier.Callback newClassPathModifierCallback() {
313
    private ClassPathModifier.Callback newClassPathModifierCallback() {
332
        return new ClassPathModifier.Callback() {
314
        return new ClassPathModifier.Callback() {
Lines 350-355 Link Here
350
        };
332
        };
351
    }
333
    }
352
334
335
    @NonNull
336
    private Runnable newConfigCustomizerAction() {
337
        return new Runnable() {
338
            @Override
339
            public void run() {
340
                J2MEProject.this.getLookup().lookup(CustomizerProviderImpl.class).
341
                    showCustomizer(J2MECompositeCategoryProvider.RUN, null);
342
            }
343
        };
344
    }
345
353
    private class J2MEExtenderImplementation implements AntBuildExtenderImplementation {
346
    private class J2MEExtenderImplementation implements AntBuildExtenderImplementation {
354
        //add targets here as required by the external plugins..
347
        //add targets here as required by the external plugins..
355
        @Override
348
        @Override
Lines 363-396 Link Here
363
            return J2MEProject.this;
356
            return J2MEProject.this;
364
        }
357
        }
365
    }
358
    }
366
367
    private static final class ConfigPropertyProvider extends FilterPropertyProvider implements PropertyChangeListener {
368
        private final PropertyEvaluator baseEval;
369
        private final String prefix;
370
        private final AntProjectHelper helper;
371
372
        @SuppressWarnings("LeakingThisInConstructor")
373
        public ConfigPropertyProvider(PropertyEvaluator baseEval, String prefix, AntProjectHelper helper) {
374
            super(computeDelegate(baseEval, prefix, helper));
375
            this.baseEval = baseEval;
376
            this.prefix = prefix;
377
            this.helper = helper;
378
            baseEval.addPropertyChangeListener(this);
379
        }
380
381
        @Override
382
        public void propertyChange(PropertyChangeEvent ev) {
383
            if (ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG.equals(ev.getPropertyName())) {
384
                setDelegate(computeDelegate(baseEval, prefix, helper));
385
            }
386
        }
387
        private static PropertyProvider computeDelegate(PropertyEvaluator baseEval, String prefix, AntProjectHelper helper) {
388
            String config = baseEval.getProperty(ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG);
389
            if (config != null) {
390
                return helper.getPropertyProvider(prefix + "/" + config + ".properties"); // NOI18N
391
            } else {
392
                return PropertyUtils.fixedPropertyProvider(Collections.<String,String>emptyMap());
393
            }
394
        }
395
    }
396
}
359
}
(-)a/j2me.project/src/org/netbeans/modules/j2me/project/ui/customizer/J2MECompositeCategoryProvider.java (-1 / +1 lines)
Lines 60-66 Link Here
60
    static final String LIBRARIES = "Libraries";
60
    static final String LIBRARIES = "Libraries";
61
    public static final String BUILD = "Build";
61
    public static final String BUILD = "Build";
62
    private static final String PLATFORM = "Platform";
62
    private static final String PLATFORM = "Platform";
63
    private static final String RUN = "Run";
63
    public static final String RUN = "Run";
64
    private static final String APPLICATION_DESCRIPTOR = "Application Descriptor";
64
    private static final String APPLICATION_DESCRIPTOR = "Application Descriptor";
65
    private static final String OBFUSCATING = "Obfuscating";
65
    private static final String OBFUSCATING = "Obfuscating";
66
    private static final String SIGNING = "Signing";
66
    private static final String SIGNING = "Signing";
(-)a/java.api.common/apichanges.xml (+14 lines)
Lines 105-110 Link Here
105
105
106
    <!-- ACTUAL CHANGES BEGIN HERE: -->
106
    <!-- ACTUAL CHANGES BEGIN HERE: -->
107
    <changes>
107
    <changes>
108
        <change id="ProjectConfigurations">
109
            <api name="java-api-common"/>
110
            <summary>Added <code>ProjectConfigurations</code> support for <code>ProjectConfiguration</code>s in Ant base project.</summary>
111
            <version major="1" minor="64"/>
112
            <date day="23" month="10" year="2013"/>
113
            <author login="tzezula"/>
114
            <compatibility addition="yes"/>
115
            <description>
116
                <p>
117
                   Added <code>ProjectConfigurations</code> support for <code>ProjectConfiguration</code>s in Ant base project.
118
                </p>
119
            </description>
120
            <class package="org.netbeans.modules.java.api.common.project" name="ProjectConfigurations"/>
121
        </change>
108
        <change id="LibrariesNode.Builder">
122
        <change id="LibrariesNode.Builder">
109
            <api name="java-api-common"/>
123
            <api name="java-api-common"/>
110
            <summary>Added <code>LibrariesNode.Builder</code> to create configured <code>LibrariesNode</code>.</summary>
124
            <summary>Added <code>LibrariesNode.Builder</code> to create configured <code>LibrariesNode</code>.</summary>
(-)a/java.api.common/manifest.mf (-1 / +1 lines)
Lines 1-4 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.modules.java.api.common/0
2
OpenIDE-Module: org.netbeans.modules.java.api.common/0
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/api/common/resources/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/api/common/resources/Bundle.properties
4
OpenIDE-Module-Specification-Version: 1.63
4
OpenIDE-Module-Specification-Version: 1.64
(-)a/java.api.common/src/org/netbeans/modules/java/api/common/project/Bundle.properties (+1 lines)
Lines 39-41 Link Here
39
# Portions Copyrighted 2013 Sun Microsystems, Inc.
39
# Portions Copyrighted 2013 Sun Microsystems, Inc.
40
ERR_RegenerateProjectFiles=Cannot regenerate project metadata.
40
ERR_RegenerateProjectFiles=Cannot regenerate project metadata.
41
ERR_ProjectReadOnly=The project folder {0} is read-only.
41
ERR_ProjectReadOnly=The project folder {0} is read-only.
42
TXT_DefaultConfig=<default config>
(-)a/java.api.common/src/org/netbeans/modules/java/api/common/project/ProjectConfigurations.java (+515 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2013 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.java.api.common.project;
44
45
import java.beans.PropertyChangeEvent;
46
import java.beans.PropertyChangeListener;
47
import java.beans.PropertyChangeSupport;
48
import java.io.IOException;
49
import java.io.InputStream;
50
import java.text.Collator;
51
import java.util.ArrayDeque;
52
import java.util.ArrayList;
53
import java.util.Collection;
54
import java.util.Collections;
55
import java.util.Comparator;
56
import java.util.HashMap;
57
import java.util.HashSet;
58
import java.util.List;
59
import java.util.Map;
60
import java.util.Objects;
61
import java.util.Properties;
62
import java.util.Queue;
63
import java.util.Set;
64
import java.util.logging.Level;
65
import java.util.logging.Logger;
66
import org.netbeans.api.annotations.common.CheckForNull;
67
import org.netbeans.api.annotations.common.NonNull;
68
import org.netbeans.api.annotations.common.NullAllowed;
69
import org.netbeans.api.project.Project;
70
import org.netbeans.api.project.ProjectManager;
71
import org.netbeans.modules.java.api.common.ant.UpdateHelper;
72
import org.netbeans.spi.project.ProjectConfiguration;
73
import org.netbeans.spi.project.ProjectConfigurationProvider;
74
import org.netbeans.spi.project.support.ant.AntProjectHelper;
75
import org.netbeans.spi.project.support.ant.EditableProperties;
76
import org.netbeans.spi.project.support.ant.FilterPropertyProvider;
77
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
78
import org.netbeans.spi.project.support.ant.PropertyProvider;
79
import org.netbeans.spi.project.support.ant.PropertyUtils;
80
import org.openide.filesystems.FileChangeAdapter;
81
import org.openide.filesystems.FileChangeListener;
82
import org.openide.filesystems.FileEvent;
83
import org.openide.filesystems.FileObject;
84
import org.openide.filesystems.FileRenameEvent;
85
import org.openide.filesystems.FileUtil;
86
import org.openide.util.NbBundle;
87
import org.openide.util.Parameters;
88
import org.openide.util.Utilities;
89
90
/**
91
 * Support for {@link ProjectConfiguration}s in Ant based project.
92
 * @author Jesse Glick
93
 * @author Tomas Zezula
94
 * @since 1.64
95
 */
96
public class ProjectConfigurations {
97
98
    private static final Logger LOGGER = Logger.getLogger(ProjectConfigurations.class.getName());
99
100
    /**
101
     * Path to the file holding the active configuration.
102
     */
103
    public static final String CONFIG_PROPS_PATH = "nbproject/private/config.properties"; // NOI18N
104
105
    private ProjectConfigurations() {
106
        throw new IllegalStateException("No instance allowed"); //NOI18N
107
    }
108
109
    /**
110
     * Creates a {@link ConfigurationProviderBuilder}.
111
     * @param project the {@link Project} to create builder for
112
     * @param eval the {@link Project}'s {@link PropertyEvaluator}
113
     * @param updateHelper the {@link Project}'s {@link UpdateHelper}
114
     * @return the {@link ConfigurationProviderBuilder}
115
     */
116
    @NonNull
117
    public static ConfigurationProviderBuilder createConfigurationProviderBuilder(
118
            @NonNull final Project project,
119
            @NonNull final PropertyEvaluator eval,
120
            @NonNull final UpdateHelper updateHelper) {
121
        return new ConfigurationProviderBuilder(project, eval, updateHelper);
122
    }
123
124
    /**
125
     * Creates a {@link PropertyEvaluator} with {@link ProjectConfiguration} support.
126
     * @param project the project to create {@link PropertyEvaluator} for
127
     * @param helper the {@link Project}'s {@link AntProjectHelper}
128
     * @param additionalPropertyProviders the additional {@link PropertyProvider}s
129
     * @return a new {@link PropertyEvaluator}
130
     */
131
    @NonNull
132
    public static PropertyEvaluator createPropertyEvaluator(
133
        @NonNull final Project project,
134
        @NonNull final AntProjectHelper helper,
135
        @NonNull final PropertyProvider... additionalPropertyProviders) {
136
        Parameters.notNull("project", project); //NOI18N
137
        Parameters.notNull("helper", helper);   //NOI18N
138
        Parameters.notNull("additionalPropertyProviders", additionalPropertyProviders); //NOI18N
139
140
        PropertyEvaluator baseEval1 = PropertyUtils.sequentialPropertyEvaluator(
141
                helper.getStockPropertyPreprovider(),
142
                helper.getPropertyProvider(ProjectConfigurations.CONFIG_PROPS_PATH));
143
        PropertyEvaluator baseEval2 = PropertyUtils.sequentialPropertyEvaluator(
144
                helper.getStockPropertyPreprovider(),
145
                helper.getPropertyProvider(AntProjectHelper.PRIVATE_PROPERTIES_PATH));
146
        final Queue<PropertyProvider> providers = new ArrayDeque<>(additionalPropertyProviders.length + 7);
147
        providers.offer(helper.getPropertyProvider(ProjectConfigurations.CONFIG_PROPS_PATH));
148
        providers.offer(new ConfigPropertyProvider(baseEval1, "nbproject/private/configs", helper));    //NOI18N
149
        providers.offer(helper.getPropertyProvider(AntProjectHelper.PRIVATE_PROPERTIES_PATH));
150
        providers.offer(helper.getProjectLibrariesPropertyProvider());
151
        providers.offer(PropertyUtils.userPropertiesProvider(baseEval2,
152
            "user.properties.file", FileUtil.toFile(project.getProjectDirectory())));   //NOI18N
153
        providers.offer(new ConfigPropertyProvider(baseEval1, "nbproject/configs", helper));    //NOI18N
154
        providers.offer(helper.getPropertyProvider(AntProjectHelper.PROJECT_PROPERTIES_PATH));
155
        Collections.addAll(providers, additionalPropertyProviders);
156
        return PropertyUtils.sequentialPropertyEvaluator(
157
            helper.getStockPropertyPreprovider(),
158
            providers.toArray(new PropertyProvider[providers.size()]));
159
    }
160
161
    /**
162
     * Builder for {@link ProjectConfigurationProvider}.
163
     */
164
    public static final class ConfigurationProviderBuilder {
165
166
        private final Project project;
167
        private final PropertyEvaluator eval;
168
        private final UpdateHelper updateHelper;
169
        private final Set<String> configurationsAffectActions;
170
        private Runnable customizerAction;
171
172
        private ConfigurationProviderBuilder(
173
                @NonNull final Project project,
174
                @NonNull final PropertyEvaluator eval,
175
                @NonNull final UpdateHelper updateHelper) {
176
            Parameters.notNull("project", project); //NOI18N
177
            Parameters.notNull("eval", eval);   //NOI18N
178
            Parameters.notNull("updateHelper", updateHelper);   //NOI18N
179
            this.project = project;
180
            this.eval = eval;
181
            this.updateHelper = updateHelper;
182
            this.configurationsAffectActions = new HashSet<>();
183
        }
184
185
        /**
186
         * Sets actions affected by the configurations.
187
         * @param commands the actions affected by configurations
188
         * @return the {@link ConfigurationProviderBuilder}
189
         */
190
        @NonNull
191
        public ConfigurationProviderBuilder addConfigurationsAffectActions(@NonNull final String... commands) {
192
            Parameters.notNull("commands", commands);   //NOI18N
193
            Collections.addAll(configurationsAffectActions, commands);
194
            return this;
195
        }
196
197
        /**
198
         * Sets an action showing the customizer for {@link ProjectConfiguration}s.
199
         * @param action the action
200
         * @return the {@link ConfigurationProviderBuilder}
201
         */
202
        @NonNull
203
        public ConfigurationProviderBuilder setCustomizerAction(@NonNull final Runnable action) {
204
            Parameters.notNull("action", action);   //NOI18N
205
            this.customizerAction = action;
206
            return this;
207
        }
208
209
        /**
210
         * Creates a configured {@link ProjectConfigurationProvider}.
211
         * @return a new configured instance of {@link ProjectConfigurationProvider}
212
         */
213
        @NonNull
214
        public ProjectConfigurationProvider<? extends ProjectConfiguration> build() {
215
            return new ConfigurationProviderImpl(
216
                project,
217
                eval,
218
                updateHelper,
219
                configurationsAffectActions,
220
                customizerAction);
221
        }
222
    }
223
224
    /**
225
     * The {@link ProjectConfiguration} implementation.
226
     */
227
    public static final class Configuration implements ProjectConfiguration {
228
        private final String name;
229
        private final String displayName;
230
231
        private Configuration(
232
                @NullAllowed final String name,
233
                @NonNull final String displayName) {
234
            Parameters.notNull("displayName", displayName); //NOI18N
235
            this.name = name;
236
            this.displayName = displayName;
237
        }
238
239
        /**
240
         * Returns the system name of the configuration.
241
         * @return the system name of configuration
242
         */
243
        @CheckForNull
244
        public String getName() {
245
            return name;
246
        }
247
248
        /**
249
         * Checks if the {@link Configuration} is a default one.
250
         * @return true when the {@link Configuration} is default
251
         */
252
        public boolean isDefault() {
253
            return name == null;
254
        }
255
256
        @Override
257
        @NonNull
258
        public String getDisplayName() {
259
            return displayName;
260
        }
261
262
        @Override
263
        public int hashCode() {
264
            return Objects.hashCode(name);
265
        }
266
267
        @Override
268
        public boolean equals(Object o) {
269
            return (o instanceof Configuration) && Objects.equals(name, ((Configuration) o).name);
270
        }
271
272
        @Override
273
        public String toString() {
274
            return "Config[" + name + "," + displayName + "]"; // NOI18N
275
        }
276
    }
277
278
    private static final class ConfigurationProviderImpl implements ProjectConfigurationProvider<Configuration> {
279
280
        private static final Configuration DEFAULT = new Configuration(
281
            null,
282
            NbBundle.getMessage(ProjectConfigurations.class, "TXT_DefaultConfig"));
283
284
        private final Project p;
285
        private final PropertyEvaluator eval;
286
        private final UpdateHelper updateHelper;
287
        private final Set<String> configurationsAffectActions;
288
        private final Runnable customizerAction;
289
        private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
290
        private final FileChangeListener fcl = new FileChangeAdapter() {
291
            @Override
292
            public void fileFolderCreated(@NonNull final FileEvent fe) {
293
                update(fe);
294
            }
295
296
            @Override
297
            public void fileDataCreated(@NonNull final FileEvent fe) {
298
                update(fe);
299
            }
300
301
            @Override
302
            public void fileDeleted(@NonNull final FileEvent fe) {
303
                update(fe);
304
            }
305
306
            @Override
307
            public void fileRenamed(@NonNull final FileRenameEvent fe) {
308
                update(fe);
309
            }
310
311
            private void update(@NonNull final FileEvent ev) {
312
                Parameters.notNull("ev", ev);   //NOI18N
313
                LOGGER.log(Level.FINEST, "Received {0}", ev);
314
                Set<String> oldConfigs = configs != null ? configs.keySet() : Collections.<String>emptySet();
315
                configDir = p.getProjectDirectory().getFileObject("nbproject/configs"); // NOI18N
316
                if (configDir != null) {
317
                    configDir.removeFileChangeListener(fclWeak);
318
                    configDir.addFileChangeListener(fclWeak);
319
                    LOGGER.log(Level.FINEST, "(Re-)added listener to {0}", configDir);
320
                } else {
321
                    LOGGER.log(Level.FINEST, "No nbproject/configs exists");
322
                }
323
                calculateConfigs();
324
                Set<String> newConfigs = configs.keySet();
325
                if (!oldConfigs.equals(newConfigs)) {
326
                    LOGGER.log(Level.FINER, "Firing " + ProjectConfigurationProvider.PROP_CONFIGURATIONS + ": {0} -> {1}", new Object[] {oldConfigs, newConfigs});
327
                    pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATIONS, null, null);
328
                    // XXX also fire PROP_ACTIVE_CONFIGURATION?
329
                }
330
            }
331
        };
332
        private final FileChangeListener fclWeak;
333
        private FileObject configDir;
334
        private Map<String,Configuration> configs;
335
        private FileObject nbp;
336
337
        public ConfigurationProviderImpl(
338
                @NonNull final Project p,
339
                @NonNull final PropertyEvaluator eval,
340
                @NonNull final UpdateHelper updateHelper,
341
                @NonNull final Set<String> configurationsAffectActions,
342
                @NullAllowed final Runnable customizerAction) {
343
            Parameters.notNull("p", p); //NOI18N
344
            Parameters.notNull("eval", eval);   //NOI18N
345
            Parameters.notNull("updateHelper", updateHelper);   //NOI18N
346
            Parameters.notNull("configurationsAffectActions", configurationsAffectActions); //NOI18N
347
            this.p = p;
348
            this.eval = eval;
349
            this.updateHelper = updateHelper;
350
            this.configurationsAffectActions = configurationsAffectActions;
351
            this.customizerAction = customizerAction;
352
            fclWeak = FileUtil.weakFileChangeListener(fcl, null);
353
            nbp = p.getProjectDirectory().getFileObject("nbproject"); // NOI18N
354
            if (nbp != null) {
355
                nbp.addFileChangeListener(fclWeak);
356
                LOGGER.log(Level.FINEST, "Added listener to {0}", nbp);
357
                configDir = nbp.getFileObject("configs"); // NOI18N
358
                if (configDir != null) {
359
                    configDir.addFileChangeListener(fclWeak);
360
                    LOGGER.log(Level.FINEST, "Added listener to {0}", configDir);
361
                }
362
            }
363
            eval.addPropertyChangeListener(new PropertyChangeListener() {
364
                @Override
365
                public void propertyChange(@NonNull final PropertyChangeEvent evt) {
366
                    if (ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG.equals(evt.getPropertyName())) {
367
                        LOGGER.log(Level.FINER, "Refiring " + ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG + " -> " + ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE);
368
                        Set<String> oldConfigs = configs != null ? configs.keySet() : Collections.<String>emptySet();
369
                        calculateConfigs();
370
                        Set<String> newConfigs = configs.keySet();
371
                        if (!oldConfigs.equals(newConfigs)) {
372
                            LOGGER.log(Level.FINER, "Firing " + ProjectConfigurationProvider.PROP_CONFIGURATIONS + ": {0} -> {1}", new Object[] {oldConfigs, newConfigs});
373
                            pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATIONS, null, null);
374
                        }
375
                        pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE, null, null);
376
                    }
377
                }
378
            });
379
        }
380
381
        private void calculateConfigs() {
382
            configs = new HashMap<String,Configuration>();
383
            if (configDir != null) {
384
                for (FileObject kid : configDir.getChildren()) {
385
                    if (!kid.hasExt("properties")) {    //NOI18N
386
                        continue;
387
                    }
388
                    try {
389
                        try (InputStream is = kid.getInputStream()) {
390
                            final Properties props = new Properties();
391
                            props.load(is);
392
                            final String name = kid.getName();
393
                            final String label = props.getProperty("$label"); // NOI18N
394
                            configs.put(name, new Configuration(name, label != null ? label : name));
395
                        }
396
                    } catch (IOException x) {
397
                        LOGGER.log(Level.INFO, null, x);
398
                    }
399
                }
400
            }
401
            LOGGER.log(Level.FINEST, "Calculated configurations: {0}", configs);
402
        }
403
404
        @NonNull
405
        @Override
406
        public Collection<Configuration> getConfigurations() {
407
            calculateConfigs();
408
            List<Configuration> l = new ArrayList<Configuration>();
409
            l.addAll(configs.values());
410
            Collections.sort(l, new Comparator<Configuration>() {
411
                Collator c = Collator.getInstance();
412
                @Override
413
                public int compare(Configuration c1, Configuration c2) {
414
                    return c.compare(c1.getDisplayName(), c2.getDisplayName());
415
                }
416
            });
417
            l.add(0, DEFAULT);
418
            return l;
419
        }
420
421
        @NonNull
422
        @Override
423
        public Configuration getActiveConfiguration() {
424
            calculateConfigs();
425
            String config = eval.getProperty(ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG);
426
            if (config != null && configs.containsKey(config)) {
427
                return configs.get(config);
428
            } else {
429
                return DEFAULT;
430
            }
431
        }
432
433
        @Override
434
        public void setActiveConfiguration(@NonNull final Configuration c) throws IllegalArgumentException, IOException {
435
            if (c != DEFAULT && !configs.values().contains(c)) {
436
                throw new IllegalArgumentException(String.valueOf(c));
437
            }
438
            final String n = c.name;
439
            EditableProperties ep = updateHelper.getProperties(CONFIG_PROPS_PATH);
440
            if (Utilities.compareObjects(n, ep.getProperty(ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG))) {
441
                return;
442
            }
443
            if (n != null) {
444
                ep.setProperty(ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG, n);
445
            } else {
446
                ep.remove(ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG);
447
            }
448
            updateHelper.putProperties(CONFIG_PROPS_PATH, ep);
449
            pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE, null, null);
450
            ProjectManager.getDefault().saveProject(p);
451
            assert p.getProjectDirectory().getFileObject(CONFIG_PROPS_PATH) != null;
452
        }
453
454
        @Override
455
        public boolean hasCustomizer() {
456
            return customizerAction != null;
457
        }
458
459
        @Override
460
        public void customize() {
461
            if (customizerAction != null) {
462
                customizerAction.run();
463
            }
464
        }
465
466
467
        @Override
468
        public boolean configurationsAffectAction(@NonNull final String command) {
469
            return configurationsAffectActions.contains(command);
470
        }
471
472
        @Override
473
        public void addPropertyChangeListener(@NonNull final PropertyChangeListener lst) {
474
            Parameters.notNull("lst", lst);     //NOI18N
475
            pcs.addPropertyChangeListener(lst);
476
        }
477
478
        @Override
479
        public void removePropertyChangeListener(@NonNull final PropertyChangeListener lst) {
480
            Parameters.notNull("lst", lst);     //NOI18N
481
            pcs.removePropertyChangeListener(lst);
482
        }
483
    }
484
485
    private static final class ConfigPropertyProvider extends FilterPropertyProvider implements PropertyChangeListener {
486
        private final PropertyEvaluator baseEval;
487
        private final String prefix;
488
        private final AntProjectHelper helper;
489
490
        @SuppressWarnings("LeakingThisInConstructor")
491
        public ConfigPropertyProvider(PropertyEvaluator baseEval, String prefix, AntProjectHelper helper) {
492
            super(computeDelegate(baseEval, prefix, helper));
493
            this.baseEval = baseEval;
494
            this.prefix = prefix;
495
            this.helper = helper;
496
            baseEval.addPropertyChangeListener(this);
497
        }
498
499
        @Override
500
        public void propertyChange(PropertyChangeEvent ev) {
501
            if (ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG.equals(ev.getPropertyName())) {
502
                setDelegate(computeDelegate(baseEval, prefix, helper));
503
            }
504
        }
505
506
        private static PropertyProvider computeDelegate(PropertyEvaluator baseEval, String prefix, AntProjectHelper helper) {
507
            String config = baseEval.getProperty(ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG);
508
            if (config != null) {
509
                return helper.getPropertyProvider(prefix + "/" + config + ".properties"); // NOI18N
510
            } else {
511
                return PropertyUtils.fixedPropertyProvider(Collections.<String,String>emptyMap());
512
            }
513
        }
514
    }
515
}
(-)a/java.j2seproject/nbproject/project.xml (-1 / +1 lines)
Lines 142-148 Link Here
142
                    <compile-dependency/>
142
                    <compile-dependency/>
143
                    <run-dependency>
143
                    <run-dependency>
144
                        <release-version>0-1</release-version>
144
                        <release-version>0-1</release-version>
145
                        <specification-version>1.62</specification-version>
145
                        <specification-version>1.64</specification-version>
146
                    </run-dependency>
146
                    </run-dependency>
147
                </dependency>
147
                </dependency>
148
                <dependency>
148
                <dependency>
(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEActionProvider.java (-3 / +4 lines)
Lines 62-67 Link Here
62
import org.netbeans.modules.java.api.common.project.ProjectProperties;
62
import org.netbeans.modules.java.api.common.project.ProjectProperties;
63
import org.netbeans.modules.java.api.common.project.BaseActionProvider;
63
import org.netbeans.modules.java.api.common.project.BaseActionProvider;
64
import org.netbeans.modules.java.api.common.project.BaseActionProvider.Callback3;
64
import org.netbeans.modules.java.api.common.project.BaseActionProvider.Callback3;
65
import org.netbeans.modules.java.api.common.project.ProjectConfigurations;
65
import org.netbeans.modules.java.j2seproject.api.J2SEBuildPropertiesProvider;
66
import org.netbeans.modules.java.j2seproject.api.J2SEBuildPropertiesProvider;
66
import org.netbeans.spi.project.ActionProvider;
67
import org.netbeans.spi.project.ActionProvider;
67
import org.netbeans.spi.project.LookupProvider;
68
import org.netbeans.spi.project.LookupProvider;
Lines 219-229 Link Here
219
    @Override
220
    @Override
220
    public String[] getTargetNames(String command, Lookup context, Properties p, boolean doJavaChecks) throws IllegalArgumentException {
221
    public String[] getTargetNames(String command, Lookup context, Properties p, boolean doJavaChecks) throws IllegalArgumentException {
221
        String names[] = super.getTargetNames(command, context, p, doJavaChecks);
222
        String names[] = super.getTargetNames(command, context, p, doJavaChecks);
222
        J2SEConfigurationProvider.Config c = context.lookup(J2SEConfigurationProvider.Config.class);
223
        ProjectConfigurations.Configuration c = context.lookup(ProjectConfigurations.Configuration.class);
223
        if (c != null) {
224
        if (c != null) {
224
            String config;
225
            String config;
225
            if (c.name != null) {
226
            if (!c.isDefault()) {
226
                config = c.name;
227
                config = c.getName();
227
            } else {
228
            } else {
228
                // Invalid but overrides any valid setting in config.properties.
229
                // Invalid but overrides any valid setting in config.properties.
229
                config = "";
230
                config = "";
(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEConfigurationProvider.java (-282 lines)
Lines 1-282 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.java.j2seproject;
44
45
import java.beans.PropertyChangeEvent;
46
import java.beans.PropertyChangeListener;
47
import java.beans.PropertyChangeSupport;
48
import java.io.IOException;
49
import java.io.InputStream;
50
import java.text.Collator;
51
import java.util.ArrayList;
52
import java.util.Collection;
53
import java.util.Collections;
54
import java.util.Comparator;
55
import java.util.HashMap;
56
import java.util.List;
57
import java.util.Map;
58
import java.util.Properties;
59
import java.util.Set;
60
import java.util.logging.Level;
61
import java.util.logging.Logger;
62
import org.netbeans.api.project.ProjectManager;
63
import org.netbeans.modules.java.api.common.project.ProjectProperties;
64
import org.netbeans.modules.java.j2seproject.ui.customizer.CustomizerProviderImpl;
65
import org.netbeans.modules.java.j2seproject.ui.customizer.J2SECompositePanelProvider;
66
import org.netbeans.spi.project.ActionProvider;
67
import org.netbeans.spi.project.ProjectConfiguration;
68
import org.netbeans.spi.project.ProjectConfigurationProvider;
69
import org.netbeans.spi.project.support.ant.EditableProperties;
70
import org.openide.filesystems.FileChangeAdapter;
71
import org.openide.filesystems.FileChangeListener;
72
import org.openide.filesystems.FileEvent;
73
import org.openide.filesystems.FileObject;
74
import org.openide.filesystems.FileRenameEvent;
75
import org.openide.filesystems.FileUtil;
76
import org.openide.util.NbBundle;
77
import org.openide.util.Utilities;
78
79
/**
80
 * Manages configurations for a Java SE project.
81
 * @author Jesse Glick
82
 */
83
final class J2SEConfigurationProvider implements ProjectConfigurationProvider<J2SEConfigurationProvider.Config> {
84
85
    private static final Logger LOGGER = Logger.getLogger(J2SEConfigurationProvider.class.getName());
86
87
    /**
88
     * Ant property name for active config.
89
     */
90
    public static final String PROP_CONFIG = ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG;
91
    /**
92
     * Ant property file which specified active config.
93
     */
94
    public static final String CONFIG_PROPS_PATH = "nbproject/private/config.properties"; // NOI18N
95
96
    public static final class Config implements ProjectConfiguration {
97
        /** file basename, or null for default config */
98
        public final String name;
99
        private final String displayName;
100
        public Config(String name, String displayName) {
101
            this.name = name;
102
            this.displayName = displayName;
103
        }
104
        public String getDisplayName() {
105
            return displayName;
106
        }
107
        public int hashCode() {
108
            return name != null ? name.hashCode() : 0;
109
        }
110
        public boolean equals(Object o) {
111
            return (o instanceof Config) && Utilities.compareObjects(name, ((Config) o).name);
112
        }
113
        public String toString() {
114
            return "J2SEConfigurationProvider.Config[" + name + "," + displayName + "]"; // NOI18N
115
        }
116
    }
117
118
    private static final Config DEFAULT = new Config(null,
119
            NbBundle.getMessage(J2SEConfigurationProvider.class, "J2SEConfigurationProvider.default.label"));
120
121
    private final J2SEProject p;
122
    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
123
    private final FileChangeListener fcl = new FileChangeAdapter() {
124
        public void fileFolderCreated(FileEvent fe) {
125
            update(fe);
126
        }
127
        public void fileDataCreated(FileEvent fe) {
128
            update(fe);
129
        }
130
        public void fileDeleted(FileEvent fe) {
131
            update(fe);
132
        }
133
        public void fileRenamed(FileRenameEvent fe) {
134
            update(fe);
135
        }
136
        private void update(FileEvent ev) {
137
            LOGGER.log(Level.FINEST, "Received {0}", ev);
138
            Set<String> oldConfigs = configs != null ? configs.keySet() : Collections.<String>emptySet();
139
            configDir = p.getProjectDirectory().getFileObject("nbproject/configs"); // NOI18N
140
            if (configDir != null) {
141
                configDir.removeFileChangeListener(fclWeak);
142
                configDir.addFileChangeListener(fclWeak);
143
                LOGGER.log(Level.FINEST, "(Re-)added listener to {0}", configDir);
144
            } else {
145
                LOGGER.log(Level.FINEST, "No nbproject/configs exists");
146
            }
147
            calculateConfigs();
148
            Set<String> newConfigs = configs.keySet();
149
            if (!oldConfigs.equals(newConfigs)) {
150
                LOGGER.log(Level.FINER, "Firing " + ProjectConfigurationProvider.PROP_CONFIGURATIONS + ": {0} -> {1}", new Object[] {oldConfigs, newConfigs});
151
                pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATIONS, null, null);
152
                // XXX also fire PROP_ACTIVE_CONFIGURATION?
153
            }
154
        }
155
    };
156
    private final FileChangeListener fclWeak;
157
    private FileObject configDir;
158
    private Map<String,Config> configs;
159
    private FileObject nbp;
160
    
161
    public J2SEConfigurationProvider(J2SEProject p) {
162
        this.p = p;
163
        fclWeak = FileUtil.weakFileChangeListener(fcl, null);
164
        nbp = p.getProjectDirectory().getFileObject("nbproject"); // NOI18N
165
        if (nbp != null) {
166
            nbp.addFileChangeListener(fclWeak);
167
            LOGGER.log(Level.FINEST, "Added listener to {0}", nbp);
168
            configDir = nbp.getFileObject("configs"); // NOI18N
169
            if (configDir != null) {
170
                configDir.addFileChangeListener(fclWeak);
171
                LOGGER.log(Level.FINEST, "Added listener to {0}", configDir);
172
            }
173
        }
174
        p.evaluator().addPropertyChangeListener(new PropertyChangeListener() {
175
            public void propertyChange(PropertyChangeEvent evt) {
176
                if (PROP_CONFIG.equals(evt.getPropertyName())) {
177
                    LOGGER.log(Level.FINER, "Refiring " + PROP_CONFIG + " -> " + ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE);
178
                    Set<String> oldConfigs = configs != null ? configs.keySet() : Collections.<String>emptySet();
179
                    calculateConfigs();
180
                    Set<String> newConfigs = configs.keySet();
181
                    if (!oldConfigs.equals(newConfigs)) {
182
                        LOGGER.log(Level.FINER, "Firing " + ProjectConfigurationProvider.PROP_CONFIGURATIONS + ": {0} -> {1}", new Object[] {oldConfigs, newConfigs});
183
                        pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATIONS, null, null);
184
                    }
185
                    pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE, null, null);
186
                }
187
            }
188
        });
189
    }
190
191
    private void calculateConfigs() {
192
        configs = new HashMap<String,Config>();
193
        if (configDir != null) {
194
            for (FileObject kid : configDir.getChildren()) {
195
                if (!kid.hasExt("properties")) {
196
                    continue;
197
                }
198
                try {
199
                    InputStream is = kid.getInputStream();
200
                    try {
201
                        Properties p = new Properties();
202
                        p.load(is);
203
                        String name = kid.getName();
204
                        String label = p.getProperty("$label"); // NOI18N
205
                        configs.put(name, new Config(name, label != null ? label : name));
206
                    } finally {
207
                        is.close();
208
                    }
209
                } catch (IOException x) {
210
                    LOGGER.log(Level.INFO, null, x);
211
                }
212
            }
213
        }
214
        LOGGER.log(Level.FINEST, "Calculated configurations: {0}", configs);
215
    }
216
217
    public Collection<Config> getConfigurations() {
218
        calculateConfigs();
219
        List<Config> l = new ArrayList<Config>();
220
        l.addAll(configs.values());
221
        Collections.sort(l, new Comparator<Config>() {
222
            Collator c = Collator.getInstance();
223
            public int compare(Config c1, Config c2) {
224
                return c.compare(c1.getDisplayName(), c2.getDisplayName());
225
            }
226
        });
227
        l.add(0, DEFAULT);
228
        return l;
229
    }
230
231
    public Config getActiveConfiguration() {
232
        calculateConfigs();
233
        String config = p.evaluator().getProperty(PROP_CONFIG);
234
        if (config != null && configs.containsKey(config)) {
235
            return configs.get(config);
236
        } else {
237
            return DEFAULT;
238
        }
239
    }
240
241
    public void setActiveConfiguration(Config c) throws IllegalArgumentException, IOException {
242
        if (c != DEFAULT && !configs.values().contains(c)) {
243
            throw new IllegalArgumentException();
244
        }
245
        final String n = c.name;
246
        EditableProperties ep = p.getUpdateHelper().getProperties(CONFIG_PROPS_PATH);
247
        if (Utilities.compareObjects(n, ep.getProperty(PROP_CONFIG))) {
248
            return;
249
        }
250
        if (n != null) {
251
            ep.setProperty(PROP_CONFIG, n);
252
        } else {
253
            ep.remove(PROP_CONFIG);
254
        }
255
        p.getUpdateHelper().putProperties(CONFIG_PROPS_PATH, ep);
256
        pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE, null, null);
257
        ProjectManager.getDefault().saveProject(p);
258
        assert p.getProjectDirectory().getFileObject(CONFIG_PROPS_PATH) != null;
259
    }
260
261
    public boolean hasCustomizer() {
262
        return true;
263
    }
264
265
    public void customize() {
266
        p.getLookup().lookup(CustomizerProviderImpl.class).showCustomizer(J2SECompositePanelProvider.RUN);
267
    }
268
269
    public boolean configurationsAffectAction(String command) {
270
        return command.equals(ActionProvider.COMMAND_RUN) ||
271
               command.equals(ActionProvider.COMMAND_DEBUG);
272
    }
273
274
    public void addPropertyChangeListener(PropertyChangeListener lst) {
275
        pcs.addPropertyChangeListener(lst);
276
    }
277
278
    public void removePropertyChangeListener(PropertyChangeListener lst) {
279
        pcs.removePropertyChangeListener(lst);
280
    }
281
282
}
(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java (-55 / +21 lines)
Lines 89-104 Link Here
89
import org.netbeans.modules.java.api.common.ant.UpdateHelper;
89
import org.netbeans.modules.java.api.common.ant.UpdateHelper;
90
import org.netbeans.modules.java.api.common.classpath.ClassPathModifier;
90
import org.netbeans.modules.java.api.common.classpath.ClassPathModifier;
91
import org.netbeans.modules.java.api.common.classpath.ClassPathProviderImpl;
91
import org.netbeans.modules.java.api.common.classpath.ClassPathProviderImpl;
92
import org.netbeans.modules.java.api.common.project.ProjectConfigurations;
92
import org.netbeans.modules.java.api.common.project.ProjectHooks;
93
import org.netbeans.modules.java.api.common.project.ProjectHooks;
93
import org.netbeans.modules.java.api.common.project.ProjectProperties;
94
import org.netbeans.modules.java.api.common.project.ProjectProperties;
94
import org.netbeans.modules.java.api.common.project.ui.LogicalViewProviders;
95
import org.netbeans.modules.java.api.common.project.ui.LogicalViewProviders;
95
import org.netbeans.modules.java.api.common.queries.QuerySupport;
96
import org.netbeans.modules.java.api.common.queries.QuerySupport;
96
import org.netbeans.modules.java.j2seproject.api.J2SEPropertyEvaluator;
97
import org.netbeans.modules.java.j2seproject.api.J2SEPropertyEvaluator;
97
import org.netbeans.modules.java.j2seproject.ui.customizer.CustomizerProviderImpl;
98
import org.netbeans.modules.java.j2seproject.ui.customizer.CustomizerProviderImpl;
99
import org.netbeans.modules.java.j2seproject.ui.customizer.J2SECompositePanelProvider;
98
import org.netbeans.modules.project.ui.spi.TemplateCategorySorter;
100
import org.netbeans.modules.project.ui.spi.TemplateCategorySorter;
99
import org.netbeans.spi.java.project.support.ExtraSourceJavadocSupport;
101
import org.netbeans.spi.java.project.support.ExtraSourceJavadocSupport;
100
import org.netbeans.spi.java.project.support.LookupMergerSupport;
102
import org.netbeans.spi.java.project.support.LookupMergerSupport;
101
import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport;
103
import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport;
104
import org.netbeans.spi.project.ActionProvider;
102
import org.netbeans.spi.project.AuxiliaryConfiguration;
105
import org.netbeans.spi.project.AuxiliaryConfiguration;
103
import org.netbeans.spi.project.ant.AntArtifactProvider;
106
import org.netbeans.spi.project.ant.AntArtifactProvider;
104
import org.netbeans.spi.project.ant.AntBuildExtenderFactory;
107
import org.netbeans.spi.project.ant.AntBuildExtenderFactory;
Lines 193-198 Link Here
193
     */
196
     */
194
    private final ThreadLocal<Boolean> projectPropertiesSave;
197
    private final ThreadLocal<Boolean> projectPropertiesSave;
195
198
199
    @SuppressWarnings("LeakingThisInConstructor")
196
    public J2SEProject(AntProjectHelper helper) throws IOException {
200
    public J2SEProject(AntProjectHelper helper) throws IOException {
197
        this.projectPropertiesSave = new ThreadLocal<Boolean>() {
201
        this.projectPropertiesSave = new ThreadLocal<Boolean>() {
198
            @Override
202
            @Override
Lines 204-210 Link Here
204
        aux = helper.createAuxiliaryConfiguration();
208
        aux = helper.createAuxiliaryConfiguration();
205
        UpdateProjectImpl updateProject = new UpdateProjectImpl(this, helper, aux);
209
        UpdateProjectImpl updateProject = new UpdateProjectImpl(this, helper, aux);
206
        this.updateHelper = new UpdateHelper(updateProject, helper);
210
        this.updateHelper = new UpdateHelper(updateProject, helper);
207
        eval = createEvaluator();
211
        eval = ProjectConfigurations.createPropertyEvaluator(this, helper, UPDATE_PROPERTIES);
208
        for (int v = 4; v < 10; v++) {
212
        for (int v = 4; v < 10; v++) {
209
            if (aux.getConfigurationFragment("data", "http://www.netbeans.org/ns/j2se-project/" + v, true) != null) { // NOI18N
213
            if (aux.getConfigurationFragment("data", "http://www.netbeans.org/ns/j2se-project/" + v, true) != null) { // NOI18N
210
                throw Exceptions.attachLocalizedMessage(new IOException("too new"), // NOI18N
214
                throw Exceptions.attachLocalizedMessage(new IOException("too new"), // NOI18N
Lines 253-312 Link Here
253
    public String toString() {
257
    public String toString() {
254
        return "J2SEProject[" + FileUtil.getFileDisplayName(getProjectDirectory()) + "]"; // NOI18N
258
        return "J2SEProject[" + FileUtil.getFileDisplayName(getProjectDirectory()) + "]"; // NOI18N
255
    }
259
    }
256
260
        
257
    private PropertyEvaluator createEvaluator() {
258
        // It is currently safe to not use the UpdateHelper for PropertyEvaluator; UH.getProperties() delegates to APH
259
        // Adapted from APH.getStandardPropertyEvaluator (delegates to ProjectProperties):
260
        PropertyEvaluator baseEval1 = PropertyUtils.sequentialPropertyEvaluator(
261
                helper.getStockPropertyPreprovider(),
262
                helper.getPropertyProvider(J2SEConfigurationProvider.CONFIG_PROPS_PATH));
263
        PropertyEvaluator baseEval2 = PropertyUtils.sequentialPropertyEvaluator(
264
                helper.getStockPropertyPreprovider(),
265
                helper.getPropertyProvider(AntProjectHelper.PRIVATE_PROPERTIES_PATH));
266
        return PropertyUtils.sequentialPropertyEvaluator(
267
                helper.getStockPropertyPreprovider(),
268
                helper.getPropertyProvider(J2SEConfigurationProvider.CONFIG_PROPS_PATH),
269
                new ConfigPropertyProvider(baseEval1, "nbproject/private/configs", helper), // NOI18N
270
                helper.getPropertyProvider(AntProjectHelper.PRIVATE_PROPERTIES_PATH),
271
                helper.getProjectLibrariesPropertyProvider(),
272
                PropertyUtils.userPropertiesProvider(baseEval2,
273
                    "user.properties.file", FileUtil.toFile(getProjectDirectory())), // NOI18N
274
                new ConfigPropertyProvider(baseEval1, "nbproject/configs", helper), // NOI18N
275
                helper.getPropertyProvider(AntProjectHelper.PROJECT_PROPERTIES_PATH),
276
                UPDATE_PROPERTIES);
277
    }
278
    private static final class ConfigPropertyProvider extends FilterPropertyProvider implements PropertyChangeListener {
279
        private final PropertyEvaluator baseEval;
280
        private final String prefix;
281
        private final AntProjectHelper helper;
282
283
        @SuppressWarnings("LeakingThisInConstructor")
284
        public ConfigPropertyProvider(PropertyEvaluator baseEval, String prefix, AntProjectHelper helper) {
285
            super(computeDelegate(baseEval, prefix, helper));
286
            this.baseEval = baseEval;
287
            this.prefix = prefix;
288
            this.helper = helper;
289
            baseEval.addPropertyChangeListener(this);
290
        }
291
292
        @Override
293
        public void propertyChange(PropertyChangeEvent ev) {
294
            if (J2SEConfigurationProvider.PROP_CONFIG.equals(ev.getPropertyName())) {
295
                setDelegate(computeDelegate(baseEval, prefix, helper));
296
            }
297
        }
298
        private static PropertyProvider computeDelegate(PropertyEvaluator baseEval, String prefix, AntProjectHelper helper) {
299
            String config = baseEval.getProperty(J2SEConfigurationProvider.PROP_CONFIG);
300
            if (config != null) {
301
                return helper.getPropertyProvider(prefix + "/" + config + ".properties"); // NOI18N
302
            } else {
303
                return PropertyUtils.fixedPropertyProvider(Collections.<String,String>emptyMap());
304
            }
305
        }
306
    }
307
308
    private static final PropertyProvider UPDATE_PROPERTIES;
261
    private static final PropertyProvider UPDATE_PROPERTIES;
309
310
    static {
262
    static {
311
        Map<String, String> defs = new HashMap<String, String>();
263
        Map<String, String> defs = new HashMap<String, String>();
312
264
Lines 400-406 Link Here
400
            buildExtender,
352
            buildExtender,
401
            cpMod,
353
            cpMod,
402
            ops,
354
            ops,
403
            new J2SEConfigurationProvider(this),
355
            ProjectConfigurations.createConfigurationProviderBuilder(this, eval, updateHelper).
356
                    addConfigurationsAffectActions(ActionProvider.COMMAND_RUN, ActionProvider.COMMAND_DEBUG).
357
                    setCustomizerAction(newConfigCustomizerAction()).
358
                    build(),
404
            new J2SEPersistenceProvider(this, cpProvider),
359
            new J2SEPersistenceProvider(this, cpProvider),
405
            UILookupMergerSupport.createPrivilegedTemplatesMerger(),
360
            UILookupMergerSupport.createPrivilegedTemplatesMerger(),
406
            UILookupMergerSupport.createRecommendedTemplatesMerger(),
361
            UILookupMergerSupport.createRecommendedTemplatesMerger(),
Lines 983-988 Link Here
983
    }
938
    }
984
939
985
    @NonNull
940
    @NonNull
941
    private Runnable newConfigCustomizerAction() {
942
        return new Runnable() {
943
            @Override
944
            public void run() {
945
                J2SEProject.this.getLookup().lookup(CustomizerProviderImpl.class).
946
                    showCustomizer(J2SECompositePanelProvider.RUN);
947
            }
948
        };
949
    }
950
951
    @NonNull
986
    private LogicalViewProviders.CompileOnSaveBadge newCoSBadge() {
952
    private LogicalViewProviders.CompileOnSaveBadge newCoSBadge() {
987
        return new LogicalViewProviders.CompileOnSaveBadge() {
953
        return new LogicalViewProviders.CompileOnSaveBadge() {
988
            @Override
954
            @Override
(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProjectOperations.java (-1 / +2 lines)
Lines 61-66 Link Here
61
import org.netbeans.api.project.ProjectInformation;
61
import org.netbeans.api.project.ProjectInformation;
62
import org.netbeans.api.project.ProjectManager;
62
import org.netbeans.api.project.ProjectManager;
63
import org.netbeans.api.project.ProjectUtils;
63
import org.netbeans.api.project.ProjectUtils;
64
import org.netbeans.modules.java.api.common.project.ProjectConfigurations;
64
import org.netbeans.modules.java.api.common.project.ProjectProperties;
65
import org.netbeans.modules.java.api.common.project.ProjectProperties;
65
import org.netbeans.modules.java.j2seproject.ui.customizer.J2SEProjectProperties;
66
import org.netbeans.modules.java.j2seproject.ui.customizer.J2SEProjectProperties;
66
import org.netbeans.spi.project.ActionProvider;
67
import org.netbeans.spi.project.ActionProvider;
Lines 372-378 Link Here
372
    }
373
    }
373
    
374
    
374
    private void rememberConfigurations () {
375
    private void rememberConfigurations () {
375
        FileObject fo = project.getProjectDirectory().getFileObject(J2SEConfigurationProvider.CONFIG_PROPS_PATH);
376
        FileObject fo = project.getProjectDirectory().getFileObject(ProjectConfigurations.CONFIG_PROPS_PATH);
376
        if (fo != null) {
377
        if (fo != null) {
377
            //Has configurations
378
            //Has configurations
378
            try {
379
            try {
(-)a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/MainClassUpdater.java (-1 / +2 lines)
Lines 62-67 Link Here
62
import org.netbeans.api.project.Project;
62
import org.netbeans.api.project.Project;
63
import org.netbeans.api.project.ProjectManager;
63
import org.netbeans.api.project.ProjectManager;
64
import org.netbeans.modules.java.api.common.ant.UpdateHelper;
64
import org.netbeans.modules.java.api.common.ant.UpdateHelper;
65
import org.netbeans.modules.java.api.common.project.ProjectProperties;
65
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
66
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
66
import org.netbeans.spi.project.support.ant.AntProjectHelper;
67
import org.netbeans.spi.project.support.ant.AntProjectHelper;
67
import org.netbeans.spi.project.support.ant.EditableProperties;
68
import org.netbeans.spi.project.support.ant.EditableProperties;
Lines 208-214 Link Here
208
                        }                    
209
                        }                    
209
                        if (newMainClass != null && !newMainClass.equals(oldMainClass) && helper.requestUpdate() &&
210
                        if (newMainClass != null && !newMainClass.equals(oldMainClass) && helper.requestUpdate() &&
210
                                // XXX ##84806: ideally should update nbproject/configs/*.properties in this case:
211
                                // XXX ##84806: ideally should update nbproject/configs/*.properties in this case:
211
                            eval.getProperty(J2SEConfigurationProvider.PROP_CONFIG) == null) {
212
                            eval.getProperty(ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG) == null) {
212
                            final String newMainClassFinal = newMainClass;
213
                            final String newMainClassFinal = newMainClass;
213
                            ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Void>() {
214
                            ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Void>() {
214
                                @Override
215
                                @Override

Return to bug 237548