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.platform;
043:
044: import java.awt.Color;
045: import java.awt.Component;
046: import java.io.File;
047: import java.io.IOException;
048: import java.net.URI;
049: import java.net.URL;
050: import java.text.Collator;
051: import java.util.Arrays;
052: import java.util.Comparator;
053: import java.util.Set;
054: import java.util.TreeSet;
055: import javax.swing.AbstractListModel;
056: import javax.swing.ComboBoxModel;
057: import javax.swing.DefaultListCellRenderer;
058: import javax.swing.JComboBox;
059: import javax.swing.JLabel;
060: import javax.swing.JList;
061: import javax.swing.ListCellRenderer;
062: import javax.swing.ListSelectionModel;
063: import javax.swing.MutableComboBoxModel;
064: import javax.swing.UIManager;
065: import javax.swing.plaf.UIResource;
066: import org.netbeans.api.project.Project;
067: import org.netbeans.api.project.ui.OpenProjects;
068: import org.netbeans.modules.apisupport.project.ui.customizer.SuiteUtils;
069: import org.netbeans.modules.apisupport.project.universe.NbPlatform;
070: import org.netbeans.modules.apisupport.project.universe.ModuleEntry;
071: import org.openide.ErrorManager;
072: import org.openide.filesystems.FileUtil;
073:
074: /**
075: * Factory for creating miscellaneous UI components, their models and renderers
076: * as they are needed through the code of this module.
077: *
078: * @author Martin Krauskopf
079: */
080: public final class PlatformComponentFactory {
081:
082: private static final Color INVALID_PLAF_COLOR = UIManager
083: .getColor("nb.errorForeground"); // NOI18N
084:
085: /** Set of suites added by the user in <em>this</em> IDE session. */
086: private static Set<String> userSuites = new TreeSet<String>(
087: Collator.getInstance());
088:
089: private PlatformComponentFactory() {
090: // don't allow instances
091: }
092:
093: /**
094: * Returns <code>JComboBox</code> initialized with {@link
095: * NbPlatformListModel} which contains all NetBeans platform.
096: */
097: public static JComboBox getNbPlatformsComboxBox() {
098: JComboBox plafComboBox = new JComboBox(
099: new NbPlatformListModel());
100: plafComboBox.setRenderer(new NbPlatformListRenderer());
101: return plafComboBox;
102: }
103:
104: /**
105: * Returns <code>JList</code> initialized with {@link NbPlatformListModel}
106: * which contains all NetBeans platform.
107: */
108: public static JList getNbPlatformsList() {
109: JList plafList = new JList(new NbPlatformListModel());
110: plafList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
111: plafList.setCellRenderer(new NbPlatformListRenderer());
112: return plafList;
113: }
114:
115: /**
116: * Returns <code>JComboBox</code> containing all suites. Also see
117: * {@link #addUserSuite}.
118: */
119: public static JComboBox getSuitesComboBox() {
120: MutableComboBoxModel model = new SuiteListModel(userSuites);
121: Project[] projects = OpenProjects.getDefault()
122: .getOpenProjects();
123: for (int i = 0; i < projects.length; i++) {
124: String suiteDir = SuiteUtils
125: .getSuiteDirectoryPath(projects[i]);
126: if (suiteDir != null) {
127: model.addElement(suiteDir);
128: }
129: }
130: JComboBox suiteCombo = new JComboBox(model);
131: if (model.getSize() > 0) {
132: suiteCombo.setSelectedIndex(0);
133: }
134: return suiteCombo;
135: }
136:
137: /**
138: * Adds <code>suiteDir</code> to the list of suites returned by the
139: * {@link #getSuitesComboBox} method. Such a suites are remembered
140: * <b>only</b> for the current IDE session.
141: */
142: public static void addUserSuite(String suiteDir) {
143: userSuites.add(suiteDir);
144: }
145:
146: public static ListCellRenderer getURLListRenderer() {
147: return new URLListRenderer();
148: }
149:
150: /**
151: * Render {@link NbPlatform} using its computed display name. If computation
152: * fails platform ID is used as a fallback. For <code>null</code> values
153: * renders an empty string.
154: * <p>Use in conjuction with {@link NbPlatformListModel}</p>
155: */
156: private static class NbPlatformListRenderer extends JLabel
157: implements ListCellRenderer, UIResource {
158:
159: public NbPlatformListRenderer() {
160: setOpaque(true);
161: }
162:
163: public Component getListCellRendererComponent(JList list,
164: Object value, int index, boolean isSelected,
165: boolean cellHasFocus) {
166: // #93658: GTK needs name to render cell renderer "natively"
167: setName("ComboBox.listRenderer"); // NOI18N
168:
169: NbPlatform plaf = ((NbPlatform) value);
170: // NetBeans.org modules doesn't have platform at all --> null
171: String text = plaf == null ? "" : plaf.getLabel(); // NOI18N
172: setText(text);
173:
174: if (isSelected) {
175: setBackground(list.getSelectionBackground());
176: setForeground(list.getSelectionForeground());
177: } else {
178: setBackground(list.getBackground());
179: setForeground(list.getForeground());
180: }
181:
182: if (plaf != null && !plaf.isValid()) {
183: setForeground(INVALID_PLAF_COLOR);
184: }
185:
186: return this ;
187: }
188:
189: // #93658: GTK needs name to render cell renderer "natively"
190: public @Override
191: String getName() {
192: String name = super .getName();
193: return name == null ? "ComboBox.renderer" : name; // NOI18N
194: }
195:
196: }
197:
198: /**
199: * Returns model containing all <em>currently</em> registered NbPlatforms.
200: * See also {@link NbPlatform#getPlatforms}.
201: * <p>Use in conjuction with {@link NbPlatformListRenderer}</p>
202: */
203: public static class NbPlatformListModel extends AbstractListModel
204: implements ComboBoxModel {
205:
206: private static NbPlatform[] getSortedPlatforms(NbPlatform extra) {
207: Set<NbPlatform> _platforms = NbPlatform.getPlatforms();
208: if (extra != null) {
209: _platforms.add(extra);
210: }
211: NbPlatform[] platforms = _platforms
212: .toArray(new NbPlatform[_platforms.size()]);
213: Arrays.sort(platforms, new Comparator<NbPlatform>() {
214: public int compare(NbPlatform p1, NbPlatform p2) {
215: int res = Collator.getInstance().compare(
216: p1.getLabel(), p2.getLabel());
217: if (res != 0) {
218: return res;
219: } else {
220: return System.identityHashCode(p1)
221: - System.identityHashCode(p2);
222: }
223: }
224: });
225: return platforms;
226: }
227:
228: private NbPlatform[] nbPlafs;
229: private Object selectedPlaf;
230:
231: public NbPlatformListModel() {
232: nbPlafs = getSortedPlatforms(null);
233: if (nbPlafs.length > 0) {
234: selectedPlaf = nbPlafs[0];
235: }
236: }
237:
238: public NbPlatformListModel(NbPlatform initiallySelected) {
239: nbPlafs = getSortedPlatforms(initiallySelected);
240: selectedPlaf = initiallySelected;
241: }
242:
243: public int getSize() {
244: return nbPlafs.length;
245: }
246:
247: public Object getElementAt(int index) {
248: return index < nbPlafs.length ? nbPlafs[index] : null;
249: }
250:
251: public void setSelectedItem(Object plaf) {
252: assert plaf == null || plaf instanceof NbPlatform;
253: if (selectedPlaf != plaf) {
254: selectedPlaf = plaf;
255: fireContentsChanged(this , -1, -1);
256: }
257: }
258:
259: public Object getSelectedItem() {
260: return selectedPlaf;
261: }
262:
263: void removePlatform(NbPlatform plaf) {
264: try {
265: NbPlatform.removePlatform(plaf);
266: nbPlafs = getSortedPlatforms(null); // refresh
267: fireContentsChanged(this , 0, nbPlafs.length - 1);
268: } catch (IOException e) {
269: // tell the user that something goes wrong
270: ErrorManager.getDefault().notify(ErrorManager.USER, e);
271: }
272: }
273:
274: NbPlatform addPlatform(String id, String destdir, String label) {
275: try {
276: NbPlatform def = NbPlatform.getDefaultPlatform();
277: NbPlatform plaf = def != null ? NbPlatform.addPlatform(
278: id, new File(destdir), /* #71629 */def
279: .getHarnessLocation(), label) :
280: // Installation somehow corrupted, but try to behave gracefully:
281: NbPlatform.addPlatform(id, new File(destdir),
282: label);
283: nbPlafs = getSortedPlatforms(null); // refresh
284: fireContentsChanged(this , 0, nbPlafs.length - 1);
285: return plaf;
286: } catch (IOException e) {
287: // tell the user that something goes wrong
288: ErrorManager.getDefault().notify(ErrorManager.USER, e);
289: }
290: return null;
291: }
292: }
293:
294: static class ModuleEntryListModel extends AbstractListModel {
295:
296: private ModuleEntry[] mes;
297:
298: ModuleEntryListModel(ModuleEntry[] mes) {
299: this .mes = mes;
300: }
301:
302: public int getSize() {
303: return mes.length;
304: }
305:
306: public Object getElementAt(int index) {
307: return mes[index].getLocalizedName();
308: }
309: }
310:
311: private static class SuiteListModel extends AbstractListModel
312: implements MutableComboBoxModel {
313:
314: private Set<String> suites = new TreeSet<String>(Collator
315: .getInstance());
316: private String selectedSuite;
317:
318: SuiteListModel(Set<String> suites) {
319: this .suites.addAll(suites);
320: }
321:
322: public void setSelectedItem(Object suite) {
323: if (suite == null) {
324: return;
325: }
326: if (selectedSuite != suite) {
327: selectedSuite = (String) suite;
328: fireContentsChanged(this , -1, -1);
329: }
330: }
331:
332: public Object getSelectedItem() {
333: return selectedSuite;
334: }
335:
336: public int getSize() {
337: return suites.size();
338: }
339:
340: public Object getElementAt(int index) {
341: return suites.toArray()[index];
342: }
343:
344: public void addElement(Object obj) {
345: suites.add((String) obj);
346: fireIntervalAdded(this , 0, suites.size());
347: }
348:
349: /** Shouldn't be needed in the meantime. */
350: public void insertElementAt(Object obj, int index) {
351: assert false : "Who needs to insertElementAt?"; // NOI18N
352: }
353:
354: /** Shouldn't be needed in the meantime. */
355: public void removeElement(Object obj) {
356: assert false : "Who needs to removeElement?"; // NOI18N
357: }
358:
359: /** Shouldn't be needed in the meantime. */
360: public void removeElementAt(int index) {
361: assert false : "Who needs to call removeElementAt?"; // NOI18N
362: }
363: }
364:
365: /**
366: * <code>ListModel</code> capable to manage NetBeans platform source roots.
367: * <p>Can be used in conjuction with {@link URLListRenderer}</p>
368: */
369: static final class NbPlatformSourceRootsModel extends
370: AbstractListModel {
371:
372: private NbPlatform plaf;
373: private URL[] srcRoots;
374:
375: NbPlatformSourceRootsModel(NbPlatform plaf) {
376: this .plaf = plaf;
377: this .srcRoots = plaf.getSourceRoots();
378: }
379:
380: public Object getElementAt(int index) {
381: return srcRoots[index];
382: }
383:
384: public int getSize() {
385: return srcRoots.length;
386: }
387:
388: void removeSourceRoot(URL[] srcRootToRemove) {
389: try {
390: plaf.removeSourceRoots(srcRootToRemove);
391: this .srcRoots = plaf.getSourceRoots(); // refresh
392: fireContentsChanged(this , 0, srcRootToRemove.length);
393: } catch (IOException e) {
394: // tell the user that something goes wrong
395: ErrorManager.getDefault().notify(ErrorManager.USER, e);
396: }
397: }
398:
399: void addSourceRoot(URL srcRootToAdd) {
400: try {
401: plaf.addSourceRoot(srcRootToAdd);
402: this .srcRoots = plaf.getSourceRoots(); // refresh
403: fireContentsChanged(this , 0, srcRoots.length);
404: } catch (IOException e) {
405: // tell the user that something goes wrong
406: ErrorManager.getDefault().notify(ErrorManager.USER, e);
407: }
408: }
409:
410: void moveSourceRootsDown(int[] toMoveDown) {
411: try {
412: for (int i = 0; i < toMoveDown.length; i++) {
413: plaf.moveSourceRootDown(toMoveDown[i]);
414: }
415: this .srcRoots = plaf.getSourceRoots(); // refresh
416: fireContentsChanged(this , 0, srcRoots.length);
417: } catch (IOException e) {
418: // tell the user that something goes wrong
419: ErrorManager.getDefault().notify(ErrorManager.USER, e);
420: }
421: }
422:
423: void moveSourceRootsUp(int[] toMoveUp) {
424: try {
425: for (int i = 0; i < toMoveUp.length; i++) {
426: plaf.moveSourceRootUp(toMoveUp[i]);
427: }
428: this .srcRoots = plaf.getSourceRoots(); // refresh
429: fireContentsChanged(this , 0, srcRoots.length);
430: } catch (IOException e) {
431: // tell the user that something goes wrong
432: ErrorManager.getDefault().notify(ErrorManager.USER, e);
433: }
434: }
435: }
436:
437: /**
438: * <code>ListModel</code> capable to manage NetBeans platform javadoc roots.
439: * <p>Can be used in conjuction with {@link URLListRenderer}</p>
440: */
441: static final class NbPlatformJavadocRootsModel extends
442: AbstractListModel {
443:
444: private NbPlatform plaf;
445: private URL[] javadocRoots;
446:
447: NbPlatformJavadocRootsModel(NbPlatform plaf) {
448: this .plaf = plaf;
449: this .javadocRoots = plaf.getJavadocRoots();
450: }
451:
452: public Object getElementAt(int index) {
453: return javadocRoots[index];
454: }
455:
456: public int getSize() {
457: return javadocRoots.length;
458: }
459:
460: void removeJavadocRoots(URL[] jdRootToRemove) {
461: try {
462: plaf.removeJavadocRoots(jdRootToRemove);
463: this .javadocRoots = plaf.getJavadocRoots(); // refresh
464: fireContentsChanged(this , 0, javadocRoots.length);
465: } catch (IOException e) {
466: // tell the user that something goes wrong
467: ErrorManager.getDefault().notify(ErrorManager.USER, e);
468: }
469: }
470:
471: void addJavadocRoot(URL jdRootToAdd) {
472: try {
473: plaf.addJavadocRoot(jdRootToAdd);
474: this .javadocRoots = plaf.getJavadocRoots(); // refresh
475: fireContentsChanged(this , 0, javadocRoots.length);
476: } catch (IOException e) {
477: // tell the user that something goes wrong
478: ErrorManager.getDefault().notify(ErrorManager.USER, e);
479: }
480: }
481:
482: void moveJavadocRootsDown(int[] toMoveDown) {
483: try {
484: for (int i = 0; i < toMoveDown.length; i++) {
485: plaf.moveJavadocRootDown(toMoveDown[i]);
486: }
487: this .javadocRoots = plaf.getJavadocRoots(); // refresh
488: fireContentsChanged(this , 0, javadocRoots.length);
489: } catch (IOException e) {
490: // tell the user that something goes wrong
491: ErrorManager.getDefault().notify(ErrorManager.USER, e);
492: }
493: }
494:
495: void moveJavadocRootsUp(int[] toMoveUp) {
496: try {
497: for (int i = 0; i < toMoveUp.length; i++) {
498: plaf.moveJavadocRootUp(toMoveUp[i]);
499: }
500: this .javadocRoots = plaf.getJavadocRoots(); // refresh
501: fireContentsChanged(this , 0, javadocRoots.length);
502: } catch (IOException e) {
503: // tell the user that something goes wrong
504: ErrorManager.getDefault().notify(ErrorManager.USER, e);
505: }
506: }
507: }
508:
509: /**
510: * Render {@link java.net.URL} using {@link java.net.URL#getFile}.
511: * <p>Use in conjuction with {@link NbPlatformSourceRootsModel} and
512: * {@link NbPlatformJavadocRootsModel}</p>
513: */
514: static final class URLListRenderer extends DefaultListCellRenderer {
515:
516: public @Override
517: Component getListCellRendererComponent(JList list,
518: Object value, int index, boolean isSelected,
519: boolean cellHasFocus) {
520: URL u = (URL) value;
521: String text = u.toExternalForm();
522: if (u.getProtocol().equals("file")) { // NOI18N
523: text = new File(URI.create(u.toExternalForm()))
524: .getAbsolutePath();
525: } else if (u.getProtocol().equals("jar")) { // NOI18N
526: URL baseU = FileUtil.getArchiveFile(u);
527: if (u.equals(FileUtil.getArchiveRoot(baseU))
528: && baseU.getProtocol().equals("file")) { // NOI18N
529: text = new File(URI.create(baseU.toExternalForm()))
530: .getAbsolutePath();
531: }
532: }
533: return super.getListCellRendererComponent(list, text,
534: index, isSelected, cellHasFocus);
535: }
536: }
537:
538: }
|