2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
41
package org.netbeans.modules.java.j2seplatform.platformdefinition;
45
import java.awt.event.ActionListener;
46
import java.awt.event.ActionEvent;
48
import java.util.Collection;
49
import java.util.ArrayList;
50
import java.util.Arrays;
51
import java.util.Iterator;
54
import java.net.MalformedURLException;
56
import javax.swing.filechooser.FileFilter;
57
import javax.swing.event.ListSelectionListener;
58
import javax.swing.event.ListSelectionEvent;
59
import org.openide.NotifyDescriptor;
60
import org.openide.ErrorManager;
61
import org.openide.filesystems.FileUtil;
62
import org.openide.util.NbBundle;
63
import org.netbeans.api.java.classpath.ClassPath;
64
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
68
public class J2SEPlatformCustomizer extends JTabbedPane {
70
private static final int CLASSPATH = 0;
71
private static final int SOURCES = 1;
72
private static final int JAVADOC = 2;
74
private J2SEPlatformImpl platform;
76
public J2SEPlatformCustomizer (J2SEPlatformImpl platform) {
77
this.platform = platform;
78
this.initComponents ();
82
private void initComponents () {
83
this.getAccessibleContext().setAccessibleName (NbBundle.getMessage(J2SEPlatformCustomizer.class,"AN_J2SEPlatformCustomizer"));
84
this.getAccessibleContext().setAccessibleDescription (NbBundle.getMessage(J2SEPlatformCustomizer.class,"AD_J2SEPlatformCustomizer"));
85
this.addTab(NbBundle.getMessage(J2SEPlatformCustomizer.class,"TXT_Classes"), createPathTab(CLASSPATH));
86
this.addTab(NbBundle.getMessage(J2SEPlatformCustomizer.class,"TXT_Sources"), createPathTab(SOURCES));
87
this.addTab(NbBundle.getMessage(J2SEPlatformCustomizer.class,"TXT_Javadoc"), createPathTab(JAVADOC));
91
private JComponent createPathTab (int type) {
92
return new PathView (this.platform, type);
96
private static class PathView extends JPanel {
98
private JList resources;
99
private JButton addButton;
100
// private JButton addURLButton;
101
private JButton removeButton;
102
private JButton moveUpButton;
103
private JButton moveDownButton;
105
private File currentDir;
107
public PathView (J2SEPlatformImpl platform, int type) {
109
this.initComponents (platform);
112
private void initComponents (J2SEPlatformImpl platform) {
113
this.setLayout(new GridBagLayout());
114
JLabel label = new JLabel ();
116
String mneKey = null;
120
key = "TXT_JDKClasspath"; //NOI18N
121
mneKey = "MNE_JDKClasspath"; //NOI18N
122
ad = "AD_JDKClasspath"; //NOI18N
125
key = "TXT_JDKSources"; //NOI18N
126
mneKey = "MNE_JDKSources"; //NOI18N
127
ad = "AD_JDKSources"; //NOI18N
130
key = "TXT_JDKJavadoc"; //NOI18N
131
mneKey = "MNE_JDKJavadoc"; //NOI8N
132
ad = "AD_JDKJavadoc"; //NOI8N
135
assert false : "Illegal type of panel"; //NOI18N
138
label.setText (NbBundle.getMessage(J2SEPlatformCustomizer.class,key));
139
label.setDisplayedMnemonic(NbBundle.getMessage(J2SEPlatformCustomizer.class,mneKey).charAt(0));
140
GridBagConstraints c = new GridBagConstraints();
141
c.gridx = GridBagConstraints.RELATIVE;
142
c.gridy = GridBagConstraints.RELATIVE;
143
c.gridwidth = GridBagConstraints.REMAINDER;
144
c.insets = new Insets (6,6,2,6);
145
c.fill = GridBagConstraints.HORIZONTAL;
147
((GridBagLayout)this.getLayout()).setConstraints(label,c);
149
this.resources = new JList(new PathModel(platform,type));
150
label.setLabelFor (this.resources);
151
this.resources.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(J2SEPlatformCustomizer.class,ad));
152
this.resources.addListSelectionListener(new ListSelectionListener() {
153
public void valueChanged(ListSelectionEvent e) {
157
JScrollPane spane = new JScrollPane (this.resources);
158
c = new GridBagConstraints();
159
c.gridx = GridBagConstraints.RELATIVE;
160
c.gridy = GridBagConstraints.RELATIVE;
163
c.insets = new Insets (0,6,6,6);
164
c.fill = GridBagConstraints.BOTH;
167
((GridBagLayout)this.getLayout()).setConstraints(spane,c);
169
if (type == SOURCES || type == JAVADOC) {
170
this.addButton = new JButton ();
173
if (type == SOURCES) {
174
text = NbBundle.getMessage(J2SEPlatformCustomizer.class, "CTL_Add");
175
mne = NbBundle.getMessage(J2SEPlatformCustomizer.class, "MNE_Add").charAt(0);
176
ad = NbBundle.getMessage(J2SEPlatformCustomizer.class, "AD_Add");
179
text = NbBundle.getMessage(J2SEPlatformCustomizer.class, "CTL_AddZip");
180
mne = NbBundle.getMessage(J2SEPlatformCustomizer.class, "MNE_AddZip").charAt(0);
181
ad = NbBundle.getMessage(J2SEPlatformCustomizer.class, "AD_AddZip");
183
this.addButton.setText(text);
184
this.addButton.setMnemonic(mne);
185
this.addButton.getAccessibleContext().setAccessibleDescription (ad);
186
addButton.addActionListener( new ActionListener () {
187
public void actionPerformed(ActionEvent e) {
191
c = new GridBagConstraints();
194
c.gridwidth = GridBagConstraints.REMAINDER;
195
c.fill = GridBagConstraints.HORIZONTAL;
196
c.anchor = GridBagConstraints.NORTHWEST;
197
c.insets = new Insets (0,6,0,6);
198
((GridBagLayout)this.getLayout()).setConstraints(addButton,c);
199
this.add (addButton);
200
// if (this.type == JAVADOC) {
201
// addURLButton = new JButton (NbBundle.getMessage(J2SEPlatformCustomizer.class, "CTL_AddURL"));
202
// addURLButton.setMnemonic(NbBundle.getMessage(J2SEPlatformCustomizer.class, "MNE_AddURL").charAt(0));
203
// addURLButton.addActionListener(new ActionListener () {
204
// public void actionPerformed(ActionEvent e) {
208
// c = new GridBagConstraints();
211
// c.gridwidth = GridBagConstraints.REMAINDER;
212
// c.fill = GridBagConstraints.HORIZONTAL;
213
// c.anchor = GridBagConstraints.NORTHWEST;
214
// c.insets = new Insets (0,6,6,12);
215
// ((GridBagLayout)this.getLayout()).setConstraints(addURLButton,c);
216
// this.add (addURLButton);
218
removeButton = new JButton (NbBundle.getMessage(J2SEPlatformCustomizer.class, "CTL_Remove"));
219
removeButton.setMnemonic(NbBundle.getMessage(J2SEPlatformCustomizer.class, "MNE_Remove").charAt(0));
220
removeButton.getAccessibleContext().setAccessibleDescription (NbBundle.getMessage(J2SEPlatformCustomizer.class,"AD_Remove"));
221
removeButton.addActionListener( new ActionListener () {
222
public void actionPerformed(ActionEvent e) {
223
removePathElement ();
226
removeButton.setEnabled(false);
227
c = new GridBagConstraints();
230
c.gridwidth = GridBagConstraints.REMAINDER;
231
c.fill = GridBagConstraints.HORIZONTAL;
232
c.anchor = GridBagConstraints.NORTHWEST;
233
c.insets = new Insets (12,6,0,6);
234
((GridBagLayout)this.getLayout()).setConstraints(removeButton,c);
235
this.add (removeButton);
236
moveUpButton = new JButton (NbBundle.getMessage(J2SEPlatformCustomizer.class, "CTL_Up"));
237
moveUpButton.setMnemonic(NbBundle.getMessage(J2SEPlatformCustomizer.class, "MNE_Up").charAt(0));
238
moveUpButton.getAccessibleContext().setAccessibleDescription (NbBundle.getMessage(J2SEPlatformCustomizer.class,"AD_Up"));
239
moveUpButton.addActionListener( new ActionListener () {
240
public void actionPerformed(ActionEvent e) {
241
moveUpPathElement ();
244
moveUpButton.setEnabled(false);
245
c = new GridBagConstraints();
248
c.gridwidth = GridBagConstraints.REMAINDER;
249
c.fill = GridBagConstraints.HORIZONTAL;
250
c.anchor = GridBagConstraints.NORTHWEST;
251
c.insets = new Insets (12,6,0,6);
252
((GridBagLayout)this.getLayout()).setConstraints(moveUpButton,c);
253
this.add (moveUpButton);
254
moveDownButton = new JButton (NbBundle.getMessage(J2SEPlatformCustomizer.class, "CTL_Down"));
255
moveDownButton.setMnemonic (NbBundle.getMessage(J2SEPlatformCustomizer.class, "MNE_Down").charAt(0));
256
moveDownButton.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(J2SEPlatformCustomizer.class,"AD_Down"));
257
moveDownButton.addActionListener( new ActionListener () {
258
public void actionPerformed(ActionEvent e) {
259
moveDownPathElement ();
262
moveDownButton.setEnabled(false);
263
c = new GridBagConstraints();
266
c.gridwidth = GridBagConstraints.REMAINDER;
267
c.fill = GridBagConstraints.HORIZONTAL;
268
c.anchor = GridBagConstraints.NORTHWEST;
269
c.insets = new Insets (5,6,6,6);
270
((GridBagLayout)this.getLayout()).setConstraints(moveDownButton,c);
271
this.add (moveDownButton);
275
// private void addURLElement() {
276
// JPanel p = new JPanel ();
277
// GridBagLayout lm = new GridBagLayout();
279
// GridBagConstraints c = new GridBagConstraints ();
280
// c.gridx = c.gridy = GridBagConstraints.RELATIVE;
281
// c.insets = new Insets (12,12,12,6);
282
// c.anchor = GridBagConstraints.NORTHWEST;
283
// JLabel label = new JLabel (NbBundle.getMessage(J2SEPlatformCustomizer.class,"CTL_AddJavadocURLMessage"));
284
// label.setDisplayedMnemonic ('U');
285
// lm.setConstraints(label,c);
287
// c = new GridBagConstraints ();
288
// c.gridx = c.gridy = GridBagConstraints.RELATIVE;
289
// c.gridwidth = GridBagConstraints.REMAINDER;
290
// c.insets = new Insets (12,0,12,6);
291
// c.fill = GridBagConstraints.HORIZONTAL;
292
// c.anchor = GridBagConstraints.NORTHWEST;
293
// JTextField text = new JTextField ();
294
// text.setColumns(30);
295
// text.setText (NbBundle.getMessage(J2SEPlatformCustomizer.class,"TXT_DefaultProtocol"));
297
// label.setLabelFor(text);
298
// lm.setConstraints(text,c);
300
// JButton[] options = new JButton[] {
301
// new JButton (NbBundle.getMessage(J2SEPlatformCustomizer.class,"CTL_AddJavadocURLTitle")),
302
// new JButton (NbBundle.getMessage(J2SEPlatformCustomizer.class,"CTL_Cancel"))
304
// options[0].setMnemonic(NbBundle.getMessage(J2SEPlatformCustomizer.class,"MNE_Add").charAt(0));
305
// options[1].setMnemonic(NbBundle.getMessage(J2SEPlatformCustomizer.class,"MNE_Cancel").charAt(0));
306
// DialogDescriptor input = new DialogDescriptor (
308
// NbBundle.getMessage(J2SEPlatformCustomizer.class,"CTL_AddJavadocURLTitle"),
309
// true, options, options[0], DialogDescriptor.DEFAULT_ALIGN, null, null);
310
// if (DialogDisplayer.getDefault().notify(input) == options[0]) {
312
// String value = text.getText();
313
// URL url = new URL (value);
314
// ((PathModel)this.resources.getModel()).addPath(url);
315
// this.resources.setSelectedIndex (this.resources.getModel().getSize()-1);
316
// } catch (MalformedURLException mue) {
317
// DialogDescriptor.Message message = new DialogDescriptor.Message (
318
// NbBundle.getMessage(J2SEPlatformCustomizer.class,"CTL_InvalidURLFormat"),
319
// DialogDescriptor.ERROR_MESSAGE);
320
// DialogDisplayer.getDefault().notify(message);
325
private void addPathElement () {
326
JFileChooser chooser = new JFileChooser ();
327
FileUtil.preventFileChooserSymlinkTraversal(chooser, null);
328
chooser.setMultiSelectionEnabled (true);
330
String message = null;
331
String approveButtonName = null;
332
String approveButtonNameMne = null;
333
if (this.type == SOURCES) {
334
title = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_OpenSources");
335
message = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_Sources");
336
approveButtonName = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_OpenSources");
337
approveButtonNameMne = NbBundle.getMessage (J2SEPlatformCustomizer.class,"MNE_OpenSources");
339
else if (this.type == JAVADOC) {
340
title = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_OpenJavadoc");
341
message = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_Javadoc");
342
approveButtonName = NbBundle.getMessage (J2SEPlatformCustomizer.class,"TXT_OpenJavadoc");
343
approveButtonNameMne = NbBundle.getMessage (J2SEPlatformCustomizer.class,"MNE_OpenJavadoc");
345
chooser.setDialogTitle(title);
346
chooser.setApproveButtonText(approveButtonName);
347
chooser.setApproveButtonMnemonic (approveButtonNameMne.charAt(0));
348
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
349
//#61789 on old macosx (jdk 1.4.1) these two method need to be called in this order.
350
chooser.setAcceptAllFileFilterUsed( false );
351
chooser.setFileFilter (new SimpleFileFilter(message,new String[] {"ZIP","JAR"})); //NOI18N
352
if (this.currentDir != null) {
353
chooser.setCurrentDirectory(this.currentDir);
355
if (chooser.showOpenDialog(this)==JFileChooser.APPROVE_OPTION) {
356
File[] fs = chooser.getSelectedFiles();
357
PathModel model = (PathModel) this.resources.getModel();
358
boolean addingFailed = false;
359
int firstIndex = this.resources.getModel().getSize();
360
for (int i = 0; i < fs.length; i++) {
362
//XXX: JFileChooser workaround (JDK bug #5075580), double click on folder returns wrong file
363
// E.g. for /foo/src it returns /foo/src/src
364
// Try to convert it back by removing last invalid name component
366
File parent = f.getParentFile();
367
if (parent != null && f.getName().equals(parent.getName()) && parent.exists()) {
371
addingFailed|=!model.addPath (f);
374
new NotifyDescriptor.Message (NbBundle.getMessage(J2SEPlatformCustomizer.class,"TXT_CanNotAddResolve"),
375
NotifyDescriptor.ERROR_MESSAGE);
377
int lastIndex = this.resources.getModel().getSize()-1;
378
if (firstIndex<=lastIndex) {
379
int[] toSelect = new int[lastIndex-firstIndex+1];
380
for (int i = 0; i < toSelect.length; i++) {
381
toSelect[i] = firstIndex+i;
383
this.resources.setSelectedIndices(toSelect);
385
this.currentDir = FileUtil.normalizeFile(chooser.getCurrentDirectory());
389
private void removePathElement () {
390
int[] indices = this.resources.getSelectedIndices();
391
if (indices.length == 0) {
394
PathModel model = (PathModel) this.resources.getModel();
395
model.removePath (indices);
396
if ( indices[indices.length-1]-indices.length+1 < this.resources.getModel().getSize()) {
397
this.resources.setSelectedIndex (indices[indices.length-1]-indices.length+1);
399
else if (indices[0]>0) {
400
this.resources.setSelectedIndex (indices[0]-1);
404
private void moveDownPathElement () {
405
int[] indices = this.resources.getSelectedIndices();
406
if (indices.length == 0) {
409
PathModel model = (PathModel) this.resources.getModel();
410
model.moveDownPath (indices);
411
for (int i=0; i< indices.length; i++) {
412
indices[i] = indices[i] + 1;
414
this.resources.setSelectedIndices (indices);
417
private void moveUpPathElement () {
418
int[] indices = this.resources.getSelectedIndices();
419
if (indices.length == 0) {
422
PathModel model = (PathModel) this.resources.getModel();
423
model.moveUpPath (indices);
424
for (int i=0; i< indices.length; i++) {
425
indices[i] = indices[i] - 1;
427
this.resources.setSelectedIndices (indices);
430
private void selectionChanged () {
431
if (this.type == CLASSPATH) {
434
int indices[] = this.resources.getSelectedIndices();
435
this.removeButton.setEnabled (indices.length > 0);
436
this.moveUpButton.setEnabled (indices.length > 0 && indices[0]>0);
437
this.moveDownButton.setEnabled(indices.length > 0 && indices[indices.length-1]<this.resources.getModel().getSize()-1);
443
private static class PathModel extends AbstractListModel/*<String>*/ {
445
private J2SEPlatformImpl platform;
447
private java.util.List data;
449
public PathModel (J2SEPlatformImpl platform, int type) {
450
this.platform = platform;
454
public int getSize() {
455
return this.getData().size();
458
public Object getElementAt(int index) {
459
java.util.List list = this.getData();
460
URL url = (URL)list.get(index);
461
if ("jar".equals(url.getProtocol())) { //NOI18N
462
URL fileURL = FileUtil.getArchiveFile (url);
463
if (FileUtil.getArchiveRoot(fileURL).equals(url)) {
467
// some subdir, just show it as is
468
return url.toExternalForm();
471
if ("file".equals(url.getProtocol())) {
472
File f = new File (URI.create(url.toExternalForm()));
473
return f.getAbsolutePath();
476
return url.toExternalForm();
480
private void removePath (int[] indices) {
481
java.util.List data = getData();
482
for (int i=indices.length-1; i>=0; i--) {
483
data.remove(indices[i]);
486
fireIntervalRemoved(this,indices[0],indices[indices.length-1]);
489
private void moveUpPath (int[] indices) {
490
java.util.List data = getData ();
491
for (int i=0; i<indices.length; i++) {
492
Object p2 = data.get (indices[i]);
493
Object p1 = data.set (indices[i]-1,p2);
494
data.set (indices[i],p1);
497
fireContentsChanged(this,indices[0]-1,indices[indices.length-1]);
500
private void moveDownPath (int[] indices) {
501
java.util.List data = getData ();
502
for (int i=indices.length-1; i>=0; i--) {
503
Object p1 = data.get (indices[i]);
504
Object p2 = data.set (indices[i]+1,p1);
505
data.set (indices[i],p2);
508
fireContentsChanged(this,indices[0],indices[indices.length-1]+1);
511
private boolean addPath (File f) {
513
URL url = f.toURI().toURL();
514
return this.addPath (url);
515
} catch (MalformedURLException mue) {
520
private boolean addPath (URL url) {
521
if (FileUtil.isArchiveFile(url)) {
522
url = FileUtil.getArchiveRoot (url);
524
else if (!url.toExternalForm().endsWith("/")){
526
url = new URL (url.toExternalForm()+"/");
527
} catch (MalformedURLException mue) {
528
ErrorManager.getDefault().notify(mue);
531
java.util.List data = getData();
532
int oldSize = data.size ();
535
fireIntervalAdded(this,oldSize,oldSize);
539
private synchronized java.util.List getData () {
540
if (this.data == null) {
543
this.data = getPathList (this.platform.getBootstrapLibraries());
546
this.data = getPathList (this.platform.getSourceFolders());
549
this.data = new ArrayList(this.platform.getJavadocFolders());
556
private static java.util.List getPathList (ClassPath cp) {
557
java.util.List result = new ArrayList ();
558
for (Iterator it = cp.entries().iterator(); it.hasNext();) {
559
ClassPath.Entry entry = (ClassPath.Entry) it.next ();
560
result.add (entry.getURL());
565
private static ClassPath createClassPath (java.util.List/*<URL>*/ roots) {
566
java.util.List resources = new ArrayList ();
567
for (Iterator it = roots.iterator(); it.hasNext();) {
568
URL url = (URL) it.next ();
569
resources.add (ClassPathSupport.createResource(url));
571
return ClassPathSupport.createClassPath(resources);
574
private void updatePlatform () {
577
this.platform.setSourceFolders(createClassPath(data));
580
this.platform.setJavadocFolders (data);
583
assert false : "Trying to update unknown property"; //NOI18N
589
private static class SimpleFileFilter extends FileFilter {
591
private String description;
592
private Collection extensions;
595
public SimpleFileFilter (String description, String[] extensions) {
596
this.description = description;
597
this.extensions = Arrays.asList(extensions);
600
public boolean accept(File f) {
603
String name = f.getName();
604
int index = name.lastIndexOf('.'); //NOI18N
605
if (index <= 0 || index==name.length()-1)
607
String extension = name.substring (index+1).toUpperCase();
608
return this.extensions.contains(extension);
611
public String getDescription() {
612
return this.description;