001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.java.j2seproject.ui.customizer;
043:
044: import java.io.File;
045: import java.io.IOException;
046: import java.net.MalformedURLException;
047: import java.net.URL;
048: import java.nio.charset.Charset;
049: import java.nio.charset.UnsupportedCharsetException;
050: import java.util.Comparator;
051: import java.util.HashMap;
052: import java.util.HashSet;
053: import java.util.Map;
054: import java.util.Set;
055: import java.util.TreeMap;
056: import java.util.Vector;
057: import javax.swing.ButtonModel;
058: import javax.swing.ComboBoxModel;
059: import javax.swing.DefaultListModel;
060: import javax.swing.JButton;
061: import javax.swing.JToggleButton;
062: import javax.swing.ListCellRenderer;
063: import javax.swing.table.DefaultTableModel;
064: import javax.swing.text.BadLocationException;
065: import javax.swing.text.Document;
066: import javax.swing.text.PlainDocument;
067: import org.netbeans.api.queries.FileEncodingQuery;
068: import org.netbeans.api.project.ProjectManager;
069: import org.netbeans.api.project.ProjectUtils;
070: import org.netbeans.modules.java.api.common.SourceRoots;
071: import org.netbeans.modules.java.api.common.ant.UpdateHelper;
072: import org.netbeans.modules.java.api.common.ui.PlatformUiSupport;
073: import org.netbeans.modules.java.j2seproject.J2SEProject;
074: import org.netbeans.modules.java.j2seproject.J2SEProjectType;
075: import org.netbeans.modules.java.j2seproject.J2SEProjectUtil;
076: import org.netbeans.modules.java.j2seproject.classpath.ClassPathSupport;
077: import org.netbeans.spi.java.project.support.ui.IncludeExcludeVisualizer;
078: import org.netbeans.spi.project.support.ant.AntProjectHelper;
079: import org.netbeans.spi.project.support.ant.EditableProperties;
080: import org.netbeans.spi.project.support.ant.GeneratedFilesHelper;
081: import org.netbeans.spi.project.support.ant.PropertyEvaluator;
082: import org.netbeans.spi.project.support.ant.ReferenceHelper;
083: import org.netbeans.spi.project.support.ant.ui.StoreGroup;
084: import org.openide.DialogDisplayer;
085: import org.openide.ErrorManager;
086: import org.openide.NotifyDescriptor;
087: import org.openide.filesystems.FileObject;
088: import org.openide.filesystems.FileUtil;
089: import org.openide.util.Exceptions;
090: import org.openide.util.Mutex;
091: import org.openide.util.MutexException;
092: import org.openide.util.NbBundle;
093: import org.openide.util.Utilities;
094:
095: /**
096: * @author Petr Hrebejk
097: */
098: public class J2SEProjectProperties {
099:
100: //Hotfix of the issue #70058
101: //Should be removed when the StoreGroup SPI will be extended to allow false default value in ToggleButtonModel
102: private static final Integer BOOLEAN_KIND_TF = new Integer(0);
103: private static final Integer BOOLEAN_KIND_YN = new Integer(1);
104: private static final Integer BOOLEAN_KIND_ED = new Integer(2);
105: private Integer javacDebugBooleanKind;
106: private Integer doJarBooleanKind;
107: private Integer javadocPreviewBooleanKind;
108:
109: // Special properties of the project
110: public static final String J2SE_PROJECT_NAME = "j2se.project.name"; // NOI18N
111: public static final String JAVA_PLATFORM = "platform.active"; // NOI18N
112:
113: // Properties stored in the PROJECT.PROPERTIES
114: public static final String DIST_DIR = "dist.dir"; // NOI18N
115: public static final String DIST_JAR = "dist.jar"; // NOI18N
116: public static final String JAVAC_CLASSPATH = "javac.classpath"; // NOI18N
117: public static final String RUN_CLASSPATH = "run.classpath"; // NOI18N
118: public static final String RUN_JVM_ARGS = "run.jvmargs"; // NOI18N
119: public static final String RUN_WORK_DIR = "work.dir"; // NOI18N
120: public static final String DEBUG_CLASSPATH = "debug.classpath"; // NOI18N
121: public static final String JAR_COMPRESS = "jar.compress"; // NOI18N
122: public static final String MAIN_CLASS = "main.class"; // NOI18N
123: public static final String JAVAC_SOURCE = "javac.source"; // NOI18N
124: public static final String JAVAC_TARGET = "javac.target"; // NOI18N
125: public static final String JAVAC_TEST_CLASSPATH = "javac.test.classpath"; // NOI18N
126: public static final String JAVAC_DEBUG = "javac.debug"; // NOI18N
127: public static final String JAVAC_DEPRECATION = "javac.deprecation"; // NOI18N
128: public static final String JAVAC_COMPILER_ARG = "javac.compilerargs"; //NOI18N
129: public static final String RUN_TEST_CLASSPATH = "run.test.classpath"; // NOI18N
130: public static final String BUILD_DIR = "build.dir"; // NOI18N
131: public static final String BUILD_CLASSES_DIR = "build.classes.dir"; // NOI18N
132: public static final String BUILD_TEST_CLASSES_DIR = "build.test.classes.dir"; // NOI18N
133: public static final String BUILD_TEST_RESULTS_DIR = "build.test.results.dir"; // NOI18N
134: public static final String BUILD_CLASSES_EXCLUDES = "build.classes.excludes"; // NOI18N
135: public static final String DIST_JAVADOC_DIR = "dist.javadoc.dir"; // NOI18N
136: public static final String NO_DEPENDENCIES = "no.dependencies"; // NOI18N
137: public static final String DEBUG_TEST_CLASSPATH = "debug.test.classpath"; // NOI18N
138: public static final String SOURCE_ENCODING = "source.encoding"; // NOI18N
139: /** @since org.netbeans.modules.java.j2seproject/1 1.11 */
140: public static final String INCLUDES = "includes"; // NOI18N
141: /** @since org.netbeans.modules.java.j2seproject/1 1.11 */
142: public static final String EXCLUDES = "excludes"; // NOI18N
143: /** @since org.netbeans.modules.java.j2seproject/1 1.12 */
144: public static final String DO_DEPEND = "do.depend"; // NOI18N
145: /** @since org.netbeans.modules.java.j2seproject/1 1.12 */
146: public static final String DO_JAR = "do.jar"; // NOI18N
147:
148: public static final String JAVADOC_PRIVATE = "javadoc.private"; // NOI18N
149: public static final String JAVADOC_NO_TREE = "javadoc.notree"; // NOI18N
150: public static final String JAVADOC_USE = "javadoc.use"; // NOI18N
151: public static final String JAVADOC_NO_NAVBAR = "javadoc.nonavbar"; // NOI18N
152: public static final String JAVADOC_NO_INDEX = "javadoc.noindex"; // NOI18N
153: public static final String JAVADOC_SPLIT_INDEX = "javadoc.splitindex"; // NOI18N
154: public static final String JAVADOC_AUTHOR = "javadoc.author"; // NOI18N
155: public static final String JAVADOC_VERSION = "javadoc.version"; // NOI18N
156: public static final String JAVADOC_WINDOW_TITLE = "javadoc.windowtitle"; // NOI18N
157: public static final String JAVADOC_ENCODING = "javadoc.encoding"; // NOI18N
158: public static final String JAVADOC_ADDITIONALPARAM = "javadoc.additionalparam"; // NOI18N
159:
160: public static final String APPLICATION_TITLE = "application.title"; // NOI18N
161: public static final String APPLICATION_VENDOR = "application.vendor"; // NOI18N
162: public static final String APPLICATION_DESC = "application.desc"; // NOI18N
163: public static final String APPLICATION_HOMEPAGE = "application.homepage"; // NOI18N
164: public static final String APPLICATION_SPLASH = "application.splash"; // NOI18N
165:
166: // Properties stored in the PRIVATE.PROPERTIES
167: public static final String APPLICATION_ARGS = "application.args"; // NOI18N
168: public static final String JAVADOC_PREVIEW = "javadoc.preview"; // NOI18N
169: // Main build.xml location
170: public static final String BUILD_SCRIPT = "buildfile"; //NOI18N
171:
172: // Well known paths
173: public static final String[] WELL_KNOWN_PATHS = new String[] {
174: "${" + JAVAC_CLASSPATH + "}",
175: "${" + JAVAC_TEST_CLASSPATH + "}",
176: "${" + RUN_CLASSPATH + "}",
177: "${" + RUN_TEST_CLASSPATH + "}",
178: "${" + BUILD_CLASSES_DIR + "}",
179: "${" + BUILD_TEST_CLASSES_DIR + "}", };
180:
181: // XXX looks like there is some kind of API missing in ReferenceHelper?
182: public static final String ANT_ARTIFACT_PREFIX = "${reference."; // NOI18N
183:
184: ClassPathSupport cs;
185:
186: // SOURCE ROOTS
187: // public static final String SOURCE_ROOTS = "__virtual_source_roots__"; //NOI18N
188: // public static final String TEST_ROOTS = "__virtual_test_roots__"; // NOI18N
189:
190: // MODELS FOR VISUAL CONTROLS
191:
192: // CustomizerSources
193: DefaultTableModel SOURCE_ROOTS_MODEL;
194: DefaultTableModel TEST_ROOTS_MODEL;
195: ComboBoxModel JAVAC_SOURCE_MODEL;
196:
197: // CustomizerLibraries
198: DefaultListModel JAVAC_CLASSPATH_MODEL;
199: DefaultListModel JAVAC_TEST_CLASSPATH_MODEL;
200: DefaultListModel RUN_CLASSPATH_MODEL;
201: DefaultListModel RUN_TEST_CLASSPATH_MODEL;
202: ComboBoxModel PLATFORM_MODEL;
203: ListCellRenderer CLASS_PATH_LIST_RENDERER;
204: ListCellRenderer PLATFORM_LIST_RENDERER;
205: ListCellRenderer JAVAC_SOURCE_RENDERER;
206: Document SHARED_LIBRARIES_MODEL;
207:
208: // CustomizerCompile
209: ButtonModel JAVAC_DEPRECATION_MODEL;
210: ButtonModel JAVAC_DEBUG_MODEL;
211: ButtonModel DO_DEPEND_MODEL;
212: ButtonModel NO_DEPENDENCIES_MODEL;
213: Document JAVAC_COMPILER_ARG_MODEL;
214:
215: // CustomizerCompileTest
216:
217: // CustomizerJar
218: Document DIST_JAR_MODEL;
219: Document BUILD_CLASSES_EXCLUDES_MODEL;
220: ButtonModel JAR_COMPRESS_MODEL;
221: ButtonModel DO_JAR_MODEL;
222:
223: // CustomizerJavadoc
224: ButtonModel JAVADOC_PRIVATE_MODEL;
225: ButtonModel JAVADOC_NO_TREE_MODEL;
226: ButtonModel JAVADOC_USE_MODEL;
227: ButtonModel JAVADOC_NO_NAVBAR_MODEL;
228: ButtonModel JAVADOC_NO_INDEX_MODEL;
229: ButtonModel JAVADOC_SPLIT_INDEX_MODEL;
230: ButtonModel JAVADOC_AUTHOR_MODEL;
231: ButtonModel JAVADOC_VERSION_MODEL;
232: Document JAVADOC_WINDOW_TITLE_MODEL;
233: ButtonModel JAVADOC_PREVIEW_MODEL;
234: Document JAVADOC_ADDITIONALPARAM_MODEL;
235:
236: // CustomizerRun
237: Map<String/*|null*/, Map<String, String/*|null*/>/*|null*/> RUN_CONFIGS;
238: String activeConfig;
239:
240: // CustomizerApplication
241: Document APPLICATION_TITLE_DOC;
242: Document APPLICATION_VENDOR_DOC;
243: Document APPLICATION_DESC_DOC;
244: Document APPLICATION_HOMEPAGE_DOC;
245: Document APPLICATION_SPLASH_DOC;
246:
247: // CustomizerRunTest
248:
249: // Private fields ----------------------------------------------------------
250: private J2SEProject project;
251: private UpdateHelper updateHelper;
252: private PropertyEvaluator evaluator;
253: private ReferenceHelper refHelper;
254: private GeneratedFilesHelper genFileHelper;
255:
256: private StoreGroup privateGroup;
257: private StoreGroup projectGroup;
258:
259: private Map<String, String> additionalProperties;
260:
261: private String includes, excludes;
262:
263: J2SEProject getProject() {
264: return project;
265: }
266:
267: /** Creates a new instance of J2SEUIProperties and initializes them */
268: public J2SEProjectProperties(J2SEProject project,
269: UpdateHelper updateHelper, PropertyEvaluator evaluator,
270: ReferenceHelper refHelper,
271: GeneratedFilesHelper genFileHelper) {
272: this .project = project;
273: this .updateHelper = updateHelper;
274: this .evaluator = evaluator;
275: this .refHelper = refHelper;
276: this .genFileHelper = genFileHelper;
277: this .cs = new ClassPathSupport(evaluator, refHelper,
278: updateHelper.getAntProjectHelper(), updateHelper,
279: WELL_KNOWN_PATHS, ANT_ARTIFACT_PREFIX);
280:
281: privateGroup = new StoreGroup();
282: projectGroup = new StoreGroup();
283:
284: additionalProperties = new HashMap<String, String>();
285:
286: init(); // Load known properties
287: }
288:
289: /** Initializes the visual models
290: */
291: private void init() {
292:
293: CLASS_PATH_LIST_RENDERER = new J2SEClassPathUi.ClassPathListCellRenderer(
294: evaluator, project.getProjectDirectory());
295:
296: // CustomizerSources
297: SOURCE_ROOTS_MODEL = J2SESourceRootsUi.createModel(project
298: .getSourceRoots());
299: TEST_ROOTS_MODEL = J2SESourceRootsUi.createModel(project
300: .getTestSourceRoots());
301: includes = evaluator.getProperty(INCLUDES);
302: if (includes == null) {
303: includes = "**"; // NOI18N
304: }
305: excludes = evaluator.getProperty(EXCLUDES);
306: if (excludes == null) {
307: excludes = ""; // NOI18N
308: }
309:
310: // CustomizerLibraries
311: EditableProperties projectProperties = updateHelper
312: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
313:
314: JAVAC_CLASSPATH_MODEL = ClassPathUiSupport.createListModel(cs
315: .itemsIterator(projectProperties.get(JAVAC_CLASSPATH)));
316: JAVAC_TEST_CLASSPATH_MODEL = ClassPathUiSupport
317: .createListModel(cs.itemsIterator(projectProperties
318: .get(JAVAC_TEST_CLASSPATH)));
319: RUN_CLASSPATH_MODEL = ClassPathUiSupport.createListModel(cs
320: .itemsIterator(projectProperties.get(RUN_CLASSPATH)));
321: RUN_TEST_CLASSPATH_MODEL = ClassPathUiSupport
322: .createListModel(cs.itemsIterator(projectProperties
323: .get(RUN_TEST_CLASSPATH)));
324: PLATFORM_MODEL = PlatformUiSupport
325: .createPlatformComboBoxModel(evaluator
326: .getProperty(JAVA_PLATFORM));
327: PLATFORM_LIST_RENDERER = PlatformUiSupport
328: .createPlatformListCellRenderer();
329: JAVAC_SOURCE_MODEL = PlatformUiSupport
330: .createSourceLevelComboBoxModel(PLATFORM_MODEL,
331: evaluator.getProperty(JAVAC_SOURCE), evaluator
332: .getProperty(JAVAC_TARGET));
333: JAVAC_SOURCE_RENDERER = PlatformUiSupport
334: .createSourceLevelListCellRenderer();
335: SHARED_LIBRARIES_MODEL = new PlainDocument();
336: try {
337: SHARED_LIBRARIES_MODEL
338: .insertString(0, project.getAntProjectHelper()
339: .getLibrariesLocation(), null);
340: } catch (BadLocationException ex) {
341: Exceptions.printStackTrace(ex);
342: }
343:
344: // CustomizerCompile
345: JAVAC_DEPRECATION_MODEL = projectGroup.createToggleButtonModel(
346: evaluator, JAVAC_DEPRECATION);
347:
348: //Hotfix of the issue #70058
349: //Should use the StoreGroup when the StoreGroup SPI will be extended to allow false default value in ToggleButtonModel
350: Integer[] kind = new Integer[1];
351: JAVAC_DEBUG_MODEL = createToggleButtonModel(evaluator,
352: JAVAC_DEBUG, kind);
353: javacDebugBooleanKind = kind[0];
354:
355: DO_DEPEND_MODEL = privateGroup.createToggleButtonModel(
356: evaluator, DO_DEPEND);
357:
358: NO_DEPENDENCIES_MODEL = projectGroup
359: .createInverseToggleButtonModel(evaluator,
360: NO_DEPENDENCIES);
361: JAVAC_COMPILER_ARG_MODEL = projectGroup.createStringDocument(
362: evaluator, JAVAC_COMPILER_ARG);
363:
364: // CustomizerJar
365: DIST_JAR_MODEL = projectGroup.createStringDocument(evaluator,
366: DIST_JAR);
367: BUILD_CLASSES_EXCLUDES_MODEL = projectGroup
368: .createStringDocument(evaluator, BUILD_CLASSES_EXCLUDES);
369: JAR_COMPRESS_MODEL = projectGroup.createToggleButtonModel(
370: evaluator, JAR_COMPRESS);
371: DO_JAR_MODEL = createToggleButtonModel(evaluator, DO_JAR, kind);
372: doJarBooleanKind = kind[0];
373:
374: // CustomizerJavadoc
375: JAVADOC_PRIVATE_MODEL = projectGroup.createToggleButtonModel(
376: evaluator, JAVADOC_PRIVATE);
377: JAVADOC_NO_TREE_MODEL = projectGroup
378: .createInverseToggleButtonModel(evaluator,
379: JAVADOC_NO_TREE);
380: JAVADOC_USE_MODEL = projectGroup.createToggleButtonModel(
381: evaluator, JAVADOC_USE);
382: JAVADOC_NO_NAVBAR_MODEL = projectGroup
383: .createInverseToggleButtonModel(evaluator,
384: JAVADOC_NO_NAVBAR);
385: JAVADOC_NO_INDEX_MODEL = projectGroup
386: .createInverseToggleButtonModel(evaluator,
387: JAVADOC_NO_INDEX);
388: JAVADOC_SPLIT_INDEX_MODEL = projectGroup
389: .createToggleButtonModel(evaluator, JAVADOC_SPLIT_INDEX);
390: JAVADOC_AUTHOR_MODEL = projectGroup.createToggleButtonModel(
391: evaluator, JAVADOC_AUTHOR);
392: JAVADOC_VERSION_MODEL = projectGroup.createToggleButtonModel(
393: evaluator, JAVADOC_VERSION);
394: JAVADOC_WINDOW_TITLE_MODEL = projectGroup.createStringDocument(
395: evaluator, JAVADOC_WINDOW_TITLE);
396: //Hotfix of the issue #70058
397: //Should use the StoreGroup when the StoreGroup SPI will be extended to allow false default value in ToggleButtonModel
398: JAVADOC_PREVIEW_MODEL = createToggleButtonModel(evaluator,
399: JAVADOC_PREVIEW, kind);
400: javadocPreviewBooleanKind = kind[0];
401:
402: JAVADOC_ADDITIONALPARAM_MODEL = projectGroup
403: .createStringDocument(evaluator,
404: JAVADOC_ADDITIONALPARAM);
405:
406: // CustomizerApplication
407: APPLICATION_TITLE_DOC = projectGroup.createStringDocument(
408: evaluator, APPLICATION_TITLE);
409: String title = evaluator.getProperty("application.title");
410: if (title == null) {
411: try {
412: APPLICATION_TITLE_DOC
413: .insertString(0, ProjectUtils.getInformation(
414: project).getDisplayName(), null);
415: } catch (BadLocationException ex) {
416: // just do not set anything
417: }
418: }
419: APPLICATION_VENDOR_DOC = projectGroup.createStringDocument(
420: evaluator, APPLICATION_VENDOR);
421: String vendor = evaluator.getProperty("application.vendor");
422: if (vendor == null) {
423: try {
424: APPLICATION_VENDOR_DOC.insertString(0, System
425: .getProperty("user.name", "User Name"), null);
426: } catch (BadLocationException ex) {
427: // just do not set anything
428: }
429: }
430: APPLICATION_DESC_DOC = projectGroup.createStringDocument(
431: evaluator, APPLICATION_DESC);
432: APPLICATION_HOMEPAGE_DOC = projectGroup.createStringDocument(
433: evaluator, APPLICATION_HOMEPAGE);
434: APPLICATION_SPLASH_DOC = projectGroup.createStringDocument(
435: evaluator, APPLICATION_SPLASH);
436:
437: // CustomizerRun
438: RUN_CONFIGS = readRunConfigs();
439: activeConfig = evaluator.getProperty("config");
440:
441: }
442:
443: public void save() {
444: try {
445: saveLibrariesLocation();
446: // Store properties
447: boolean result = ProjectManager.mutex().writeAccess(
448: new Mutex.ExceptionAction<Boolean>() {
449: final FileObject projectDir = updateHelper
450: .getAntProjectHelper()
451: .getProjectDirectory();
452:
453: public Boolean run() throws IOException {
454: if ((genFileHelper
455: .getBuildScriptState(
456: GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
457: J2SEProject.class
458: .getResource("resources/build-impl.xsl")) //NOI18N
459: & GeneratedFilesHelper.FLAG_MODIFIED) == GeneratedFilesHelper.FLAG_MODIFIED) { //NOI18N
460: if (showModifiedMessage(NbBundle
461: .getMessage(
462: J2SEProjectProperties.class,
463: "TXT_ModifiedTitle"))) {
464: //Delete user modified build-impl.xml
465: FileObject fo = projectDir
466: .getFileObject(GeneratedFilesHelper.BUILD_IMPL_XML_PATH);
467: if (fo != null) {
468: fo.delete();
469: }
470: } else {
471: return false;
472: }
473: }
474: storeProperties();
475: return true;
476: }
477: });
478: // and save the project
479: if (result) {
480: ProjectManager.getDefault().saveProject(project);
481: }
482: } catch (MutexException e) {
483: ErrorManager.getDefault().notify(
484: (IOException) e.getException());
485: } catch (IOException ex) {
486: ErrorManager.getDefault().notify(ex);
487: }
488: }
489:
490: private void saveLibrariesLocation() throws IOException,
491: IllegalArgumentException {
492: try {
493: String str = SHARED_LIBRARIES_MODEL.getText(0,
494: SHARED_LIBRARIES_MODEL.getLength()).trim();
495: if (str.length() == 0) {
496: str = null;
497: }
498: String old = project.getAntProjectHelper()
499: .getLibrariesLocation();
500: if ((old == null && str == null)
501: || (old != null && old.equals(str))) {
502: //ignore, nothing changed..
503: } else {
504: project.getAntProjectHelper().setLibrariesLocation(str);
505: ProjectManager.getDefault().saveProject(project);
506: }
507: } catch (BadLocationException x) {
508: ErrorManager.getDefault().notify(x);
509: }
510: }
511:
512: private void storeProperties() throws IOException {
513: // Store special properties
514:
515: // Modify the project dependencies properly
516: resolveProjectDependencies();
517:
518: // Encode all paths (this may change the project properties)
519: String[] javac_cp = cs.encodeToStrings(ClassPathUiSupport
520: .getIterator(JAVAC_CLASSPATH_MODEL));
521: String[] javac_test_cp = cs.encodeToStrings(ClassPathUiSupport
522: .getIterator(JAVAC_TEST_CLASSPATH_MODEL));
523: String[] run_cp = cs.encodeToStrings(ClassPathUiSupport
524: .getIterator(RUN_CLASSPATH_MODEL));
525: String[] run_test_cp = cs.encodeToStrings(ClassPathUiSupport
526: .getIterator(RUN_TEST_CLASSPATH_MODEL));
527:
528: // Store source roots
529: storeRoots(project.getSourceRoots(), SOURCE_ROOTS_MODEL);
530: storeRoots(project.getTestSourceRoots(), TEST_ROOTS_MODEL);
531:
532: // Store standard properties
533: EditableProperties projectProperties = updateHelper
534: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
535: EditableProperties privateProperties = updateHelper
536: .getProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH);
537:
538: // Assure inegrity which can't shound not be assured in UI
539: if (!JAVADOC_NO_INDEX_MODEL.isSelected()) {
540: JAVADOC_SPLIT_INDEX_MODEL.setSelected(false); // Can't split non existing index
541: }
542:
543: // Standard store of the properties
544: projectGroup.store(projectProperties);
545: privateGroup.store(privateProperties);
546:
547: storeRunConfigs(RUN_CONFIGS, projectProperties,
548: privateProperties);
549: EditableProperties ep = updateHelper
550: .getProperties("nbproject/private/config.properties");
551: if (activeConfig == null) {
552: ep.remove("config");
553: } else {
554: ep.setProperty("config", activeConfig);
555: }
556: updateHelper.putProperties(
557: "nbproject/private/config.properties", ep);
558:
559: //Hotfix of the issue #70058
560: //Should use the StoreGroup when the StoreGroup SPI will be extended to allow false default value in ToggleButtonModel
561: //Save javac.debug
562: privateProperties.setProperty(JAVAC_DEBUG, encodeBoolean(
563: JAVAC_DEBUG_MODEL.isSelected(), javacDebugBooleanKind));
564: privateProperties.setProperty(DO_JAR, encodeBoolean(
565: DO_JAR_MODEL.isSelected(), doJarBooleanKind));
566:
567: //Hotfix of the issue #70058
568: //Should use the StoreGroup when the StoreGroup SPI will be extended to allow false default value in ToggleButtonModel
569: //Save javadoc.preview
570: privateProperties.setProperty(JAVADOC_PREVIEW, encodeBoolean(
571: JAVADOC_PREVIEW_MODEL.isSelected(),
572: javadocPreviewBooleanKind));
573:
574: // Save all paths
575: projectProperties.setProperty(JAVAC_CLASSPATH, javac_cp);
576: projectProperties.setProperty(JAVAC_TEST_CLASSPATH,
577: javac_test_cp);
578: projectProperties.setProperty(RUN_CLASSPATH, run_cp);
579: projectProperties.setProperty(RUN_TEST_CLASSPATH, run_test_cp);
580:
581: //Handle platform selection and javac.source javac.target properties
582: PlatformUiSupport.storePlatform(projectProperties,
583: updateHelper,
584: J2SEProjectType.PROJECT_CONFIGURATION_NAMESPACE,
585: PLATFORM_MODEL.getSelectedItem(), JAVAC_SOURCE_MODEL
586: .getSelectedItem());
587:
588: // Handle other special cases
589: if (NO_DEPENDENCIES_MODEL.isSelected()) { // NOI18N
590: projectProperties.remove(NO_DEPENDENCIES); // Remove the property completely if not set
591: }
592:
593: projectProperties.putAll(additionalProperties);
594:
595: projectProperties.put(INCLUDES, includes);
596: projectProperties.put(EXCLUDES, excludes);
597:
598: // Store the property changes into the project
599: updateHelper.putProperties(
600: AntProjectHelper.PROJECT_PROPERTIES_PATH,
601: projectProperties);
602: updateHelper.putProperties(
603: AntProjectHelper.PRIVATE_PROPERTIES_PATH,
604: privateProperties);
605:
606: String value = additionalProperties.get(SOURCE_ENCODING);
607: if (value != null) {
608: try {
609: FileEncodingQuery.setDefaultEncoding(Charset
610: .forName(value));
611: } catch (UnsupportedCharsetException e) {
612: //When the encoding is not supported by JVM do not set it as default
613: }
614: }
615: }
616:
617: /** Finds out what are new and removed project dependencies and
618: * applyes the info to the project
619: */
620: private void resolveProjectDependencies() {
621:
622: // Create a set of old and new artifacts.
623: Set<ClassPathSupport.Item> oldArtifacts = new HashSet<ClassPathSupport.Item>();
624: EditableProperties projectProperties = updateHelper
625: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
626: oldArtifacts.addAll(cs.itemsList(projectProperties
627: .get(JAVAC_CLASSPATH)));
628: oldArtifacts.addAll(cs.itemsList(projectProperties
629: .get(JAVAC_TEST_CLASSPATH)));
630: oldArtifacts.addAll(cs.itemsList(projectProperties
631: .get(RUN_CLASSPATH)));
632: oldArtifacts.addAll(cs.itemsList(projectProperties
633: .get(RUN_TEST_CLASSPATH)));
634:
635: Set<ClassPathSupport.Item> newArtifacts = new HashSet<ClassPathSupport.Item>();
636: newArtifacts.addAll(ClassPathUiSupport
637: .getList(JAVAC_CLASSPATH_MODEL));
638: newArtifacts.addAll(ClassPathUiSupport
639: .getList(JAVAC_TEST_CLASSPATH_MODEL));
640: newArtifacts.addAll(ClassPathUiSupport
641: .getList(RUN_CLASSPATH_MODEL));
642: newArtifacts.addAll(ClassPathUiSupport
643: .getList(RUN_TEST_CLASSPATH_MODEL));
644:
645: // Create set of removed artifacts and remove them
646: Set<ClassPathSupport.Item> removed = new HashSet<ClassPathSupport.Item>(
647: oldArtifacts);
648: removed.removeAll(newArtifacts);
649: Set<ClassPathSupport.Item> added = new HashSet<ClassPathSupport.Item>(
650: newArtifacts);
651: added.removeAll(oldArtifacts);
652:
653: // 1. first remove all project references. The method will modify
654: // project property files, so it must be done separately
655: for (ClassPathSupport.Item item : removed) {
656: if (item.getType() == ClassPathSupport.Item.TYPE_ARTIFACT
657: || item.getType() == ClassPathSupport.Item.TYPE_JAR) {
658: refHelper.destroyReference(item.getReference());
659: if (item.getType() == ClassPathSupport.Item.TYPE_JAR) {
660: //oh well, how do I do this otherwise??
661: EditableProperties ep = updateHelper
662: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
663: if (item.getJavadocProperty() != null) {
664: ep.remove(item.getJavadocProperty());
665: }
666: if (item.getSourceProperty() != null) {
667: ep.remove(item.getSourceProperty());
668: }
669: updateHelper.putProperties(
670: AntProjectHelper.PROJECT_PROPERTIES_PATH,
671: ep);
672: }
673: }
674: }
675:
676: boolean changed = false;
677: // 2. now read project.properties and modify rest
678: EditableProperties ep = updateHelper
679: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
680:
681: for (ClassPathSupport.Item item : removed) {
682: if (item.getType() == ClassPathSupport.Item.TYPE_LIBRARY) {
683: // remove helper property pointing to library jar if there is any
684: String prop = item.getReference();
685: prop = ClassPathSupport.getAntPropertyName(prop);
686: ep.remove(prop);
687: changed = true;
688: }
689: }
690: if (changed) {
691: updateHelper.putProperties(
692: AntProjectHelper.PROJECT_PROPERTIES_PATH, ep);
693: }
694: }
695:
696: private void storeRoots(SourceRoots roots,
697: DefaultTableModel tableModel) throws MalformedURLException {
698: Vector data = tableModel.getDataVector();
699: URL[] rootURLs = new URL[data.size()];
700: String[] rootLabels = new String[data.size()];
701: for (int i = 0; i < data.size(); i++) {
702: File f = (File) ((Vector) data.elementAt(i)).elementAt(0);
703: rootURLs[i] = J2SEProjectUtil.getRootURL(f, null);
704: rootLabels[i] = (String) ((Vector) data.elementAt(i))
705: .elementAt(1);
706: }
707: roots.putRoots(rootURLs, rootLabels);
708: }
709:
710: /* This is used by CustomizerWSServiceHost */
711: public void putAdditionalProperty(String propertyName,
712: String propertyValue) {
713: additionalProperties.put(propertyName, propertyValue);
714: }
715:
716: private static boolean showModifiedMessage(String title) {
717: String message = NbBundle.getMessage(
718: J2SEProjectProperties.class, "TXT_Regenerate");
719: JButton regenerateButton = new JButton(NbBundle.getMessage(
720: J2SEProjectProperties.class, "CTL_RegenerateButton"));
721: regenerateButton.setDefaultCapable(true);
722: regenerateButton.getAccessibleContext()
723: .setAccessibleDescription(
724: NbBundle.getMessage(
725: J2SEProjectProperties.class,
726: "AD_RegenerateButton"));
727: NotifyDescriptor d = new NotifyDescriptor.Message(message,
728: NotifyDescriptor.WARNING_MESSAGE);
729: d.setTitle(title);
730: d.setOptionType(NotifyDescriptor.OK_CANCEL_OPTION);
731: d.setOptions(new Object[] { regenerateButton,
732: NotifyDescriptor.CANCEL_OPTION });
733: return DialogDisplayer.getDefault().notify(d) == regenerateButton;
734: }
735:
736: //Hotfix of the issue #70058
737: //Should be removed when the StoreGroup SPI will be extended to allow false default value in ToggleButtonModel
738: private static String encodeBoolean(boolean value, Integer kind) {
739: if (kind == BOOLEAN_KIND_ED) {
740: return value ? "on" : "off"; // NOI18N
741: } else if (kind == BOOLEAN_KIND_YN) { // NOI18N
742: return value ? "yes" : "no";
743: } else {
744: return value ? "true" : "false"; // NOI18N
745: }
746: }
747:
748: //Hotfix of the issue #70058
749: //Should be removed when the StoreGroup SPI will be extended to allow true default value in ToggleButtonModel
750: private static JToggleButton.ToggleButtonModel createToggleButtonModel(
751: final PropertyEvaluator evaluator, final String propName,
752: Integer[] kind) {
753: assert evaluator != null && propName != null && kind != null
754: && kind.length == 1;
755: String value = evaluator.getProperty(propName);
756: boolean isSelected = false;
757: if (value == null) {
758: isSelected = true;
759: } else {
760: String lowercaseValue = value.toLowerCase();
761: if (lowercaseValue.equals("yes")
762: || lowercaseValue.equals("no")) { // NOI18N
763: kind[0] = BOOLEAN_KIND_YN;
764: } else if (lowercaseValue.equals("on")
765: || lowercaseValue.equals("off")) { // NOI18N
766: kind[0] = BOOLEAN_KIND_ED;
767: } else {
768: kind[0] = BOOLEAN_KIND_TF;
769: }
770:
771: if (lowercaseValue.equals("true") || // NOI18N
772: lowercaseValue.equals("yes") || // NOI18N
773: lowercaseValue.equals("on")) { // NOI18N
774: isSelected = true;
775: }
776: }
777: JToggleButton.ToggleButtonModel bm = new JToggleButton.ToggleButtonModel();
778: bm.setSelected(isSelected);
779: return bm;
780: }
781:
782: /**
783: * A mess.
784: */
785: Map<String/*|null*/, Map<String, String>> readRunConfigs() {
786: Map<String, Map<String, String>> m = new TreeMap<String, Map<String, String>>(
787: new Comparator<String>() {
788: public int compare(String s1, String s2) {
789: return s1 != null ? (s2 != null ? s1
790: .compareTo(s2) : 1) : (s2 != null ? -1
791: : 0);
792: }
793: });
794: Map<String, String> def = new TreeMap<String, String>();
795: for (String prop : new String[] { MAIN_CLASS, APPLICATION_ARGS,
796: RUN_JVM_ARGS, RUN_WORK_DIR }) {
797: String v = updateHelper.getProperties(
798: AntProjectHelper.PRIVATE_PROPERTIES_PATH)
799: .getProperty(prop);
800: if (v == null) {
801: v = updateHelper.getProperties(
802: AntProjectHelper.PROJECT_PROPERTIES_PATH)
803: .getProperty(prop);
804: }
805: if (v != null) {
806: def.put(prop, v);
807: }
808: }
809: m.put(null, def);
810: FileObject configs = project.getProjectDirectory()
811: .getFileObject("nbproject/configs");
812: if (configs != null) {
813: for (FileObject kid : configs.getChildren()) {
814: if (!kid.hasExt("properties")) {
815: continue;
816: }
817: m.put(kid.getName(), new TreeMap<String, String>(
818: updateHelper.getProperties(FileUtil
819: .getRelativePath(project
820: .getProjectDirectory(), kid))));
821: }
822: }
823: configs = project.getProjectDirectory().getFileObject(
824: "nbproject/private/configs");
825: if (configs != null) {
826: for (FileObject kid : configs.getChildren()) {
827: if (!kid.hasExt("properties")) {
828: continue;
829: }
830: Map<String, String> c = m.get(kid.getName());
831: if (c == null) {
832: continue;
833: }
834: c.putAll(new HashMap<String, String>(updateHelper
835: .getProperties(FileUtil.getRelativePath(project
836: .getProjectDirectory(), kid))));
837: }
838: }
839: //System.err.println("readRunConfigs: " + m);
840: return m;
841: }
842:
843: /**
844: * A royal mess.
845: */
846: void storeRunConfigs(
847: Map<String/*|null*/, Map<String, String/*|null*/>/*|null*/> configs,
848: EditableProperties projectProperties,
849: EditableProperties privateProperties) throws IOException {
850: //System.err.println("storeRunConfigs: " + configs);
851: Map<String, String> def = configs.get(null);
852: for (String prop : new String[] { MAIN_CLASS, APPLICATION_ARGS,
853: RUN_JVM_ARGS, RUN_WORK_DIR }) {
854: String v = def.get(prop);
855: EditableProperties ep = (prop.equals(APPLICATION_ARGS) || prop
856: .equals(RUN_WORK_DIR)) ? privateProperties
857: : projectProperties;
858: if (!Utilities.compareObjects(v, ep.getProperty(prop))) {
859: if (v != null && v.length() > 0) {
860: ep.setProperty(prop, v);
861: } else {
862: ep.remove(prop);
863: }
864: }
865: }
866: for (Map.Entry<String, Map<String, String>> entry : configs
867: .entrySet()) {
868: String config = entry.getKey();
869: if (config == null) {
870: continue;
871: }
872: String sharedPath = "nbproject/configs/" + config
873: + ".properties"; // NOI18N
874: String privatePath = "nbproject/private/configs/" + config
875: + ".properties"; // NOI18N
876: Map<String, String> c = entry.getValue();
877: if (c == null) {
878: updateHelper.putProperties(sharedPath, null);
879: updateHelper.putProperties(privatePath, null);
880: continue;
881: }
882: for (Map.Entry<String, String> entry2 : c.entrySet()) {
883: String prop = entry2.getKey();
884: String v = entry2.getValue();
885: String path = (prop.equals(APPLICATION_ARGS) || prop
886: .equals(RUN_WORK_DIR)) ? privatePath
887: : sharedPath;
888: EditableProperties ep = updateHelper
889: .getProperties(path);
890: if (!Utilities.compareObjects(v, ep.getProperty(prop))) {
891: if (v != null
892: && (v.length() > 0 || (def.get(prop) != null && def
893: .get(prop).length() > 0))) {
894: ep.setProperty(prop, v);
895: } else {
896: ep.remove(prop);
897: }
898: updateHelper.putProperties(path, ep);
899: }
900: }
901: // Make sure the definition file is always created, even if it is empty.
902: updateHelper.putProperties(sharedPath, updateHelper
903: .getProperties(sharedPath));
904: }
905: }
906:
907: void loadIncludesExcludes(IncludeExcludeVisualizer v) {
908: Set<File> roots = new HashSet<File>();
909: for (DefaultTableModel model : new DefaultTableModel[] {
910: SOURCE_ROOTS_MODEL, TEST_ROOTS_MODEL }) {
911: for (Object row : model.getDataVector()) {
912: File d = (File) ((Vector) row).elementAt(0);
913: if (/* #104996 */d.isDirectory()) {
914: roots.add(d);
915: }
916: }
917: }
918: v.setRoots(roots.toArray(new File[roots.size()]));
919: v.setIncludePattern(includes);
920: v.setExcludePattern(excludes);
921: }
922:
923: void storeIncludesExcludes(IncludeExcludeVisualizer v) {
924: includes = v.getIncludePattern();
925: excludes = v.getExcludePattern();
926: }
927:
928: }
|