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.apisupport.project.ui;
043:
044: import java.beans.PropertyChangeEvent;
045: import java.beans.PropertyChangeListener;
046: import java.io.CharConversionException;
047: import java.net.URL;
048: import java.text.MessageFormat;
049: import java.util.Arrays;
050: import java.util.Collections;
051: import java.util.HashSet;
052: import java.util.Iterator;
053: import java.util.List;
054: import java.util.ArrayList;
055: import java.util.Set;
056: import javax.swing.Action;
057: import javax.swing.Icon;
058: import javax.swing.ImageIcon;
059: import javax.swing.event.ChangeEvent;
060: import javax.swing.event.ChangeListener;
061: import org.netbeans.api.java.classpath.ClassPath;
062: import org.netbeans.api.java.queries.JavadocForBinaryQuery;
063: import org.openide.filesystems.FileObject;
064: import org.openide.filesystems.FileStateInvalidException;
065: import org.openide.filesystems.FileUtil;
066: import org.openide.nodes.Children;
067: import org.openide.nodes.AbstractNode;
068: import org.openide.nodes.Node;
069: import org.openide.util.NbBundle;
070: import org.openide.util.RequestProcessor;
071: import org.openide.util.Utilities;
072: import org.openide.util.WeakListeners;
073: import org.openide.ErrorManager;
074: import org.netbeans.api.java.platform.JavaPlatform;
075: import org.netbeans.api.java.platform.JavaPlatformManager;
076: import org.netbeans.api.project.SourceGroup;
077: import org.netbeans.modules.apisupport.project.ui.customizer.ModuleProperties;
078: import org.netbeans.spi.project.support.ant.PropertyEvaluator;
079: import org.netbeans.spi.java.project.support.ui.PackageView;
080: import org.openide.util.ChangeSupport;
081: import org.openide.util.actions.SystemAction;
082: import org.openide.util.lookup.Lookups;
083: import org.openide.xml.XMLUtil;
084:
085: // XXX this class is more or less copy-pasted from j2seproject.
086: // Get rid of it as soon as "some" Libraries Node API is provided.
087:
088: /**
089: * PlatformNode represents Java platform in the logical view.
090: * Listens on the {@link PropertyEvaluator} for change of
091: * the ant property holding the platform name.
092: * It displays the content of boot classpath.
093: * @see JavaPlatform
094: * @author Tomas Zezula
095: */
096: final class PlatformNode extends AbstractNode implements ChangeListener {
097:
098: private static final String PLATFORM_ICON = "org/netbeans/modules/apisupport/project/ui/resources/platform.gif"; //NOI18N
099: private static final String ARCHIVE_ICON = "org/netbeans/modules/apisupport/project/ui/resources/jar.gif"; //NOI18N
100:
101: private final PlatformProvider pp;
102:
103: private PlatformNode(PlatformProvider pp) {
104: super (new PlatformContentChildren(), Lookups
105: .singleton(new JavadocProvider(pp)));
106: this .pp = pp;
107: this .pp.addChangeListener(this );
108: setIconBaseWithExtension(PLATFORM_ICON);
109: }
110:
111: public String getName() {
112: return this .getDisplayName();
113: }
114:
115: public String getDisplayName() {
116: JavaPlatform plat = pp.getPlatform();
117: String name;
118: if (plat != null) {
119: name = plat.getDisplayName();
120: } else {
121: String platformId = pp.getPlatformID();
122: if (platformId == null) {
123: name = NbBundle.getMessage(PlatformNode.class,
124: "TXT_BrokenPlatform");
125: } else {
126: name = MessageFormat.format(NbBundle.getMessage(
127: PlatformNode.class, "FMT_BrokenPlatform"),
128: new Object[] { platformId });
129: }
130: }
131: return name;
132: }
133:
134: public String getHtmlDisplayName() {
135: if (pp.getPlatform() == null) {
136: String displayName = this .getDisplayName();
137: try {
138: displayName = XMLUtil.toElementContent(displayName);
139: } catch (CharConversionException ex) {
140: // OK, no annotation in this case
141: return null;
142: }
143: return "<font color=\"#A40000\">" + displayName + "</font>"; //NOI18N
144: } else {
145: return null;
146: }
147: }
148:
149: public boolean canCopy() {
150: return false;
151: }
152:
153: public Action[] getActions(boolean context) {
154: return new Action[] { SystemAction.get(ShowJavadocAction.class) };
155: }
156:
157: public void stateChanged(ChangeEvent e) {
158: this .fireNameChange(null, null);
159: this .fireDisplayNameChange(null, null);
160: //The caller holds ProjectManager.mutex() read lock
161: RequestProcessor.getDefault().post(new Runnable() {
162: public void run() {
163: ((PlatformContentChildren) getChildren()).addNotify();
164: }
165: });
166: }
167:
168: /**
169: * Creates new PlatformNode
170: * @param eval the PropertyEvaluator used for obtaining the active platform name
171: * and listening on the active platform change
172: * @param platformPropName the name of ant property holding the platform name
173: */
174: static PlatformNode create(PropertyEvaluator eval,
175: String platformPropName) {
176: PlatformProvider pp = new PlatformProvider(eval,
177: platformPropName);
178: return new PlatformNode(pp);
179: }
180:
181: private static class PlatformContentChildren extends
182: Children.Keys<SourceGroup> {
183:
184: PlatformContentChildren() {
185: }
186:
187: protected void addNotify() {
188: this .setKeys(this .getKeys());
189: }
190:
191: protected void removeNotify() {
192: this .setKeys(Collections.<SourceGroup> emptySet());
193: }
194:
195: protected Node[] createNodes(SourceGroup sg) {
196: return new Node[] { ActionFilterNode.create(PackageView
197: .createPackageView(sg)) };
198: }
199:
200: private List<SourceGroup> getKeys() {
201: JavaPlatform platform = ((PlatformNode) this .getNode()).pp
202: .getPlatform();
203: if (platform == null) {
204: return Collections.emptyList();
205: }
206: //Todo: Should listen on returned classpath, but now the bootstrap libraries are read only
207: FileObject[] roots = platform.getBootstrapLibraries()
208: .getRoots();
209: List<SourceGroup> result = new ArrayList<SourceGroup>(
210: roots.length);
211: for (int i = 0; i < roots.length; i++) {
212: try {
213: FileObject file;
214: Icon icon;
215: if ("jar".equals(roots[i].getURL().getProtocol())) { //NOI18N
216: file = FileUtil.getArchiveFile(roots[i]);
217: icon = new ImageIcon(Utilities
218: .loadImage(ARCHIVE_ICON));
219: } else {
220: file = roots[i];
221: icon = null;
222: }
223: if (file.isValid()) {
224: result.add(new LibrariesSourceGroup(roots[i],
225: file.getNameExt(), icon, icon));
226: }
227: } catch (FileStateInvalidException e) {
228: ErrorManager.getDefault().notify(e);
229: }
230: }
231: return result;
232: }
233: }
234:
235: private static class PlatformProvider implements
236: PropertyChangeListener {
237:
238: private final PropertyEvaluator evaluator;
239: private final String platformPropName;
240: private JavaPlatform platformCache;
241: private final ChangeSupport changeSupport = new ChangeSupport(
242: this );
243:
244: public PlatformProvider(PropertyEvaluator evaluator,
245: String platformPropName) {
246: this .evaluator = evaluator;
247: this .platformPropName = platformPropName;
248: this .evaluator.addPropertyChangeListener(WeakListeners
249: .propertyChange(this , evaluator));
250: }
251:
252: public String getPlatformID() {
253: return this .evaluator.getProperty(this .platformPropName);
254: }
255:
256: public JavaPlatform getPlatform() {
257: if (platformCache == null) {
258: final String platformPropName = getPlatformID();
259: platformCache = ModuleProperties
260: .findJavaPlatformByLocation(platformPropName);
261: if (platformCache != null
262: && platformCache.getInstallFolders().size() == 0) {
263: //Deleted platform
264: platformCache = null;
265: }
266: //Issue: #57840: Broken platform 'default_platform'
267: if (ErrorManager.getDefault().isLoggable(
268: ErrorManager.INFORMATIONAL)
269: && platformCache == null) {
270: StringBuffer message = new StringBuffer(
271: "RequestedPlatform: "
272: + platformPropName
273: + " not found.\nInstalled Platforms:\n"); // NOI18N
274: JavaPlatform[] platforms = JavaPlatformManager
275: .getDefault().getInstalledPlatforms();
276: for (int i = 0; i < platforms.length; i++) {
277: message.append("Name: "
278: + platforms[i].getProperties().get(
279: "platform.ant.name")
280: + // NOI18N
281: " Broken: "
282: + (platforms[i].getInstallFolders()
283: .size() == 0) + "\n"); // NOI18N
284: }
285: ErrorManager.getDefault().log(
286: ErrorManager.INFORMATIONAL,
287: message.toString());
288: }
289: }
290: return platformCache;
291: }
292:
293: public void addChangeListener(ChangeListener l) {
294: changeSupport.addChangeListener(l);
295: }
296:
297: public void removeChangeListener(ChangeListener l) {
298: changeSupport.removeChangeListener(l);
299: }
300:
301: public void propertyChange(PropertyChangeEvent evt) {
302: if (platformPropName.equals(evt.getPropertyName())) {
303: platformCache = null;
304: this .changeSupport.fireChange();
305: }
306: }
307:
308: }
309:
310: private static class JavadocProvider implements
311: ShowJavadocAction.JavadocProvider {
312:
313: PlatformProvider platformProvider;
314:
315: private JavadocProvider(PlatformProvider platformProvider) {
316: this .platformProvider = platformProvider;
317: }
318:
319: public boolean hasJavadoc() {
320: JavaPlatform platform = platformProvider.getPlatform();
321: if (platform == null) {
322: return false;
323: }
324: URL[] javadocRoots = getJavadocRoots(platform);
325: return javadocRoots.length > 0;
326: }
327:
328: public void showJavadoc() {
329: JavaPlatform platform = platformProvider.getPlatform();
330: if (platform != null) {
331: URL[] javadocRoots = getJavadocRoots(platform);
332: URL pageURL = ShowJavadocAction.findJavadoc(
333: "overview-summary.html", javadocRoots);
334: if (pageURL == null) {
335: pageURL = ShowJavadocAction.findJavadoc(
336: "index.html", javadocRoots);
337: }
338: ShowJavadocAction.showJavaDoc(pageURL, platform
339: .getDisplayName());
340: }
341: }
342:
343: private static URL[] getJavadocRoots(JavaPlatform platform) {
344: Set<URL> result = new HashSet<URL>();
345: List<ClassPath.Entry> l = platform.getBootstrapLibraries()
346: .entries();
347: for (Iterator it = l.iterator(); it.hasNext();) {
348: ClassPath.Entry e = (ClassPath.Entry) it.next();
349: result.addAll(Arrays.asList(JavadocForBinaryQuery
350: .findJavadoc(e.getURL()).getRoots()));
351: }
352: return result.toArray(new URL[result.size()]);
353: }
354:
355: }
356:
357: }
|