1 19 20 package org.netbeans.spi.java.project.support.ui; 21 22 import java.awt.Image ; 23 import java.awt.datatransfer.DataFlavor ; 24 import java.awt.datatransfer.Transferable ; 25 import java.awt.datatransfer.UnsupportedFlavorException ; 26 import java.io.IOException ; 27 import java.util.ArrayList ; 28 import java.util.Arrays ; 29 import java.util.Collections ; 30 import java.util.Iterator ; 31 import java.util.List ; 32 import java.util.Set ; 33 import javax.swing.Action ; 34 import javax.swing.Icon ; 35 import org.netbeans.api.project.SourceGroup; 36 import org.netbeans.spi.project.ui.support.CommonProjectActions; 37 import org.openide.ErrorManager; 38 import org.openide.actions.FileSystemAction; 39 import org.openide.actions.FindAction; 40 import org.openide.actions.PasteAction; 41 import org.openide.actions.ToolsAction; 42 import org.openide.filesystems.FileObject; 43 import org.openide.filesystems.FileStateInvalidException; 44 import org.openide.filesystems.FileStatusEvent; 45 import org.openide.filesystems.FileStatusListener; 46 import org.openide.filesystems.FileSystem; 47 import org.openide.filesystems.FileUtil; 48 import org.openide.loaders.DataFolder; 49 import org.openide.loaders.DataObject; 50 import org.openide.nodes.AbstractNode; 51 import org.openide.nodes.Node; 52 import org.openide.nodes.Node.PropertySet; 53 import org.openide.nodes.NodeNotFoundException; 54 import org.openide.nodes.NodeOp; 55 import org.openide.nodes.PropertySupport; 56 import org.openide.nodes.Sheet; 57 import org.openide.util.Lookup; 58 import org.openide.util.NbBundle; 59 import org.openide.util.RequestProcessor; 60 import org.openide.util.Utilities; 61 import org.openide.util.actions.SystemAction; 62 import org.openide.util.datatransfer.ExTransferable; 63 import org.openide.util.datatransfer.MultiTransferObject; 64 import org.openide.util.datatransfer.PasteType; 65 import org.openide.util.lookup.AbstractLookup; 66 import org.openide.util.lookup.InstanceContent; 67 import org.openide.util.lookup.Lookups; 68 import org.openide.util.lookup.ProxyLookup; 69 import org.openidex.search.SearchInfo; 70 import org.openidex.search.SearchInfoFactory; 71 72 75 final class PackageRootNode extends AbstractNode implements Runnable , FileStatusListener { 76 77 static Image PACKAGE_BADGE = Utilities.loadImage( "org/netbeans/spi/java/project/support/ui/packageBadge.gif" ); 79 private static Action actions[]; 80 81 private SourceGroup group; 82 83 private final FileObject file; 84 private final Set <FileObject> files; 85 private FileStatusListener fileSystemListener; 86 private RequestProcessor.Task task; 87 private volatile boolean iconChange; 88 private volatile boolean nameChange; 89 90 PackageRootNode( SourceGroup group ) { 91 this( group, new InstanceContent() ); 92 } 93 94 private PackageRootNode( SourceGroup group, InstanceContent ic ) { 95 super( new PackageViewChildren(group), 96 new ProxyLookup(createLookup(group), new AbstractLookup(ic))); 97 ic.add(alwaysSearchableSearchInfo(SearchInfoFactory.createSearchInfoBySubnodes(this))); 98 this.group = group; 99 file = group.getRootFolder(); 100 files = Collections.singleton(file); 101 try { 102 FileSystem fs = file.getFileSystem(); 103 fileSystemListener = FileUtil.weakFileStatusListener(this, fs); 104 fs.addFileStatusListener(fileSystemListener); 105 } catch (FileStateInvalidException e) { 106 ErrorManager err = ErrorManager.getDefault(); 107 err.annotate(e, "Can not get " + file + " filesystem, ignoring..."); err.notify(ErrorManager.INFORMATIONAL, e); 109 } 110 setName( group.getName() ); 111 setDisplayName( group.getDisplayName() ); 112 } 114 115 public Image getIcon( int type ) { 116 return computeIcon( false, type ); 117 } 118 119 public Image getOpenedIcon( int type ) { 120 return computeIcon( true, type ); 121 } 122 123 public String getDisplayName () { 124 String s = super.getDisplayName (); 125 126 try { 127 s = file.getFileSystem ().getStatus ().annotateName (s, files); 128 } catch (FileStateInvalidException e) { 129 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 130 } 131 132 return s; 133 } 134 135 public String getHtmlDisplayName() { 136 try { 137 FileSystem.Status stat = file.getFileSystem().getStatus(); 138 if (stat instanceof FileSystem.HtmlStatus) { 139 FileSystem.HtmlStatus hstat = (FileSystem.HtmlStatus) stat; 140 141 String result = hstat.annotateNameHtml ( 142 super.getDisplayName(), files); 143 144 if (!super.getDisplayName().equals(result)) { 146 return result; 147 } 148 } 149 } catch (FileStateInvalidException e) { 150 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 151 } 152 return super.getHtmlDisplayName(); 153 } 154 155 public void run() { 156 if (iconChange) { 157 fireIconChange(); 158 fireOpenedIconChange(); 159 iconChange = false; 160 } 161 if (nameChange) { 162 fireDisplayNameChange(null, null); 163 nameChange = false; 164 } 165 } 166 167 public void annotationChanged(FileStatusEvent event) { 168 if (task == null) { 169 task = RequestProcessor.getDefault().create(this); 170 } 171 172 if ((iconChange == false && event.isIconChange()) || (nameChange == false && event.isNameChange())) { 173 if (event.hasChanged(file)) { 174 iconChange |= event.isIconChange(); 175 nameChange |= event.isNameChange(); 176 } 177 } 178 179 task.schedule(50); } 181 182 public Action [] getActions( boolean context ) { 183 184 if ( actions == null ) { 185 actions = new Action [] { 186 CommonProjectActions.newFileAction(), 187 null, 188 SystemAction.get( FileSystemAction.class ), 189 null, 190 SystemAction.get( FindAction.class ), 191 null, 192 SystemAction.get( PasteAction.class ), 193 null, 194 SystemAction.get( ToolsAction.class ), 195 }; 196 } 197 return actions; 198 } 199 200 public PropertySet[] getPropertySets() { 203 PropertySet[] properties = getDataFolderNodeDelegate().getPropertySets(); 204 for (int i=0; i< properties.length; i++) { 205 if (Sheet.PROPERTIES.equals(properties[i].getName())) { 206 properties[i] = Sheet.createPropertiesSet(); 209 ((Sheet.Set) properties[i]).put(new PropertySupport.ReadOnly<String >(DataObject.PROP_NAME, String .class, 210 NbBundle.getMessage(PackageRootNode.class,"PROP_name"), NbBundle.getMessage(PackageRootNode.class,"HINT_name")) { 211 @Override 212 public String getValue() { 213 return PackageRootNode.this.getDisplayName(); 214 } 215 }); 216 ((Sheet.Set) properties[i]).put(new PropertySupport.ReadOnly<String >("ROOT_PATH", String .class, NbBundle.getMessage(PackageRootNode.class,"PROP_rootpath"), NbBundle.getMessage(PackageRootNode.class,"HINT_rootpath")) { 218 @Override 219 public String getValue() { 220 return FileUtil.getFileDisplayName(PackageRootNode.this.file); 221 } 222 }); 223 } 224 } 225 return properties; 226 } 227 228 public void createPasteTypes(Transferable t, List <PasteType> list) { 230 if (t.isDataFlavorSupported(ExTransferable.multiFlavor)) { 231 try { 232 MultiTransferObject mto = (MultiTransferObject) t.getTransferData(ExTransferable.multiFlavor); 233 List <PackageViewChildren.PackageNode> l = new ArrayList <PackageViewChildren.PackageNode>(); 234 boolean isPackageFlavor = false; 235 boolean hasTheSameRoot = false; 236 int op = -1; 237 for (int i=0; i < mto.getCount(); i++) { 238 Transferable pt = mto.getTransferableAt(i); 239 DataFlavor [] flavors = mto.getTransferDataFlavors(i); 240 for (int j=0; j< flavors.length; j++) { 241 if (PackageViewChildren.SUBTYPE.equals(flavors[j].getSubType ()) && 242 PackageViewChildren.PRIMARY_TYPE.equals(flavors[j].getPrimaryType ())) { 243 if (op == -1) { 244 op = Integer.valueOf (flavors[j].getParameter (PackageViewChildren.MASK)).intValue (); 245 } 246 PackageViewChildren.PackageNode pkgNode = (PackageViewChildren.PackageNode) pt.getTransferData(flavors[j]); 247 if ( !((PackageViewChildren)getChildren()).getRoot().equals( pkgNode.getRoot() ) ) { 248 l.add(pkgNode); 249 } 250 else { 251 hasTheSameRoot = true; 252 } 253 isPackageFlavor = true; 254 } 255 } 256 } 257 if (isPackageFlavor && !hasTheSameRoot) { 258 list.add(new PackageViewChildren.PackagePasteType(this.group.getRootFolder(), 259 l.toArray(new PackageViewChildren.PackageNode[l.size()]), 260 op)); 261 } 262 else if (!isPackageFlavor) { 263 list.addAll( Arrays.asList( getDataFolderNodeDelegate().getPasteTypes( t ) ) ); 264 } 265 } catch (UnsupportedFlavorException e) { 266 ErrorManager.getDefault().notify(e); 267 } catch (IOException e) { 268 ErrorManager.getDefault().notify(e); 269 } 270 } 271 else { 272 DataFlavor [] flavors = t.getTransferDataFlavors(); 273 FileObject root = this.group.getRootFolder(); 274 boolean isPackageFlavor = false; 275 if (root!= null && root.canWrite()) { 276 for (DataFlavor flavor : flavors) { 277 if (PackageViewChildren.SUBTYPE.equals(flavor.getSubType ()) && 278 PackageViewChildren.PRIMARY_TYPE.equals(flavor.getPrimaryType ())) { 279 isPackageFlavor = true; 280 try { 281 int op = Integer.parseInt(flavor.getParameter(PackageViewChildren.MASK)); 282 PackageViewChildren.PackageNode pkgNode = (PackageViewChildren.PackageNode) t.getTransferData(flavor); 283 if ( !((PackageViewChildren)getChildren()).getRoot().equals( pkgNode.getRoot() ) ) { 284 list.add(new PackageViewChildren.PackagePasteType (root, new PackageViewChildren.PackageNode[] {pkgNode}, op)); 285 } 286 } catch (IOException ioe) { 287 ErrorManager.getDefault().notify(ioe); 288 } 289 catch (UnsupportedFlavorException ufe) { 290 ErrorManager.getDefault().notify(ufe); 291 } 292 } 293 } 294 } 295 if (!isPackageFlavor) { 296 list.addAll( Arrays.asList( getDataFolderNodeDelegate().getPasteTypes( t ) ) ); 297 } 298 } 299 } 300 301 @Override 302 public PasteType getDropType(Transferable t, int action, int index) { 303 PasteType pasteType = super.getDropType(t, action, index); 304 if (pasteType instanceof PackageViewChildren.PackagePasteType) { 308 ((PackageViewChildren.PackagePasteType)pasteType).setOperation (action); 309 } 310 return pasteType; 311 } 312 313 315 private Node getDataFolderNodeDelegate() { 316 return getLookup().lookup(DataFolder.class).getNodeDelegate(); 317 } 318 319 private Image computeIcon( boolean opened, int type ) { 320 Image image; 321 Icon icon = group.getIcon( opened ); 322 323 if ( icon == null ) { 324 image = opened ? getDataFolderNodeDelegate().getOpenedIcon( type ) : 325 getDataFolderNodeDelegate().getIcon( type ); 326 image = Utilities.mergeImages( image, PACKAGE_BADGE, 7, 7 ); 327 } 328 else { 329 image = Utilities.icon2Image(icon); 330 } 331 332 return image; 333 } 334 335 private static Lookup createLookup( SourceGroup group ) { 336 FileObject rootFolder = group.getRootFolder(); 338 DataFolder dataFolder = DataFolder.findFolder( rootFolder ); 339 return Lookups.fixed(dataFolder, new PathFinder(group)); 340 } 341 342 344 public static class PathFinder { 345 346 private SourceGroup group; 347 348 public PathFinder( SourceGroup group ) { 349 this.group = group; 350 } 351 352 public Node findPath( Node root, Object object ) { 353 FileObject fo; 354 if (object instanceof FileObject) { 355 fo = (FileObject) object; 356 } else if (object instanceof DataObject) { 357 fo = ((DataObject) object).getPrimaryFile(); 358 } else { 359 return null; 360 } 361 362 FileObject groupRoot = group.getRootFolder(); 363 if ( FileUtil.isParentOf( groupRoot, fo ) ) { 364 366 String relPath = FileUtil.getRelativePath( groupRoot, fo.isFolder() ? fo : fo.getParent() ); 367 368 String [] path = new String [] { relPath.replace( '/', '.' ) }; 369 try { 370 Node packageNode = NodeOp.findPath( root, path ); 371 if (fo.isFolder()) { 372 return packageNode; 373 } else { 374 for (Node child : packageNode.getChildren().getNodes(true)) { 375 DataObject dobj = child.getLookup().lookup(DataObject.class); 376 if (dobj != null && dobj.getPrimaryFile().getNameExt().equals(fo.getNameExt())) { 377 return child; 378 } 379 } 380 } 381 } 382 catch ( NodeNotFoundException e ) { 383 return null; 385 } 386 } 387 else if ( groupRoot.equals( fo ) ) { 388 try { 390 return NodeOp.findPath( root, new String [] { "" } ); } 392 catch ( NodeNotFoundException e ) { 393 } 395 return root; 396 } 397 398 return null; 399 } 400 401 public String toString() { 402 return "PathFinder[" + group + "]"; } 404 405 } 406 407 411 static SearchInfo alwaysSearchableSearchInfo(SearchInfo i) { 412 return new AlwaysSearchableSearchInfo(i); 413 } 414 415 private static final class AlwaysSearchableSearchInfo implements SearchInfo { 416 417 private final SearchInfo delegate; 418 419 public AlwaysSearchableSearchInfo(SearchInfo delegate) { 420 this.delegate = delegate; 421 } 422 423 public boolean canSearch() { 424 return true; 425 } 426 427 public Iterator objectsToSearch() { 428 return delegate.objectsToSearch(); 429 } 430 431 } 432 433 } 434 | Popular Tags |