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.gsfpath.platform.wizard;
043:
044: import java.awt.Container;
045: import java.awt.Dimension;
046: import java.awt.GridBagConstraints;
047: import java.awt.GridBagLayout;
048: import java.awt.Insets;
049: import java.awt.Window;
050: import java.awt.event.ActionEvent;
051: import java.awt.event.KeyEvent;
052: import java.beans.PropertyChangeEvent;
053: import java.beans.PropertyChangeListener;
054: import java.io.File;
055: import javax.swing.AbstractAction;
056: import javax.swing.BorderFactory;
057: import javax.swing.Icon;
058: import javax.swing.ImageIcon;
059: import javax.swing.JFileChooser;
060: import javax.swing.JLabel;
061: import javax.swing.JPanel;
062: import javax.swing.JTextField;
063: import javax.swing.KeyStroke;
064: import javax.swing.event.ChangeListener;
065: import javax.swing.filechooser.FileFilter;
066: import javax.swing.filechooser.FileSystemView;
067: import javax.swing.filechooser.FileView;
068: import org.netbeans.modules.gsfpath.platform.PlatformSettings;
069: import org.netbeans.modules.gsfpath.spi.platform.PlatformInstall;
070: import org.openide.WizardDescriptor;
071: import org.openide.filesystems.FileObject;
072: import org.openide.filesystems.FileStateInvalidException;
073: import org.openide.filesystems.FileUtil;
074: import org.openide.util.ChangeSupport;
075: import org.openide.util.HelpCtx;
076: import org.openide.util.NbBundle;
077: import org.openide.util.Utilities;
078:
079: /**
080: *
081: * @author sd99038, Tomas Zezula
082: */
083: public class LocationChooser extends JFileChooser implements
084: PropertyChangeListener {
085:
086: private static final Dimension PREFERRED_SIZE = new Dimension(600,
087: 340);
088:
089: private WizardDescriptor.InstantiatingIterator<WizardDescriptor> iterator;
090: private LocationChooser.Panel firer;
091: private PlatformFileView platformFileView;
092: private PlatformAccessory accessory;
093:
094: public LocationChooser(LocationChooser.Panel firer) {
095: super ();
096: this .setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
097: this .setName(NbBundle.getMessage(LocationChooser.class,
098: "TXT_PlatformFolderTitle"));
099: this .setFileSelectionMode(DIRECTORIES_ONLY);
100: this .setMultiSelectionEnabled(false);
101: this .setControlButtonsAreShown(false);
102: this .accessory = new PlatformAccessory();
103: this .setFileFilter(new PlatformFileFilter());
104: this .setAccessory(this .accessory);
105: this .firer = firer;
106: this .platformFileView = new PlatformFileView(this
107: .getFileSystemView());
108: this .setFileView(this .platformFileView);
109: this .addPropertyChangeListener(this );
110: this .getAccessibleContext().setAccessibleDescription(
111: NbBundle.getMessage(LocationChooser.class,
112: "AD_LocationChooser"));
113:
114: //XXX JFileChooser workaround
115: getActionMap().put("cancel", new AbstractAction() {
116: public void actionPerformed(ActionEvent e) {
117: Container parent = LocationChooser.this .getParent();
118: do {
119: parent = parent.getParent();
120: } while (parent != null && !(parent instanceof Window));
121: if (parent != null) {
122: ((Window) parent).setVisible(false);
123: }
124: }
125: });
126: getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
127: .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
128: "cancel");
129:
130: }
131:
132: public @Override
133: Dimension getPreferredSize() {
134: return PREFERRED_SIZE;
135: }
136:
137: public void propertyChange(PropertyChangeEvent evt) {
138: if (SELECTED_FILE_CHANGED_PROPERTY
139: .equals(evt.getPropertyName())) {
140: this .iterator = null;
141: this .accessory.setType(""); //NOI18N
142: File file = this .getSelectedFile();
143: if (file != null) {
144: file = FileUtil.normalizeFile(file);
145: FileObject fo = FileUtil.toFileObject(FileUtil
146: .normalizeFile(file));
147: if (fo != null) {
148: PlatformInstall install = this .platformFileView
149: .getPlatformInstall();
150: if (install != null && install.accept(fo)) {
151: this .accessory
152: .setType(install.getDisplayName());
153: this .iterator = install.createIterator(fo);
154: }
155: }
156: }
157: this .firer.cs.fireChange();
158: }
159: }
160:
161: private boolean valid() {
162: return this .getInstaller() != null;
163: }
164:
165: private void read(WizardDescriptor settings) {
166: PlatformSettings ps = PlatformSettings.getDefault();
167: if (ps != null) {
168: this .setCurrentDirectory(ps.getPlatformsFolder());
169: }
170: }
171:
172: private void store(WizardDescriptor settings) {
173: File dir = this .getCurrentDirectory();
174: if (dir != null) {
175: PlatformSettings ps = PlatformSettings.getDefault();
176: if (ps != null) {
177: ps.setPlatformsFolder(dir);
178: }
179: }
180: }
181:
182: private WizardDescriptor.InstantiatingIterator<WizardDescriptor> getInstaller() {
183: return this .iterator;
184: }
185:
186: private void setPlatformInstall(PlatformInstall platformInstall) {
187: this .platformFileView.setPlatformInstall(platformInstall);
188: }
189:
190: private PlatformInstall getPlatformInstall() {
191: return this .platformFileView.getPlatformInstall();
192: }
193:
194: private static class PlatformFileFilter extends FileFilter {
195:
196: public boolean accept(File f) {
197: return f.isDirectory();
198: }
199:
200: public String getDescription() {
201: return NbBundle.getMessage(LocationChooser.class,
202: "TXT_PlatformFolder");
203: }
204: }
205:
206: private static class PlatformAccessory extends JPanel {
207:
208: private JTextField tf;
209:
210: public PlatformAccessory() {
211: this .initComponents();
212: }
213:
214: private void setType(String type) {
215: this .tf.setText(type);
216: }
217:
218: private void initComponents() {
219: this .getAccessibleContext().setAccessibleName(
220: NbBundle.getMessage(LocationChooser.class,
221: "AN_LocationChooserAccessiory"));
222: this .getAccessibleContext().setAccessibleDescription(
223: NbBundle.getMessage(LocationChooser.class,
224: "AD_LocationChooserAccessiory"));
225: GridBagLayout l = new GridBagLayout();
226: this .setLayout(l);
227: JLabel label = new JLabel(NbBundle.getMessage(
228: LocationChooser.class, "TXT_PlatformType"));
229: label.setDisplayedMnemonic(NbBundle.getMessage(
230: LocationChooser.class, "MNE_PlatformType")
231: .charAt(0));
232: GridBagConstraints c = new GridBagConstraints();
233: c.gridx = c.gridy = GridBagConstraints.RELATIVE;
234: c.gridwidth = GridBagConstraints.REMAINDER;
235: c.insets = new Insets(0, 12, 3, 12);
236: c.anchor = GridBagConstraints.NORTHWEST;
237: l.setConstraints(label, c);
238: this .add(label);
239: this .tf = new JTextField();
240: this .tf.setColumns(15);
241: this .tf.setEditable(false);
242: this .tf.getAccessibleContext().setAccessibleDescription(
243: NbBundle.getMessage(LocationChooser.class,
244: "AD_PlatformType"));
245: c = new GridBagConstraints();
246: c.gridx = c.gridy = GridBagConstraints.RELATIVE;
247: c.gridwidth = GridBagConstraints.REMAINDER;
248: c.insets = new Insets(3, 12, 12, 12);
249: c.anchor = GridBagConstraints.NORTHWEST;
250: c.fill = GridBagConstraints.HORIZONTAL;
251: c.weightx = 1.0;
252: l.setConstraints(this .tf, c);
253: this .add(tf);
254: label.setLabelFor(this .tf);
255: JPanel fill = new JPanel();
256: c = new GridBagConstraints();
257: c.gridx = c.gridy = GridBagConstraints.RELATIVE;
258: c.gridwidth = GridBagConstraints.REMAINDER;
259: c.insets = new Insets(0, 12, 12, 12);
260: c.anchor = GridBagConstraints.NORTHWEST;
261: c.fill = GridBagConstraints.BOTH;
262: c.weightx = c.weighty = 1.0;
263: l.setConstraints(fill, c);
264: this .add(fill);
265: }
266: }
267:
268: /**
269: * Controller for the LocationChooser panel.
270: */
271: public static class Panel implements
272: WizardDescriptor.Panel<WizardDescriptor> {
273:
274: LocationChooser component;
275: private final ChangeSupport cs = new ChangeSupport(this );
276:
277: public LocationChooser getComponent() {
278: if (component == null) {
279: this .component = new LocationChooser(this );
280: }
281: return component;
282: }
283:
284: public HelpCtx getHelp() {
285: return new HelpCtx(LocationChooser.class);
286: }
287:
288: public boolean isValid() {
289: return getComponent().valid();
290: }
291:
292: public void readSettings(WizardDescriptor wiz) {
293: getComponent().read(wiz);
294: }
295:
296: public void addChangeListener(ChangeListener l) {
297: cs.addChangeListener(l);
298: }
299:
300: public void removeChangeListener(ChangeListener l) {
301: cs.removeChangeListener(l);
302: }
303:
304: public void storeSettings(WizardDescriptor wiz) {
305: getComponent().store(wiz);
306: }
307:
308: /**
309: * Returns the currently selected installer.
310: */
311: WizardDescriptor.InstantiatingIterator<WizardDescriptor> getInstallerIterator() {
312: return getComponent().getInstaller();
313: }
314:
315: void setPlatformInstall(PlatformInstall platformInstall) {
316: getComponent().setPlatformInstall(platformInstall);
317: }
318:
319: PlatformInstall getPlatformInstall() {
320: return getComponent().getPlatformInstall();
321: }
322:
323: }
324:
325: private static class MergedIcon implements Icon {
326:
327: private Icon icon1;
328: private Icon icon2;
329: private int xMerge;
330: private int yMerge;
331:
332: MergedIcon(Icon icon1, Icon icon2, int xMerge, int yMerge) {
333:
334: this .icon1 = icon1;
335: this .icon2 = icon2;
336:
337: if (xMerge == -1) {
338: xMerge = icon1.getIconWidth() - icon2.getIconWidth();
339: }
340:
341: if (yMerge == -1) {
342: yMerge = icon1.getIconHeight() - icon2.getIconHeight();
343: }
344:
345: this .xMerge = xMerge;
346: this .yMerge = yMerge;
347: }
348:
349: public int getIconHeight() {
350: return Math.max(icon1.getIconHeight(), yMerge
351: + icon2.getIconHeight());
352: }
353:
354: public int getIconWidth() {
355: return Math.max(icon1.getIconWidth(), yMerge
356: + icon2.getIconWidth());
357: }
358:
359: public void paintIcon(java.awt.Component c,
360: java.awt.Graphics g, int x, int y) {
361: icon1.paintIcon(c, g, x, y);
362: icon2.paintIcon(c, g, x + xMerge, y + yMerge);
363: }
364:
365: }
366:
367: private static class PlatformFileView extends FileView {
368:
369: private static final Icon BADGE = new ImageIcon(
370: Utilities
371: .loadImage("org/netbeans/modules/gsfpath/platform/resources/platformBadge.gif")); // NOI18N
372: private static final Icon EMPTY = new ImageIcon(
373: Utilities
374: .loadImage("org/netbeans/modules/gsfpath/platform/resources/empty.gif")); // NOI18N
375:
376: private FileSystemView fsv;
377: private Icon lastOriginal;
378: private Icon lastMerged;
379: private PlatformInstall platformInstall;
380:
381: public PlatformFileView(FileSystemView fsv) {
382: this .fsv = fsv;
383: }
384:
385: public @Override
386: Icon getIcon(File _f) {
387: File f = FileUtil.normalizeFile(_f);
388: Icon original = fsv.getSystemIcon(f);
389: if (original == null) {
390: // L&F (e.g. GTK) did not specify any icon.
391: original = EMPTY;
392: }
393: if (isPlatformDir(f)) {
394: if (original.equals(lastOriginal)) {
395: return lastMerged;
396: }
397: lastOriginal = original;
398: lastMerged = new MergedIcon(original, BADGE, -1, -1);
399: return lastMerged;
400: } else {
401: return original;
402: }
403: }
404:
405: public void setPlatformInstall(PlatformInstall platformInstall) {
406: this .platformInstall = platformInstall;
407: }
408:
409: public PlatformInstall getPlatformInstall() {
410: return this .platformInstall;
411: }
412:
413: private boolean isPlatformDir(File f) {
414: //XXX: Workaround of hard NFS mounts on Solaris.
415: final int osId = Utilities.getOperatingSystem();
416: if (osId == Utilities.OS_SOLARIS
417: || osId == Utilities.OS_SUNOS) {
418: return false;
419: }
420: FileObject fo = (f != null) ? convertToValidDir(f) : null;
421: if (fo != null) {
422: //XXX: Workaround of /net folder on Unix, the folders in the root are not badged as platforms.
423: // User can still select them.
424: try {
425: if (Utilities.isUnix()
426: && (fo.getParent() == null || fo
427: .getFileSystem().getRoot().equals(
428: fo.getParent()))) {
429: return false;
430: }
431: } catch (FileStateInvalidException e) {
432: return false;
433: }
434: if (this .platformInstall.accept(fo)) {
435: return true;
436: }
437: }
438: return false;
439: }
440:
441: private static FileObject convertToValidDir(File f) {
442: FileObject fo;
443: File testFile = new File(f.getPath());
444: if (testFile == null || testFile.getParent() == null) {
445: // BTW this means that roots of file systems can't be project
446: // directories.
447: return null;
448: }
449:
450: /**ATTENTION: on Windows may occure dir.isDirectory () == dir.isFile () == true then
451: * its used testFile instead of dir.
452: */
453: if (!testFile.isDirectory()) {
454: return null;
455: }
456:
457: fo = FileUtil.toFileObject(FileUtil.normalizeFile(f));
458: return fo;
459: }
460: }
461: }
|