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.freeform.ui;
043:
044: import java.io.File;
045: import java.io.IOException;
046: import java.nio.charset.Charset;
047: import java.util.ArrayList;
048: import java.util.Arrays;
049: import java.util.HashSet;
050: import java.util.Iterator;
051: import java.util.LinkedHashSet;
052: import java.util.List;
053: import java.util.Set;
054: import javax.swing.event.ChangeListener;
055: import org.netbeans.api.java.platform.JavaPlatform;
056: import org.netbeans.api.project.Project;
057: import org.netbeans.api.project.ProjectManager;
058: import org.netbeans.api.project.ProjectUtils;
059: import org.netbeans.modules.ant.freeform.spi.ProjectConstants;
060: import org.netbeans.modules.ant.freeform.spi.support.Util;
061: import org.netbeans.modules.java.freeform.JavaProjectGenerator;
062: import org.netbeans.modules.java.freeform.JavaProjectNature;
063: import org.netbeans.spi.project.AuxiliaryConfiguration;
064: import org.netbeans.spi.project.support.ant.AntProjectHelper;
065: import org.netbeans.spi.project.support.ant.PropertyEvaluator;
066: import org.netbeans.spi.project.support.ant.PropertyUtils;
067: import org.openide.filesystems.FileUtil;
068: import org.openide.modules.SpecificationVersion;
069: import org.openide.util.ChangeSupport;
070: import org.openide.util.Exceptions;
071: import org.openide.util.Mutex;
072: import org.openide.util.NbBundle;
073:
074: /**
075: * Memory model of project. Used for creation or customization of project.
076: *
077: * @author David Konecny
078: */
079: public class ProjectModel {
080:
081: /** Original project base folder */
082: private File baseFolder;
083:
084: /** Freeform Project base folder */
085: private File nbProjectFolder;
086:
087: private PropertyEvaluator evaluator;
088:
089: private String sourceLevel;
090:
091: private String encoding;
092:
093: public static final String NO_ENCODING = NbBundle.getBundle(
094: org.netbeans.modules.java.freeform.ui.ProjectModel.class)
095: .getString("No_Encoding");
096:
097: /** List of JavaProjectGenerator.SourceFolders instances of type "java". */
098: private List<JavaProjectGenerator.SourceFolder> sourceFolders;
099:
100: public List<JavaProjectGenerator.JavaCompilationUnit> javaCompilationUnitsList;
101:
102: private Set<String> addedSourceFolders;
103: private Set<String> removedSourceFolders;
104:
105: public static final String TYPE_JAVA = "java"; // NOI18N
106: public static final String CLASSPATH_MODE_COMPILE = "compile"; // NOI18N
107: //Upper bound of sourse level supported by the java freeform project
108: private static final SpecificationVersion JDK_MAX_SUPPORTED_VERSION = new SpecificationVersion(
109: "1.5"); //NOI18N
110:
111: private ProjectModel(File baseFolder, File nbProjectFolder,
112: PropertyEvaluator evaluator,
113: List<JavaProjectGenerator.SourceFolder> sourceFolders,
114: List<JavaProjectGenerator.JavaCompilationUnit> compUnits) {
115: this .baseFolder = baseFolder;
116: this .nbProjectFolder = nbProjectFolder;
117: this .evaluator = evaluator;
118: this .sourceFolders = sourceFolders;
119: this .javaCompilationUnitsList = compUnits;
120: if (javaCompilationUnitsList.size() > 0) {
121: sourceLevel = javaCompilationUnitsList.get(0).sourceLevel;
122: }
123: if (sourceLevel == null) {
124: setSourceLevel(getDefaultSourceLevel());
125: }
126: if (sourceFolders.size() > 0) {
127: JavaProjectGenerator.SourceFolder sf = sourceFolders.get(0);
128: this .encoding = sf.encoding == null ? null : Charset
129: .forName(sf.encoding).name();
130: }
131: resetState();
132: }
133:
134: private final ChangeSupport cs = new ChangeSupport(this );
135:
136: public final void addChangeListener(ChangeListener l) {
137: cs.addChangeListener(l);
138: }
139:
140: public final void removeChangeListener(ChangeListener l) {
141: cs.removeChangeListener(l);
142: }
143:
144: /**
145: * Notifies only about change in source folders and compilation units.
146: */
147: protected final void fireChangeEvent() {
148: cs.fireChange();
149: }
150:
151: private void resetState() {
152: addedSourceFolders = new HashSet<String>();
153: removedSourceFolders = new HashSet<String>();
154: }
155:
156: /** Create empty project model. Useful for new project creation. */
157: public static ProjectModel createEmptyModel(File baseFolder,
158: File nbProjectFolder, PropertyEvaluator evaluator) {
159: return new ProjectModel(
160: baseFolder,
161: nbProjectFolder,
162: evaluator,
163: new ArrayList<JavaProjectGenerator.SourceFolder>(),
164: new ArrayList<JavaProjectGenerator.JavaCompilationUnit>());
165: }
166:
167: /** Create project model of existing project. Useful for project customization. */
168: public static ProjectModel createModel(final File baseFolder,
169: final File nbProjectFolder,
170: final PropertyEvaluator evaluator,
171: final AntProjectHelper helper) {
172: return ProjectManager.mutex().readAccess(
173: new Mutex.Action<ProjectModel>() {
174: public ProjectModel run() {
175: ProjectModel pm = new ProjectModel(
176: baseFolder,
177: nbProjectFolder,
178: evaluator,
179: // reads only "java" type because other types are not editable in UI
180: JavaProjectGenerator.getSourceFolders(
181: helper, TYPE_JAVA),
182: JavaProjectGenerator
183: .getJavaCompilationUnits(
184: helper,
185: Util
186: .getAuxiliaryConfiguration(helper)));
187: // only "java" type of sources was read so fix style to "pacakges" on all
188: updateStyle(pm.sourceFolders);
189: return pm;
190: }
191: });
192: }
193:
194: /** Instantiate project model as new Java project. */
195: public static void instantiateJavaProject(AntProjectHelper helper,
196: ProjectModel model) throws IOException {
197: List<JavaProjectGenerator.SourceFolder> sourceFolders = model
198: .updatePrincipalSourceFolders(model.sourceFolders, true);
199:
200: updateSourceFolders(sourceFolders, model);
201: if (sourceFolders.size() > 0) {
202: JavaProjectGenerator.putSourceFolders(helper,
203: sourceFolders, null);
204: }
205: if (sourceFolders.size() > 0) {
206: JavaProjectGenerator.putSourceViews(helper, sourceFolders,
207: null);
208: }
209: JavaProjectGenerator.putJavaCompilationUnits(helper, Util
210: .getAuxiliaryConfiguration(helper),
211: model.javaCompilationUnitsList);
212: List<JavaProjectGenerator.Export> exports = JavaProjectGenerator
213: .guessExports(model.evaluator, model.baseFolder,
214: JavaProjectGenerator.getTargetMappings(helper),
215: model.javaCompilationUnitsList);
216: if (exports.size() > 0) {
217: JavaProjectGenerator.putExports(helper, exports);
218: }
219: List<String> subprojects = JavaProjectGenerator
220: .guessSubprojects(model.evaluator,
221: model.javaCompilationUnitsList,
222: model.baseFolder, model.nbProjectFolder);
223: if (subprojects.size() > 0) {
224: JavaProjectGenerator.putSubprojects(helper, subprojects);
225: }
226:
227: model.resetState();
228: }
229:
230: /** Persist modifications of project. */
231: public static void saveProject(final AntProjectHelper helper,
232: final ProjectModel model) {
233: ProjectManager.mutex().writeAccess(new Mutex.Action<Void>() {
234: public Void run() {
235: // stores only "java" type because other types was not read
236: JavaProjectGenerator.putSourceFolders(helper,
237: model.sourceFolders, TYPE_JAVA);
238: JavaProjectGenerator.putSourceViews(helper,
239: model.sourceFolders,
240: JavaProjectNature.STYLE_PACKAGES);
241:
242: List<JavaProjectGenerator.SourceFolder> sourceFolders = JavaProjectGenerator
243: .getSourceFolders(helper, null);
244: sourceFolders = model.updatePrincipalSourceFolders(
245: sourceFolders, false);
246: updateSourceFolders(sourceFolders, model);
247: JavaProjectGenerator.putSourceFolders(helper,
248: sourceFolders, null);
249:
250: AuxiliaryConfiguration aux = Util
251: .getAuxiliaryConfiguration(helper);
252: JavaProjectGenerator.putJavaCompilationUnits(helper,
253: aux, model.javaCompilationUnitsList);
254: model.resetState();
255:
256: List<JavaProjectGenerator.Export> exports = JavaProjectGenerator
257: .guessExports(model.getEvaluator(),
258: model.baseFolder, JavaProjectGenerator
259: .getTargetMappings(helper),
260: model.javaCompilationUnitsList);
261: JavaProjectGenerator.putExports(helper, exports);
262:
263: List<String> subprojects = JavaProjectGenerator
264: .guessSubprojects(model.getEvaluator(),
265: model.javaCompilationUnitsList,
266: model.baseFolder, model.nbProjectFolder);
267: JavaProjectGenerator
268: .putSubprojects(helper, subprojects);
269:
270: List<String> buildFolders = JavaProjectGenerator
271: .guessBuildFolders(model.getEvaluator(),
272: model.javaCompilationUnitsList,
273: model.baseFolder, model.nbProjectFolder);
274: JavaProjectGenerator.putBuildFolders(helper,
275: buildFolders);
276:
277: List<String> buildFiles = JavaProjectGenerator
278: .getBuildFiles(model.getEvaluator(),
279: model.javaCompilationUnitsList,
280: model.baseFolder, model.nbProjectFolder);
281: JavaProjectGenerator.putBuildFiles(helper, buildFiles);
282:
283: return null;
284: }
285: });
286: }
287:
288: // #120508: special source folder is added to save encoding for files directly under project folder
289: private static void updateSourceFolders(
290: List<JavaProjectGenerator.SourceFolder> list,
291: ProjectModel model) {
292: if (model.encoding != null) {
293: for (JavaProjectGenerator.SourceFolder sf : list) {
294: if (sf.location.equals(".")) { // NOI18N
295: sf.encoding = model.encoding;
296: return;
297: }
298: }
299: JavaProjectGenerator.SourceFolder sf = new JavaProjectGenerator.SourceFolder();
300: Project project = null;
301: try {
302: project = ProjectManager.getDefault().findProject(
303: FileUtil.toFileObject(model.nbProjectFolder));
304: } catch (IOException ioe) {
305: Exceptions.printStackTrace(ioe);
306: }
307: String label = project != null ? ProjectUtils
308: .getInformation(project).getDisplayName()
309: : "projectdir"; // NOI18N
310: sf.label = label;
311: sf.location = "."; // NOI18N
312: sf.encoding = model.encoding;
313: list.add(sf);
314: }
315: }
316:
317: /**
318: * This method according to the state of removed/added source folders
319: * will ensure that all added typed external source roots will have
320: * corresponding principal source folder and that principal source
321: * folders of all removed typed external source roots are removed too.
322: * In addition it can add project base folder as principal root
323: * if it is external.
324: *
325: * It is expected that this method will be called before project instantiation
326: * or before update of project's data.
327: *
328: * @param allSourceFolders list of all source folders, i.e. typed and untyped.
329: * @param checkProjectDir should project base folder be checked
330: * and added as principal source folder if needed or not
331: * @return copy of allSourceFolders items plus added principal source folders
332: */
333: /*private*/List<JavaProjectGenerator.SourceFolder> updatePrincipalSourceFolders(
334: List<JavaProjectGenerator.SourceFolder> allSourceFolders,
335: boolean checkProjectDir) {
336: List<JavaProjectGenerator.SourceFolder> allSF = new ArrayList<JavaProjectGenerator.SourceFolder>(
337: allSourceFolders);
338: for (String location : addedSourceFolders) {
339:
340: if (!isExternalSourceRoot(location)) {
341: continue;
342: }
343:
344: boolean exist = false;
345: String label = ""; // NOI18N
346: String includes = null, excludes = null;
347: for (JavaProjectGenerator.SourceFolder _sf : allSF) {
348: if (_sf.location.equals(location) && _sf.type == null) {
349: exist = true;
350: break;
351: }
352: if (_sf.location.equals(location) && _sf.type != null) {
353: // find some label to use
354: label = _sf.label;
355: includes = _sf.includes;
356: excludes = _sf.excludes;
357: }
358: }
359:
360: if (!exist) {
361: JavaProjectGenerator.SourceFolder _sf = new JavaProjectGenerator.SourceFolder();
362: _sf.location = location;
363: _sf.label = label;
364: _sf.includes = includes;
365: _sf.excludes = excludes;
366: allSF.add(_sf);
367: }
368: }
369:
370: for (String location : removedSourceFolders) {
371:
372: if (!isExternalSourceRoot(location)) {
373: continue;
374: }
375:
376: Iterator<JavaProjectGenerator.SourceFolder> it = allSF
377: .iterator();
378: while (it.hasNext()) {
379: JavaProjectGenerator.SourceFolder _sf = it.next();
380: if (_sf.location.equals(location) && _sf.type == null) {
381: it.remove();
382: }
383: }
384: }
385:
386: if (checkProjectDir && !baseFolder.equals(nbProjectFolder)) {
387: JavaProjectGenerator.SourceFolder gen = new JavaProjectGenerator.SourceFolder();
388: gen.location = "${"
389: + ProjectConstants.PROP_PROJECT_LOCATION + "}"; // NOI18N
390: // XXX: uniquefy label
391: gen.label = baseFolder.getName();
392: allSF.add(gen);
393: }
394:
395: return allSF;
396: }
397:
398: private boolean isExternalSourceRoot(String location) {
399: String baseFolder_ = baseFolder.getAbsolutePath();
400: if (!baseFolder_.endsWith(File.separator)) {
401: baseFolder_ += File.separatorChar;
402: }
403: String nbProjectFolder_ = nbProjectFolder.getAbsolutePath();
404: if (!nbProjectFolder_.endsWith(File.separator)) {
405: nbProjectFolder_ += File.separatorChar;
406: }
407: File f = Util.resolveFile(evaluator, baseFolder, location);
408: if (f == null) {
409: return false;
410: }
411: location = f.getAbsolutePath();
412: return (!location.startsWith(baseFolder_) && !location
413: .startsWith(nbProjectFolder_));
414: }
415:
416: /** Original project base folder. */
417: public File getBaseFolder() {
418: return baseFolder;
419: }
420:
421: /** NetBeans project folder. */
422: public File getNBProjectFolder() {
423: return nbProjectFolder;
424: }
425:
426: public PropertyEvaluator getEvaluator() {
427: return evaluator;
428: }
429:
430: public int getSourceFoldersCount() {
431: return sourceFolders.size();
432: }
433:
434: public JavaProjectGenerator.SourceFolder getSourceFolder(int index) {
435: return sourceFolders.get(index);
436: }
437:
438: public void moveSourceFolder(int fromIndex, int toIndex) {
439: JavaProjectGenerator.SourceFolder sf = sourceFolders
440: .remove(fromIndex);
441: sourceFolders.add(toIndex, sf);
442: }
443:
444: public void addSourceFolder(JavaProjectGenerator.SourceFolder sf,
445: boolean isTests) {
446: List<CompilationUnitKey> keys = createCompilationUnitKeys();
447: boolean singleCU = isSingleCompilationUnit(keys);
448: if (singleCU) {
449: // Check that source being added is part of the compilation unit.
450: // If it is not then switch to multiple compilation unit mode.
451: JavaProjectGenerator.JavaCompilationUnit cu = javaCompilationUnitsList
452: .get(0);
453: if (cu.isTests != isTests) {
454: updateCompilationUnits(true);
455: singleCU = false;
456: }
457: }
458: sourceFolders.add(sf);
459: if (singleCU) {
460: if (TYPE_JAVA.equals(sf.type)) {
461: // update existing single compilation unit
462: JavaProjectGenerator.JavaCompilationUnit cu = javaCompilationUnitsList
463: .get(0);
464: cu.packageRoots.add(sf.location);
465: }
466: } else {
467: // make sure new compilation unit is created for the source folder
468: for (CompilationUnitKey key : createCompilationUnitKeys()) {
469: getCompilationUnit(key, isTests);
470: }
471: }
472: // remember all added locations
473: if (removedSourceFolders.contains(sf.location)) {
474: removedSourceFolders.remove(sf.location);
475: } else {
476: addedSourceFolders.add(sf.location);
477: }
478: fireChangeEvent();
479: }
480:
481: public void removeSourceFolder(int index) {
482: JavaProjectGenerator.SourceFolder sf = sourceFolders.get(index);
483: if (TYPE_JAVA.equals(sf.type)) {
484: removeSourceLocation(sf.location);
485: }
486: sourceFolders.remove(index);
487: // remember all removed locations
488: if (addedSourceFolders.contains(sf.location)) {
489: addedSourceFolders.remove(sf.location);
490: } else {
491: removedSourceFolders.add(sf.location);
492: }
493: fireChangeEvent();
494: }
495:
496: public void clearSourceFolders() {
497: sourceFolders.clear();
498: javaCompilationUnitsList.clear();
499: fireChangeEvent();
500: }
501:
502: public String getSourceLevel() {
503: return sourceLevel;
504: }
505:
506: public void setSourceLevel(String sourceLevel) {
507: if ((this .sourceLevel == null && sourceLevel == null)
508: || (this .sourceLevel != null && this .sourceLevel
509: .equals(sourceLevel))) {
510: return;
511: }
512: this .sourceLevel = sourceLevel;
513: for (JavaProjectGenerator.JavaCompilationUnit cu : javaCompilationUnitsList) {
514: cu.sourceLevel = sourceLevel;
515: }
516: }
517:
518: public String getEncoding() {
519: return encoding;
520: }
521:
522: public void setEncoding(String enc) {
523: if (enc == null || enc.equals(NO_ENCODING)) {
524: encoding = null;
525: } else {
526: encoding = enc;
527: }
528: for (JavaProjectGenerator.SourceFolder sf : sourceFolders) {
529: sf.encoding = encoding;
530: }
531: }
532:
533: public boolean canHaveSeparateClasspath() {
534: // if there is more than one source root or more than one
535: // compilation unit then enable checkbox "Separate Classpath".
536: return (sourceFolders.size() > 1 || javaCompilationUnitsList
537: .size() > 1);
538: }
539:
540: public boolean canCreateSingleCompilationUnit() {
541: // if there are sources and test sources I cannot create
542: // single compilation unit for them:
543: boolean testCU = false;
544: boolean sourceCU = false;
545: for (JavaProjectGenerator.JavaCompilationUnit cu : javaCompilationUnitsList) {
546: if (cu.isTests) {
547: testCU = true;
548: } else {
549: sourceCU = true;
550: }
551: }
552: return !(testCU && sourceCU);
553: }
554:
555: public static boolean isSingleCompilationUnit(
556: List<ProjectModel.CompilationUnitKey> compilationUnitKeys) {
557: return compilationUnitKeys.size() == 1
558: && compilationUnitKeys.get(0).label == null;
559: }
560:
561: /**
562: * This method checks Java source folders and compilation units and returns
563: * list of CompilationUnitKey which represent them. The problem solved by
564: * this method is that although usually there is 1:1 mapping between
565: * source folders and compilation units, there can be also N:1 mapping when
566: * one classpath is used for all source folders. Also user's customization
567: * of project.xml can result in other combinations and they cannot be
568: * clobbered by opening such a project in UI.
569: */
570: public List<CompilationUnitKey> createCompilationUnitKeys() {
571: // XXX: cache result of this method?
572: List<CompilationUnitKey> l = new ArrayList<CompilationUnitKey>();
573: for (JavaProjectGenerator.JavaCompilationUnit cu : javaCompilationUnitsList) {
574: CompilationUnitKey cul = new CompilationUnitKey();
575: cul.locations = cu.packageRoots;
576: cul.label = null;
577: l.add(cul);
578: }
579: for (JavaProjectGenerator.SourceFolder sf : sourceFolders) {
580: if (!TYPE_JAVA.equals(sf.type)) {
581: continue;
582: }
583: CompilationUnitKey cul = new CompilationUnitKey();
584: cul.locations = new ArrayList<String>();
585: cul.locations.add(sf.location);
586: cul.label = sf.label;
587: // try to find corresponding JavaCompilationUnit
588: int index = l.indexOf(cul);
589: if (index != -1) {
590: // use this key intead because it has label
591: CompilationUnitKey cul_ = l.get(index);
592: cul_.label = sf.label;
593: continue;
594: }
595: // check whether this SourceFolder.location is not part of an existing JavaCompilationUnit
596: boolean found = false;
597: for (JavaProjectGenerator.JavaCompilationUnit cu_ : javaCompilationUnitsList) {
598: if (cu_.packageRoots.contains(sf.location)) {
599: // found: skip it
600: found = true;
601: break;
602: }
603: }
604: if (found) {
605: continue;
606: }
607: // add this source folder then:
608: l.add(cul);
609: }
610: return l;
611: }
612:
613: /**
614: * Update compilation units to 1:1 or 1:N mapping to source folders.
615: * The separateClasspath attribute if true says that each source folder
616: * will have its own compilation unit. In opposite case all source
617: * folders will have one compilation unit.
618: */
619: public void updateCompilationUnits(boolean separateClasspath) {
620: if (separateClasspath) {
621: // This means that there was one compilation unit for all sources.
622: // So create compilation unit per source folder.
623: String classpath = null;
624: List<String> output = null;
625: // Copy classpath and output from the first compilation unit
626: // to all compilation units - should be easier to customize for user.
627: if (javaCompilationUnitsList.size() > 0) {
628: List<JavaProjectGenerator.JavaCompilationUnit.CP> classpaths = javaCompilationUnitsList
629: .get(0).classpath;
630: if (classpaths != null) {
631: // find first "compile" mode classpath and use it
632: for (JavaProjectGenerator.JavaCompilationUnit.CP cp : classpaths) {
633: if (cp.mode.equals(CLASSPATH_MODE_COMPILE)) {
634: classpath = cp.classpath;
635: break;
636: }
637: }
638: }
639: output = javaCompilationUnitsList.get(0).output;
640: }
641: javaCompilationUnitsList.clear();
642: for (JavaProjectGenerator.SourceFolder sf : sourceFolders) {
643: JavaProjectGenerator.JavaCompilationUnit cu = new JavaProjectGenerator.JavaCompilationUnit();
644: cu.packageRoots = new ArrayList<String>();
645: cu.packageRoots.add(sf.location);
646: if (classpath != null) {
647: JavaProjectGenerator.JavaCompilationUnit.CP cp = new JavaProjectGenerator.JavaCompilationUnit.CP();
648: cp.mode = CLASSPATH_MODE_COMPILE;
649: cp.classpath = classpath;
650: cu.classpath = new ArrayList<JavaProjectGenerator.JavaCompilationUnit.CP>();
651: cu.classpath.add(cp);
652: }
653: if (output != null) {
654: cu.output = new ArrayList<String>();
655: cu.output.addAll(output);
656: }
657: cu.sourceLevel = sourceLevel;
658: javaCompilationUnitsList.add(cu);
659: }
660: } else {
661: // This means that there are some compilation units which should be
662: // merged into one which will be used for all sources.
663: List<String> packageRoots = new ArrayList<String>();
664: // First list of source roots
665: for (JavaProjectGenerator.SourceFolder sf : sourceFolders) {
666: packageRoots.add(sf.location);
667: }
668: // Now try to merge all classpaths and outputs. Might be easier to customize
669: Set<String> classpath = new LinkedHashSet<String>();
670: Set<String> output = new LinkedHashSet<String>();
671: for (JavaProjectGenerator.JavaCompilationUnit cu : javaCompilationUnitsList) {
672: if (cu.output != null) {
673: output.addAll(cu.output);
674: }
675: if (cu.classpath != null) {
676: for (JavaProjectGenerator.JavaCompilationUnit.CP cp : cu.classpath) {
677: if (cp.mode.equals(CLASSPATH_MODE_COMPILE)) {
678: classpath
679: .addAll(Arrays
680: .asList(PropertyUtils
681: .tokenizePath(cp.classpath)));
682: }
683: }
684: }
685: }
686: javaCompilationUnitsList.clear();
687: JavaProjectGenerator.JavaCompilationUnit cu = new JavaProjectGenerator.JavaCompilationUnit();
688: cu.packageRoots = packageRoots;
689: JavaProjectGenerator.JavaCompilationUnit.CP cp = new JavaProjectGenerator.JavaCompilationUnit.CP();
690: if (classpath.size() > 0) {
691: StringBuffer cp_ = new StringBuffer();
692: Iterator<String> it = classpath.iterator();
693: while (it.hasNext()) {
694: cp_.append(it.next());
695: if (it.hasNext()) {
696: cp_.append(File.pathSeparatorChar);
697: }
698: }
699: cp.classpath = cp_.toString();
700: cp.mode = CLASSPATH_MODE_COMPILE;
701: cu.classpath = new ArrayList<JavaProjectGenerator.JavaCompilationUnit.CP>();
702: cu.classpath.add(cp);
703: }
704: cu.output = new ArrayList<String>(output);
705: cu.sourceLevel = sourceLevel;
706: javaCompilationUnitsList.add(cu);
707: }
708: fireChangeEvent();
709: }
710:
711: /** Retrieve compilation unit or create empty one if it does not exist yet for the given
712: * key which is source package path(s).
713: * The isTests is used only to initialize newly created compilation unit.
714: */
715: public JavaProjectGenerator.JavaCompilationUnit getCompilationUnit(
716: CompilationUnitKey key, boolean isTests) {
717: for (JavaProjectGenerator.JavaCompilationUnit cu : javaCompilationUnitsList) {
718: if (cu.packageRoots.equals(key.locations)) {
719: return cu;
720: }
721: }
722: JavaProjectGenerator.JavaCompilationUnit cu = new JavaProjectGenerator.JavaCompilationUnit();
723: cu.packageRoots = key.locations;
724: cu.sourceLevel = sourceLevel;
725: cu.isTests = isTests;
726: javaCompilationUnitsList.add(cu);
727: return cu;
728: }
729:
730: private void removeSourceLocation(String location) {
731: Iterator<JavaProjectGenerator.JavaCompilationUnit> it = javaCompilationUnitsList
732: .iterator();
733: while (it.hasNext()) {
734: JavaProjectGenerator.JavaCompilationUnit cu = it.next();
735: if (cu.packageRoots.contains(location)) {
736: cu.packageRoots.remove(location);
737: }
738: if (cu.packageRoots.size() == 0) {
739: it.remove();
740: }
741: }
742: }
743:
744: /** Update style of loaded source folders of type "java" to packages. */
745: private static void updateStyle(
746: List<JavaProjectGenerator.SourceFolder> sources) {
747: for (JavaProjectGenerator.SourceFolder sf : sources) {
748: assert sf.type.equals(TYPE_JAVA);
749: sf.style = JavaProjectNature.STYLE_PACKAGES;
750: }
751: }
752:
753: // only for unit testing
754: void setSourceFolders(List<JavaProjectGenerator.SourceFolder> list) {
755: sourceFolders = list;
756: }
757:
758: // only for unit testing
759: List<JavaProjectGenerator.SourceFolder> getSourceFolders() {
760: return sourceFolders;
761: }
762:
763: // only for unit testing
764: void setJavaCompilationUnits(
765: List<JavaProjectGenerator.JavaCompilationUnit> list) {
766: javaCompilationUnitsList = list;
767: }
768:
769: // only for unit testing
770: List<JavaProjectGenerator.JavaCompilationUnit> getJavaCompilationUnits() {
771: return javaCompilationUnitsList;
772: }
773:
774: /**
775: * Helper method returning source level of the current platform.
776: */
777: public static String getDefaultSourceLevel() {
778: JavaPlatform platform = JavaPlatform.getDefault();
779: SpecificationVersion sv = platform.getSpecification()
780: .getVersion();
781: if (sv.compareTo(JDK_MAX_SUPPORTED_VERSION) > 0) {
782: sv = JDK_MAX_SUPPORTED_VERSION;
783: }
784: return sv.toString();
785: }
786:
787: public boolean isTestSourceFolder(int index) {
788: return isTestSourceFolder(getSourceFolder(index));
789: }
790:
791: public boolean isTestSourceFolder(
792: JavaProjectGenerator.SourceFolder sf) {
793: for (JavaProjectGenerator.JavaCompilationUnit cu : javaCompilationUnitsList) {
794: if (cu.packageRoots.contains(sf.location)) {
795: return cu.isTests;
796: }
797: }
798: return false;
799: }
800:
801: public static class CompilationUnitKey {
802: public List<String> locations;
803: public String label;
804:
805: public boolean equals(Object o) {
806: if (o == this ) {
807: return true;
808: }
809: if (!(o instanceof CompilationUnitKey)) {
810: return false;
811: }
812: CompilationUnitKey cul = (CompilationUnitKey) o;
813: return this .locations.equals(cul.locations);
814: }
815:
816: public int hashCode() {
817: return locations.hashCode() * 7;
818: }
819:
820: public String toString() {
821: return "PM.CUK:[label=" + label + ", locations="
822: + locations + ", this=" + super .toString() + "]"; // NOI18N
823: }
824: }
825:
826: }
|