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.j2me.cdc.project.ui.wizards;
043:
044: import java.awt.Component;
045: import java.io.File;
046: import java.io.IOException;
047: import java.io.OutputStream;
048: import java.io.PrintWriter;
049: import java.net.URI;
050: import java.net.URL;
051: import java.text.MessageFormat;
052: import java.util.ArrayList;
053: import java.util.Collection;
054: import java.util.HashSet;
055: import java.util.List;
056: import java.util.NoSuchElementException;
057: import java.util.Properties;
058: import java.util.Set;
059: import javax.swing.JComponent;
060: import javax.swing.event.ChangeListener;
061: import org.netbeans.api.java.classpath.ClassPath;
062: import org.netbeans.api.java.platform.JavaPlatform;
063: import org.netbeans.api.java.platform.JavaPlatformManager;
064: import org.netbeans.api.java.platform.Specification;
065: import org.netbeans.api.project.Project;
066: import org.netbeans.modules.j2me.cdc.platform.CDCPlatform;
067: import org.netbeans.modules.j2me.cdc.project.CDCPropertiesDescriptor;
068: import org.netbeans.modules.mobility.project.J2MEProjectGenerator;
069: import org.netbeans.modules.mobility.project.ui.wizard.PlatformInstallPanel;
070: import org.netbeans.modules.j2me.cdc.project.ui.CDCFoldersListSettings;
071: import org.netbeans.modules.mobility.project.DefaultPropertiesDescriptor;
072: import org.netbeans.modules.mobility.project.ui.wizard.PlatformSelectionPanel;
073: import org.netbeans.spi.project.support.ant.AntProjectHelper;
074: import org.netbeans.spi.project.support.ant.EditableProperties;
075: import org.netbeans.spi.project.ui.support.ProjectChooser;
076: import org.openide.ErrorManager;
077: import org.openide.WizardDescriptor;
078: import org.openide.filesystems.FileLock;
079: import org.openide.filesystems.FileObject;
080: import org.openide.filesystems.FileUtil;
081: import org.openide.filesystems.Repository;
082: import org.openide.loaders.DataFolder;
083: import org.openide.loaders.DataObject;
084: import org.openide.loaders.TemplateWizard;
085: import org.openide.util.NbBundle;
086:
087: /**
088: * Wizard to create a new CDC project.
089: */
090: public class NewCDCProjectWizardIterator implements
091: TemplateWizard.Iterator {
092:
093: public static final int TYPE_APP = 0;
094: public static final int TYPE_LIB = 1;
095: public static final int TYPE_EXT = 2;
096: public static final int TYPE_SAMPLE = 3;
097:
098: static final String PROP_NAME_INDEX = "nameIndex"; //NOI18N
099: static final String MANIFEST_FILE = "manifest.mf"; // NOI18N
100:
101: private static final long serialVersionUID = 1L;
102:
103: private int type;
104:
105: /** Create a new wizard iterator. */
106: public NewCDCProjectWizardIterator() {
107: this (TYPE_APP);
108: }
109:
110: public NewCDCProjectWizardIterator(int type) {
111: this .type = type;
112: }
113:
114: public static NewCDCProjectWizardIterator library() {
115: return new NewCDCProjectWizardIterator(TYPE_LIB);
116: }
117:
118: public static NewCDCProjectWizardIterator existing() {
119: return new NewCDCProjectWizardIterator(TYPE_EXT);
120: }
121:
122: private WizardDescriptor.Panel[] createPanels() {
123: int i = getNumberOfCdcPlatforms();
124: return i != 0 ? new WizardDescriptor.Panel[] {
125: new PanelConfigureProject(this .type),
126: new PanelConfigurePlatform(), }
127: : new WizardDescriptor.Panel[] {
128: new PlatformInstallPanel.WizardPanel(
129: CDCPlatform.PLATFORM_CDC),
130: new PanelConfigureProject(this .type),
131: new PanelConfigurePlatform(),
132:
133: };
134: }
135:
136: private String[] createSteps() {
137: int i = getNumberOfCdcPlatforms();
138: return i != 0 ? new String[] {
139: NbBundle.getMessage(NewCDCProjectWizardIterator.class,
140: "LAB_ConfigureProject"),
141: NbBundle.getMessage(NewCDCProjectWizardIterator.class,
142: "LAB_SelectPlatform"), } : new String[] {
143: NbBundle.getMessage(NewCDCProjectWizardIterator.class,
144: "LAB_Step_AddPlatform"), //NOI18N
145: NbBundle.getMessage(NewCDCProjectWizardIterator.class,
146: "LAB_ConfigureProject"),
147: NbBundle.getMessage(NewCDCProjectWizardIterator.class,
148: "LAB_SelectPlatform"), };
149: }
150:
151: private static String createMainClass(String mainClassName,
152: FileObject srcFolder, String platformType)
153: throws IOException {
154: int lastDotIdx = mainClassName.lastIndexOf('.');
155: String mName, pName;
156: if (lastDotIdx == -1) {
157: mName = mainClassName.trim();
158: pName = null;
159: } else {
160: mName = mainClassName.substring(lastDotIdx + 1).trim();
161: pName = mainClassName.substring(0, lastDotIdx).trim();
162: }
163: if (mName.length() == 0 || platformType == null)
164: return null;
165: FileObject mainTemplate = Repository.getDefault()
166: .getDefaultFileSystem().findResource(
167: "MainTemplates/org.netbeans.modules.kjava.j2meproject/"
168: + platformType); //NOI18N
169: if (mainTemplate == null)
170: return null;
171: String templateName = (String) mainTemplate
172: .getAttribute("templateName"); //NOI18N
173: String templateType = (String) mainTemplate
174: .getAttribute("templateType"); //NOI18N
175: if (templateName == null || templateType == null)
176: return null;
177: mainTemplate = Repository.getDefault().getDefaultFileSystem()
178: .findResource(templateName);
179: if (mainTemplate == null)
180: return null;
181: DataObject mt = DataObject.find(mainTemplate);
182: FileObject pkgFolder = srcFolder;
183: if (pName != null) {
184: String fName = pName.replace('.', '/'); // NOI18N
185: pkgFolder = FileUtil.createFolder(srcFolder, fName);
186: }
187: DataFolder pDf = DataFolder.findFolder(pkgFolder);
188: DataObject doj = mt.createFromTemplate(pDf, mName);
189: if (doj != null)
190: doj.getPrimaryFile().setAttribute("justCreatedByNewWizard",
191: Boolean.TRUE); //NOI18N
192: return templateType;
193: }
194:
195: private static String normalizePath(File path, File jdkHome,
196: String propName) {
197: String jdkLoc = jdkHome.getAbsolutePath();
198: if (!jdkLoc.endsWith(File.separator)) {
199: jdkLoc = jdkLoc + File.separator;
200: }
201: String loc = path.getAbsolutePath();
202: if (loc.startsWith(jdkLoc)) {
203: return "${" + propName + "}" + File.separator
204: + loc.substring(jdkLoc.length()); //NOI18N
205: }
206: return loc;
207: }
208:
209: public static void generatePlatformProperties(CDCPlatform platform,
210: String activeDevice, String activeProfile,
211: EditableProperties props) {
212: Collection<FileObject> installFolders = platform
213: .getInstallFolders();
214: if (installFolders.size() > 0) {
215: File jdkHome = FileUtil.toFile(installFolders.iterator()
216: .next());
217: StringBuffer sbootcp = new StringBuffer();
218: ClassPath bootCP = platform
219: .getBootstrapLibrariesForProfile(activeDevice,
220: activeProfile);
221: for (ClassPath.Entry entry : (List<ClassPath.Entry>) bootCP
222: .entries()) {
223: URL url = entry.getURL();
224: if ("jar".equals(url.getProtocol())) { //NOI18N
225: url = FileUtil.getArchiveFile(url);
226: }
227: File root = new File(URI.create(url.toExternalForm()));
228: if (sbootcp.length() > 0) {
229: sbootcp.append(File.pathSeparator);
230: }
231: sbootcp.append(normalizePath(root, jdkHome,
232: "platform.home"));
233: }
234: props.setProperty(CDCPropertiesDescriptor.PLATFORM_FAT_JAR,
235: Boolean.toString(platform.isFatJar()));
236: props.setProperty("platform.bootclasspath", sbootcp
237: .toString()); //NOI18N
238: props.setProperty("javac.source", platform
239: .getClassVersion());
240: props.setProperty("javac.target", platform
241: .getClassVersion());
242: }
243: }
244:
245: public Set<DataObject> instantiate(TemplateWizard wiz)
246: throws IOException {
247: Set<DataObject> resultSet = new HashSet<DataObject>();
248: File dirF = (File) wiz.getProperty("projdir"); //NOI18N
249: if (dirF != null) {
250: dirF = FileUtil.normalizeFile(dirF);
251: }
252: String name = (String) wiz.getProperty("name"); //NOI18N
253: final String mainClass = (String) wiz.getProperty("mainClass"); //NOI18N
254: String appName = (String) wiz.getProperty("appName"); //NOI18N
255:
256: final String activePlatform = (String) wiz
257: .getProperty("activePlatform"); //NOI18N
258: final String activeDevice = (String) wiz
259: .getProperty("activeDevice"); //NOI18N
260: final String activeProfile = (String) wiz
261: .getProperty("activeProfile"); //NOI18N
262: Properties props = (Properties) wiz
263: .getProperty("additionalProperties"); //NOI18N
264:
265: PlatformSelectionPanel.PlatformDescription pd = (PlatformSelectionPanel.PlatformDescription) wiz
266: .getProperty(PlatformSelectionPanel.PLATFORM_DESCRIPTION);
267: AntProjectHelper h = J2MEProjectGenerator.createProject(dirF,
268: name, pd,
269: new J2MEProjectGenerator.ProjectGeneratorCallback() {
270: public void doPostGeneration(Project project,
271: AntProjectHelper helper,
272: FileObject projectLocation,
273: File projectLocationFile,
274: ArrayList<String> configurations)
275: throws IOException {
276: final FileObject src = projectLocation
277: .createFolder("src");
278: JavaPlatform[] platforms = JavaPlatformManager
279: .getDefault()
280: .getPlatforms(
281: activePlatform,
282: new Specification(
283: CDCPlatform.PLATFORM_CDC,
284: null)); //NOI18N
285: if (platforms.length != 0) {
286: CDCPlatform cdcplatform = (CDCPlatform) platforms[0];
287: final EditableProperties ep = helper
288: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
289: if (mainClass != null) {
290: String templateType = createMainClass(
291: mainClass, src, cdcplatform
292: .getType());
293: ep
294: .setProperty(
295: CDCPropertiesDescriptor.MAIN_CLASS,
296: mainClass);
297: if (templateType != null) {
298: ep
299: .setProperty(
300: CDCPropertiesDescriptor.MAIN_CLASS_CLASS,
301: templateType);
302: }
303: }
304: ep
305: .setProperty(
306: CDCPropertiesDescriptor.APPLICATION_NAME,
307: project
308: .getProjectDirectory()
309: .getNameExt());
310: ep
311: .setProperty(
312: DefaultPropertiesDescriptor.PLATFORM_ACTIVE,
313: cdcplatform.getAntName()); // NOI18N
314: ep
315: .setProperty(
316: DefaultPropertiesDescriptor.PLATFORM_ACTIVE_DESCRIPTION,
317: cdcplatform
318: .getDisplayName()); // NOI18N
319: ep
320: .setProperty(
321: DefaultPropertiesDescriptor.PLATFORM_TRIGGER,
322: "CDC"); // NOI18N
323: ep
324: .setProperty(
325: DefaultPropertiesDescriptor.PLATFORM_TYPE,
326: cdcplatform.getType()); // NOI18N
327: String classVersion = cdcplatform
328: .getClassVersion();
329: ep
330: .setProperty(
331: DefaultPropertiesDescriptor.PLATFORM_DEVICE,
332: activeDevice); // NOI18N
333: ep
334: .setProperty(
335: DefaultPropertiesDescriptor.PLATFORM_PROFILE,
336: activeProfile); // NOI18N
337: //add bootclasspath
338: generatePlatformProperties(cdcplatform,
339: activeDevice, activeProfile, ep); // NOI18N
340: ep
341: .setProperty(
342: DefaultPropertiesDescriptor.JAVAC_SOURCE,
343: classVersion != null ? classVersion
344: : "1.2"); // NOI18N
345: ep
346: .setProperty(
347: DefaultPropertiesDescriptor.JAVAC_TARGET,
348: classVersion != null ? classVersion
349: : "1.2"); // NOI18N
350: helper
351: .putProperties(
352: AntProjectHelper.PROJECT_PROPERTIES_PATH,
353: ep);
354: } else {
355: throw new IllegalArgumentException(
356: "No CDC platform installed");// NOI18N
357: }
358: }
359: });
360: if (mainClass != null && mainClass.length() > 0) {
361: try {
362: FileObject sourcesRoot = h.getProjectDirectory()
363: .getFileObject("src"); //NOI18N
364: FileObject mainClassFo = getMainClassFO(sourcesRoot,
365: mainClass);
366: assert mainClassFo != null : "sourcesRoot: "
367: + sourcesRoot + ", mainClass: " + mainClass; //NOI18N
368: // Returning FileObject of main class, will be called its preferred action
369: resultSet.add(DataObject.find(mainClassFo));
370: } catch (Exception x) {
371: ErrorManager.getDefault().notify(x);
372: }
373: }
374:
375: FileObject dir = FileUtil.toFileObject(dirF);
376: if (type == TYPE_APP || type == TYPE_EXT) {
377: createManifest(dir, MANIFEST_FILE);
378: }
379:
380: // Returning FileObject of project diretory.
381: // Project will be open and set as main
382: Integer index = (Integer) wiz.getProperty(PROP_NAME_INDEX);
383: switch (this .type) {
384: case TYPE_APP:
385: CDCFoldersListSettings.setNewApplicationCount(index);
386: break;
387: case TYPE_LIB:
388: CDCFoldersListSettings.setNewLibraryCount(index.intValue());
389: break;
390: case TYPE_EXT:
391: CDCFoldersListSettings.setNewProjectCount(index.intValue());
392: break;
393: }
394: resultSet.add(DataObject.find(h.getProjectDirectory()));
395:
396: dirF = (dirF != null) ? dirF.getParentFile() : null;
397: if (dirF != null && dirF.exists()) {
398: ProjectChooser.setProjectsFolder(dirF);
399: }
400:
401: return resultSet;
402: }
403:
404: private transient int index;
405: private transient WizardDescriptor.Panel[] panels;
406:
407: public void initialize(TemplateWizard wiz) {
408: index = 0;
409: panels = createPanels();
410: // Make sure list of steps is accurate.
411: String[] steps = createSteps();
412: for (int i = 0; i < panels.length; i++) {
413: Component c = panels[i].getComponent();
414: if (steps[i] == null) {
415: // Default step name to component name of panel.
416: // Mainly useful for getting the name of the target
417: // chooser to appear in the list of steps.
418: steps[i] = c.getName();
419: }
420: if (c instanceof JComponent) { // assume Swing components
421: JComponent jc = (JComponent) c;
422: // Step #.
423: jc.putClientProperty(
424: "WizardPanel_contentSelectedIndex",
425: new Integer(i)); // NOI18N
426: // Step name (actually the whole list for reference).
427: jc.putClientProperty("WizardPanel_contentData", steps); // NOI18N
428: }
429: }
430: wiz.putProperty("additionalProperties", new Properties());
431: }
432:
433: public void uninitialize(TemplateWizard wiz) {
434:
435: if (wiz != null) {
436: wiz.putProperty("additionalProperties", null);
437: wiz.putProperty("projdir", null); //NOI18N
438: wiz.putProperty("name", null); //NOI18N
439: wiz.putProperty("mainClass", null); //NOI18N
440: if (this .type == TYPE_EXT) {
441: wiz.putProperty("sourceRoot", null); //NOI18N
442: wiz.putProperty("testRoot", null); //NOI18N
443: }
444: }
445: wiz = null;
446: panels = null;
447: }
448:
449: public String name() {
450: return MessageFormat.format(NbBundle.getMessage(
451: NewCDCProjectWizardIterator.class, "LAB_IteratorName"),
452: new Object[] { new Integer(index + 1),
453: new Integer(panels.length) });
454: }
455:
456: public boolean hasNext() {
457: return index < panels.length - 1;
458: }
459:
460: public boolean hasPrevious() {
461: return index > 0;
462: }
463:
464: public void nextPanel() {
465: if (!hasNext())
466: throw new NoSuchElementException();
467: index++;
468: }
469:
470: public void previousPanel() {
471: if (!hasPrevious())
472: throw new NoSuchElementException();
473: index--;
474: }
475:
476: public WizardDescriptor.Panel current() {
477: return panels[index];
478: }
479:
480: // If nothing unusual changes in the middle of the wizard, simply:
481: public final void addChangeListener(ChangeListener l) {
482: }
483:
484: public final void removeChangeListener(ChangeListener l) {
485: }
486:
487: // helper methods, finds mainclass's FileObject
488: private FileObject getMainClassFO(FileObject sourcesRoot,
489: String mainClass) {
490: // replace '.' with '/'
491: mainClass = mainClass.replace('.', '/'); // NOI18N
492:
493: // ignore unvalid mainClass ???
494:
495: return sourcesRoot.getFileObject(mainClass + ".java"); // NOI18N
496: }
497:
498: static String getPackageName(String displayName) {
499: StringBuffer builder = new StringBuffer();
500: boolean firstLetter = true;
501: for (int i = 0; i < displayName.length(); i++) {
502: char c = displayName.charAt(i);
503: if ((!firstLetter && Character.isJavaIdentifierPart(c))
504: || (firstLetter && Character
505: .isJavaIdentifierStart(c))) {
506: firstLetter = false;
507: if (Character.isUpperCase(c)) {
508: c = Character.toLowerCase(c);
509: }
510: builder.append(c);
511: }
512: }
513: return builder.length() == 0 ? NbBundle.getMessage(
514: NewCDCProjectWizardIterator.class,
515: "TXT_DefaultPackageName") : builder.toString();
516: }
517:
518: /**
519: * Create a new application manifest file with minimal initial contents.
520: * @param dir the directory to create it in
521: * @param path the relative path of the file
522: * @throws IOException in case of problems
523: */
524: static void createManifest(FileObject dir, String path)
525: throws IOException {
526: FileObject manifest = dir.createData(MANIFEST_FILE);
527: FileLock lock = manifest.lock();
528: try {
529: OutputStream os = manifest.getOutputStream(lock);
530: try {
531: PrintWriter pw = new PrintWriter(os);
532: pw.println("Manifest-Version: 1.0"); // NOI18N
533: pw
534: .println("X-COMMENT: Main-Class will be added automatically by build"); // NOI18N
535: pw.println(); // safest to end in \n\n due to JRE parsing bug
536: pw.flush();
537: } finally {
538: os.close();
539: }
540: } finally {
541: lock.releaseLock();
542: }
543: }
544:
545: static int getNumberOfCdcPlatforms() {
546: JavaPlatform[] platforms = JavaPlatformManager.getDefault()
547: .getPlatforms(
548: null,
549: new Specification(CDCPlatform.PLATFORM_CDC,
550: null)); //NOI18N
551: return platforms.length;
552: }
553: }
|