1 19 20 package org.netbeans.modules.java.j2seproject.ui; 21 22 23 import java.awt.Dialog ; 24 import java.awt.Image ; 25 import java.awt.event.ActionEvent ; 26 import java.beans.BeanInfo ; 27 import java.beans.PropertyChangeEvent ; 28 import java.beans.PropertyChangeListener ; 29 import java.io.IOException ; 30 import java.io.File ; 31 import java.net.MalformedURLException ; 32 import java.net.URI ; 33 import java.net.URL ; 34 import java.text.MessageFormat ; 35 import java.util.ArrayList ; 36 import java.util.Arrays ; 37 import java.util.Collection ; 38 import java.util.Collections ; 39 import java.util.HashSet ; 40 import java.util.Iterator ; 41 import java.util.List ; 42 import java.util.Set ; 43 import javax.swing.AbstractAction ; 44 import javax.swing.Action ; 45 import javax.swing.Icon ; 46 import javax.swing.ImageIcon ; 47 import javax.swing.JButton ; 48 import javax.swing.JFileChooser ; 49 import javax.swing.filechooser.FileFilter ; 50 import org.openide.DialogDescriptor; 51 import org.openide.DialogDisplayer; 52 import org.openide.ErrorManager; 53 import org.openide.filesystems.FileObject; 54 import org.openide.filesystems.FileUtil; 55 import org.openide.filesystems.Repository; 56 import org.openide.filesystems.URLMapper; 57 import org.openide.loaders.DataFolder; 58 import org.openide.nodes.AbstractNode; 59 import org.openide.nodes.Children; 60 import org.openide.nodes.Node; 61 import org.openide.util.NbBundle; 62 import org.openide.util.RequestProcessor; 63 import org.openide.util.Utilities; 64 import org.openide.util.lookup.Lookups; 65 import org.openide.windows.WindowManager; 66 import org.netbeans.api.project.SourceGroup; 67 import org.netbeans.api.project.Project; 68 import org.netbeans.api.project.ant.AntArtifact; 69 import org.netbeans.api.project.libraries.Library; 70 import org.netbeans.api.project.libraries.LibraryManager; 71 import org.netbeans.api.java.classpath.ClassPath; 72 import org.netbeans.api.java.project.JavaProjectConstants; 73 import org.netbeans.spi.project.support.ant.AntProjectHelper; 74 import org.netbeans.spi.project.support.ant.EditableProperties; 75 import org.netbeans.spi.project.support.ant.PropertyEvaluator; 76 import org.netbeans.spi.project.support.ant.PropertyUtils; 77 import org.netbeans.spi.project.support.ant.ReferenceHelper; 78 import org.netbeans.spi.java.project.support.ui.PackageView; 79 import org.netbeans.spi.java.classpath.support.ClassPathSupport; 80 import org.netbeans.modules.java.j2seproject.UpdateHelper; 81 import org.netbeans.modules.java.j2seproject.classpath.J2SEProjectClassPathExtender; 82 import org.netbeans.modules.java.j2seproject.ui.customizer.AntArtifactChooser; 83 import org.netbeans.modules.java.j2seproject.ui.customizer.J2SEProjectProperties; 84 import org.netbeans.modules.java.j2seproject.ui.customizer.LibrariesChooser; 85 86 87 88 89 93 final class LibrariesNode extends AbstractNode { 94 95 private static final Image ICON_BADGE = Utilities.loadImage("org/netbeans/modules/java/j2seproject/ui/resources/libraries-badge.png"); static final RequestProcessor rp = new RequestProcessor (); 97 private static Icon folderIconCache; 98 private static Icon openedFolderIconCache; 99 100 private final String displayName; 101 private final Action [] librariesNodeActions; 102 103 104 119 LibrariesNode (String displayName, Project project, PropertyEvaluator eval, UpdateHelper helper, ReferenceHelper refHelper, 120 String classPathProperty, String [] classPathIgnoreRef, String platformProperty, 121 Action [] librariesNodeActions) { 122 super (new LibrariesChildren (eval, helper, refHelper, classPathProperty, classPathIgnoreRef, platformProperty), Lookups.singleton(project)); 123 this.displayName = displayName; 124 this.librariesNodeActions = librariesNodeActions; 125 } 126 127 public String getDisplayName () { 128 return this.displayName; 129 } 130 131 public String getName () { 132 return this.getDisplayName(); 133 } 134 135 public Image getIcon( int type ) { 136 return computeIcon( false, type ); 137 } 138 139 public Image getOpenedIcon( int type ) { 140 return computeIcon( true, type ); 141 } 142 143 public Action [] getActions(boolean context) { 144 return this.librariesNodeActions; 145 } 146 147 public boolean canCopy() { 148 return false; 149 } 150 151 public static Action createAddProjectAction (Project p, String classPathId) { 153 return new AddProjectAction (p, classPathId); 154 } 155 156 public static Action createAddLibraryAction (Project p, String classPathId) { 157 return new AddLibraryAction (p, classPathId); 158 } 159 160 public static Action createAddFolderAction (Project p, String classPathId) { 161 return new AddFolderAction (p, classPathId); 162 } 163 164 169 static synchronized Icon getFolderIcon (boolean opened) { 170 if (openedFolderIconCache == null) { 171 Node n = DataFolder.findFolder(Repository.getDefault().getDefaultFileSystem().getRoot()).getNodeDelegate(); 172 openedFolderIconCache = new ImageIcon (n.getOpenedIcon(BeanInfo.ICON_COLOR_16x16)); 173 folderIconCache = new ImageIcon (n.getIcon(BeanInfo.ICON_COLOR_16x16)); 174 } 175 if (opened) { 176 return openedFolderIconCache; 177 } 178 else { 179 return folderIconCache; 180 } 181 } 182 183 private Image computeIcon( boolean opened, int type ) { 184 Icon icon = getFolderIcon(opened); 185 Image image = ((ImageIcon )icon).getImage(); 186 image = Utilities.mergeImages(image, ICON_BADGE, 7, 7 ); 187 return image; 188 } 189 190 private static class LibrariesChildren extends Children.Keys implements PropertyChangeListener { 192 193 194 197 private static final String LIBRARY_PREFIX = "${libs."; 199 202 private static final String ANT_ARTIFACT_PREFIX = "${reference."; 206 private static final String FILE_REF_PREFIX = "${file.reference."; 210 private static final String REF_PREFIX = "${"; 212 private static final String LIBRARIES_ICON = "org/netbeans/modules/java/j2seproject/ui/resources/libraries.gif"; private static final String ARCHIVE_ICON = "org/netbeans/modules/java/j2seproject/ui/resources/jar.gif"; 215 private final PropertyEvaluator eval; 216 private final UpdateHelper helper; 217 private final ReferenceHelper refHelper; 218 private final String classPathProperty; 219 private final String platformProperty; 220 private final Set classPathIgnoreRef; 221 222 private ClassPath fsListener; 226 227 228 LibrariesChildren (PropertyEvaluator eval, UpdateHelper helper, ReferenceHelper refHelper, 229 String classPathProperty, String [] classPathIgnoreRef, String platformProperty) { 230 this.eval = eval; 231 this.helper = helper; 232 this.refHelper = refHelper; 233 this.classPathProperty = classPathProperty; 234 this.classPathIgnoreRef = new HashSet (Arrays.asList(classPathIgnoreRef)); 235 this.platformProperty = platformProperty; 236 } 237 238 public void propertyChange(PropertyChangeEvent evt) { 239 String propName = evt.getPropertyName(); 240 if (classPathProperty.equals(propName) || ClassPath.PROP_ROOTS.equals(propName)) { 241 synchronized (this) { 242 if (fsListener!=null) { 243 fsListener.removePropertyChangeListener (this); 244 } 245 } 246 rp.post (new Runnable () { 247 public void run () { 248 setKeys(getKeys()); 249 } 250 }); 251 } 252 } 253 254 protected void addNotify() { 255 this.eval.addPropertyChangeListener (this); 256 this.setKeys(getKeys ()); 257 } 258 259 protected void removeNotify() { 260 this.eval.removePropertyChangeListener(this); 261 synchronized (this) { 262 if (fsListener!=null) { 263 fsListener.removePropertyChangeListener (this); 264 fsListener = null; 265 } 266 } 267 this.setKeys(Collections.EMPTY_SET); 268 } 269 270 protected Node[] createNodes(Object obj) { 271 Node[] result = null; 272 if (obj instanceof Key) { 273 Key key = (Key) obj; 274 switch (key.getType()) { 275 case Key.TYPE_PLATFORM: 276 result = new Node[] {PlatformNode.create(eval, platformProperty)}; 277 break; 278 case Key.TYPE_PROJECT: 279 result = new Node[] {new ProjectNode(key.getProject(), key.getArtifactLocation(), helper, refHelper, key.getClassPathId(), 280 key.getEntryId())}; 281 break; 282 case Key.TYPE_LIBRARY: 283 result = new Node[] {ActionFilterNode.create(PackageView.createPackageView(key.getSourceGroup()), 284 helper, key.getClassPathId(), key.getEntryId())}; 285 break; 286 } 287 } 288 if (result == null) { 289 assert false : "Unknown key type"; result = new Node[0]; 291 } 292 return result; 293 } 294 295 private List getKeys () { 296 EditableProperties projectSharedProps = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); 297 EditableProperties projectPrivateProps = helper.getProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH); 298 EditableProperties privateProps = PropertyUtils.getGlobalProperties(); 299 List rootsList = new ArrayList (); 300 List result = getKeys (projectSharedProps, projectPrivateProps, privateProps, classPathProperty, rootsList); 301 FileObject projectDir = helper.getAntProjectHelper().getProjectDirectory(); 303 if (platformProperty!=null && projectDir !=null && projectDir.isValid() && !projectDir.isVirtual()) { 304 result.add (new Key()); 305 } 306 ClassPath cp = ClassPathSupport.createClassPath ((URL [])rootsList.toArray(new URL [rootsList.size()])); 309 cp.addPropertyChangeListener (this); 310 cp.getRoots(); 311 synchronized (this) { 312 fsListener = cp; 313 } 314 return result; 315 } 316 317 private List getKeys (EditableProperties projectSharedProps, EditableProperties projectPrivateProps, 318 EditableProperties privateProps, String currentClassPath, List rootsList) { 319 List result = new ArrayList (); 320 String raw = projectSharedProps.getProperty (currentClassPath); 321 if (raw == null) { 322 raw = projectPrivateProps.getProperty(currentClassPath); 323 } 324 if (raw == null) { 325 raw = privateProps.getProperty(currentClassPath); 326 } 327 if (raw == null) { 328 return result; 329 } 330 List pe = new ArrayList (Arrays.asList(PropertyUtils.tokenizePath( raw ))); 331 while (pe.size()>0){ 332 String prop = (String ) pe.remove(0); 333 String propName = org.netbeans.modules.java.j2seproject.classpath.ClassPathSupport.getAntPropertyName (prop); 334 if (classPathIgnoreRef.contains(propName)) { 335 continue; 336 } 337 else if (prop.startsWith( LIBRARY_PREFIX )) { 338 String eval = prop.substring( LIBRARY_PREFIX.length(), prop.lastIndexOf('.') ); Library lib = LibraryManager.getDefault().getLibrary (eval); 341 if (lib != null) { 342 List roots = lib.getContent("classpath"); Icon libIcon = new ImageIcon (Utilities.loadImage(LIBRARIES_ICON)); 344 for (Iterator it = roots.iterator(); it.hasNext();) { 345 URL rootUrl = (URL ) it.next(); 346 rootsList.add (rootUrl); 347 FileObject root = URLMapper.findFileObject (rootUrl); 348 if (root != null) { 349 String displayName; 350 if ("jar".equals(rootUrl.getProtocol())) { FileObject file = FileUtil.getArchiveFile (root); 352 displayName = file.getNameExt(); 353 } 354 else { 355 File file = FileUtil.toFile (root); 356 if (file != null) { 357 displayName = file.getAbsolutePath(); 358 } 359 else { 360 displayName = root.getNameExt(); 361 } 362 } 363 displayName = MessageFormat.format ( 364 NbBundle.getMessage (LibrariesNode.class,"TXT_LibraryPartFormat"), 365 new Object [] {lib.getDisplayName(), displayName}); 366 SourceGroup sg = new LibrariesSourceGroup (root, displayName, libIcon, libIcon); 367 result.add (new Key(sg,currentClassPath, propName)); 368 } 369 } 370 } 371 } 373 else if (prop.startsWith(ANT_ARTIFACT_PREFIX)) { 374 Object ret[] = refHelper.findArtifactAndLocation(prop); 376 if ( ret[0] != null && ret[1] != null) { 377 AntArtifact artifact = (AntArtifact)ret[0]; 378 URI uri = (URI ) ret[1]; 379 result.add (new Key(artifact, uri, currentClassPath, propName)); 380 } 381 } 382 else if (prop.startsWith(FILE_REF_PREFIX)) { 383 String evaluatedRef = eval.getProperty(propName); 385 if (evaluatedRef != null) { 386 File file = helper.getAntProjectHelper().resolveFile(evaluatedRef); 387 SourceGroup sg = createFileSourceGroup(file,rootsList); 388 if (sg !=null) { 389 result.add (new Key(sg,currentClassPath, propName)); 390 } 391 } 392 } 393 else if (prop.startsWith(REF_PREFIX)) { 394 result.addAll(getKeys(projectSharedProps, projectPrivateProps, privateProps,propName, rootsList)); 396 } 397 else { 398 File file = helper.getAntProjectHelper().resolveFile(prop); 400 SourceGroup sg = createFileSourceGroup(file,rootsList); 401 if (sg !=null) { 402 result.add ( new Key(sg,currentClassPath, propName)); 403 } 404 } 405 } 406 return result; 407 } 408 409 private static SourceGroup createFileSourceGroup (File file, List rootsList) { 410 Icon icon; 411 Icon openedIcon; 412 String displayName; 413 try { 414 URL url = file.toURI().toURL(); 415 if (FileUtil.isArchiveFile(url)) { 416 url = FileUtil.getArchiveRoot(url); 417 icon = openedIcon = new ImageIcon (Utilities.loadImage(ARCHIVE_ICON)); 418 displayName = file.getName(); 419 } 420 else { 421 String sURL = url.toExternalForm(); 422 if (!sURL.endsWith("/")) { url = new URL (sURL+"/"); } 425 icon = getFolderIcon (false); 426 openedIcon = getFolderIcon (true); 427 displayName = file.getAbsolutePath(); 428 } 429 rootsList.add (url); 430 FileObject root = URLMapper.findFileObject (url); 431 if (root != null) { 432 return new LibrariesSourceGroup (root,displayName,icon,openedIcon); 433 } 434 } catch (MalformedURLException e) { 435 ErrorManager.getDefault().notify(e); 436 } 437 return null; 438 } 439 } 440 441 private static class Key { 442 static final int TYPE_PLATFORM = 0; 443 static final int TYPE_LIBRARY = 1; 444 static final int TYPE_PROJECT = 2; 445 446 private int type; 447 private String classPathId; 448 private String entryId; 449 private SourceGroup sg; 450 private AntArtifact antArtifact; 451 private URI uri; 452 453 Key () { 454 this.type = TYPE_PLATFORM; 455 } 456 457 Key (SourceGroup sg, String classPathId, String entryId) { 458 this.type = TYPE_LIBRARY; 459 this.sg = sg; 460 this.classPathId = classPathId; 461 this.entryId = entryId; 462 } 463 464 Key (AntArtifact a, URI uri, String classPathId, String entryId) { 465 this.type = TYPE_PROJECT; 466 this.antArtifact = a; 467 this.uri = uri; 468 this.classPathId = classPathId; 469 this.entryId = entryId; 470 } 471 472 public int getType () { 473 return this.type; 474 } 475 476 public String getClassPathId () { 477 return this.classPathId; 478 } 479 480 public String getEntryId () { 481 return this.entryId; 482 } 483 484 public SourceGroup getSourceGroup () { 485 return this.sg; 486 } 487 488 public AntArtifact getProject () { 489 return this.antArtifact; 490 } 491 492 public URI getArtifactLocation () { 493 return this.uri; 494 } 495 496 public int hashCode() { 497 int hashCode = this.type<<16; 498 switch (this.type) { 499 case TYPE_LIBRARY: 500 hashCode ^= this.sg == null ? 0 : this.sg.hashCode(); 501 break; 502 case TYPE_PROJECT: 503 hashCode ^= this.antArtifact == null ? 0 : this.antArtifact.hashCode(); 504 break; 505 } 506 return hashCode; 507 } 508 509 public boolean equals(Object obj) { 510 if (!(obj instanceof Key)) { 511 return false; 512 } 513 Key other = (Key) obj; 514 if (other.type != type) { 515 return false; 516 } 517 switch (type) { 518 case TYPE_LIBRARY: 519 return (this.sg == null ? other.sg == null : this.sg.equals(other.sg)) && 520 (this.classPathId == null ? other.classPathId == null : this.classPathId.equals (other.classPathId)) && 521 (this.entryId == null ? other.entryId == null : this.entryId.equals (other.entryId)); 522 case TYPE_PROJECT: 523 return (this.antArtifact == null ? other.antArtifact == null : this.antArtifact.equals(other.antArtifact)) && 524 (this.classPathId == null ? other.classPathId == null : this.classPathId.equals (other.classPathId)) && 525 (this.entryId == null ? other.entryId == null : this.entryId.equals (other.entryId)); 526 case TYPE_PLATFORM: 527 return true; 528 default: 529 throw new IllegalStateException (); 530 } 531 } 532 } 533 534 private static class AddProjectAction extends AbstractAction { 535 536 private final Project project; 537 private final String classPathId; 538 539 public AddProjectAction (Project project, String classPathId) { 540 super( NbBundle.getMessage( LibrariesNode.class, "LBL_AddProject_Action" ) ); 541 this.project = project; 542 this.classPathId = classPathId; 543 } 544 545 public void actionPerformed(ActionEvent e) { 546 AntArtifactChooser.ArtifactItem ai[] = AntArtifactChooser.showDialog( 547 new String [] {JavaProjectConstants.ARTIFACT_TYPE_JAR, JavaProjectConstants.ARTIFACT_TYPE_FOLDER}, 548 project, null); 549 if ( ai != null ) { 550 addArtifacts( ai ); 551 } 552 } 553 554 private void addArtifacts (AntArtifactChooser.ArtifactItem[] artifactItems) { 555 J2SEProjectClassPathExtender cpExtender = (J2SEProjectClassPathExtender) project.getLookup().lookup(J2SEProjectClassPathExtender.class); 556 if (cpExtender != null) { 557 for (int i=0; i<artifactItems.length;i++) { 558 try { 559 cpExtender.addAntArtifact(classPathId, artifactItems[i].getArtifact(), artifactItems[i].getArtifactURI()); 560 } catch (IOException ioe) { 561 ErrorManager.getDefault().notify(ioe); 562 } 563 } 564 } 565 else { 566 ErrorManager.getDefault().log ("J2SEProjectClassPathExtender not found in the project lookup of project: "+project.getProjectDirectory().getPath()); } 568 } 569 } 570 571 private static class AddLibraryAction extends AbstractAction { 572 573 private final Project project; 574 private final String classPathId; 575 576 public AddLibraryAction (Project project, String classPathId) { 577 super( NbBundle.getMessage( LibrariesNode.class, "LBL_AddLibrary_Action" ) ); 578 this.project = project; 579 this.classPathId = classPathId; 580 } 581 582 public void actionPerformed(ActionEvent e) { 583 Object [] options = new Object [] { 584 new JButton (NbBundle.getMessage (LibrariesNode.class,"LBL_AddLibrary")), 585 DialogDescriptor.CANCEL_OPTION 586 }; 587 ((JButton )options[0]).setEnabled(false); 588 ((JButton )options[0]).getAccessibleContext().setAccessibleDescription (NbBundle.getMessage (LibrariesNode.class,"AD_AddLibrary")); 589 LibrariesChooser panel = new LibrariesChooser ((JButton )options[0], Collections.EMPTY_SET); 590 DialogDescriptor desc = new DialogDescriptor(panel,NbBundle.getMessage( LibrariesNode.class, "LBL_CustomizeCompile_Classpath_AddLibrary" ), 591 true, options, options[0], DialogDescriptor.DEFAULT_ALIGN,null,null); 592 Dialog dlg = DialogDisplayer.getDefault().createDialog(desc); 593 dlg.setVisible(true); 594 if (desc.getValue() == options[0]) { 595 addLibraries (panel.getSelectedLibraries()); 596 } 597 dlg.dispose(); 598 } 599 600 private void addLibraries (Library[] libraries) { 601 J2SEProjectClassPathExtender cpExtender = (J2SEProjectClassPathExtender) project.getLookup().lookup(J2SEProjectClassPathExtender.class); 602 if (cpExtender != null) { 603 for (int i=0; i<libraries.length;i++) { 604 try { 605 cpExtender.addLibrary(classPathId, libraries[i]); 606 } catch (IOException ioe) { 607 ErrorManager.getDefault().notify(ioe); 608 } 609 } 610 } 611 else { 612 ErrorManager.getDefault().log ("J2SEProjectClassPathExtender not found in the project lookup of project: "+project.getProjectDirectory().getPath()); } 614 } 615 616 } 617 618 private static class AddFolderAction extends AbstractAction { 619 620 private final Project project; 621 private final String classPathId; 622 623 public AddFolderAction (Project project, String classPathId) { 624 super( NbBundle.getMessage( LibrariesNode.class, "LBL_AddFolder_Action" ) ); 625 this.project = project; 626 this.classPathId = classPathId; 627 } 628 629 public void actionPerformed(ActionEvent e) { 630 JFileChooser chooser = new JFileChooser (); 631 FileUtil.preventFileChooserSymlinkTraversal(chooser, null); 632 chooser.setFileSelectionMode( JFileChooser.FILES_AND_DIRECTORIES ); 633 chooser.setMultiSelectionEnabled( true ); 634 chooser.setDialogTitle( NbBundle.getMessage( LibrariesNode.class, "LBL_AddJar_DialogTitle" ) ); FileFilter fileFilter = new SimpleFileFilter ( 636 NbBundle.getMessage( LibrariesNode.class, "LBL_ZipJarFolderFilter" ), new String [] {"ZIP","JAR"} ); chooser.setAcceptAllFileFilterUsed( false ); 640 chooser.setFileFilter(fileFilter); 641 File curDir = FoldersListSettings.getDefault().getLastUsedClassPathFolder(); 642 chooser.setCurrentDirectory (curDir); 643 int option = chooser.showOpenDialog( WindowManager.getDefault().getMainWindow() ); 644 if ( option == JFileChooser.APPROVE_OPTION ) { 645 File files[] = chooser.getSelectedFiles(); 646 addJarFiles( files, fileFilter ); 647 curDir = FileUtil.normalizeFile(chooser.getCurrentDirectory()); 648 FoldersListSettings.getDefault().setLastUsedClassPathFolder(curDir); 649 } 650 } 651 652 private void addJarFiles (File [] files, FileFilter fileFilter) { 653 J2SEProjectClassPathExtender cpExtender = (J2SEProjectClassPathExtender) project.getLookup().lookup(J2SEProjectClassPathExtender.class); 654 if (cpExtender != null) { 655 for (int i=0; i<files.length;i++) { 656 try { 657 if (fileFilter.accept(files[i])) { 660 FileObject fo = FileUtil.toFileObject (files[i]); 661 assert fo != null : files[i]; 662 cpExtender.addArchiveFile(classPathId, fo); 663 } 664 } catch (IOException ioe) { 665 ErrorManager.getDefault().notify(ioe); 666 } 667 } 668 } 669 else { 670 ErrorManager.getDefault().log ("J2SEProjectClassPathExtender not found in the project lookup of project: "+project.getProjectDirectory().getPath()); } 672 } 673 674 } 675 676 private static class SimpleFileFilter extends FileFilter { 677 678 private String description; 679 private Collection extensions; 680 681 682 public SimpleFileFilter (String description, String [] extensions) { 683 this.description = description; 684 this.extensions = Arrays.asList(extensions); 685 } 686 687 public boolean accept(File f) { 688 if (f.isDirectory()) 689 return true; 690 try { 691 return FileUtil.isArchiveFile(f.toURI().toURL()); 692 } catch (MalformedURLException mue) { 693 ErrorManager.getDefault().notify(mue); 694 return false; 695 } 696 } 697 698 public String getDescription() { 699 return this.description; 700 } 701 } 702 } 703 | Popular Tags |