1 19 20 package org.netbeans.modules.project.ui; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.io.CharConversionException ; 25 import java.lang.ref.Reference ; 26 import java.lang.ref.WeakReference ; 27 import java.text.MessageFormat ; 28 import java.util.ArrayList ; 29 import java.util.Arrays ; 30 import java.util.Collection ; 31 import java.util.Collections ; 32 import java.util.Iterator ; 33 import java.util.List ; 34 import java.util.ResourceBundle ; 35 import java.util.WeakHashMap ; 36 import javax.swing.Action ; 37 import javax.swing.JSeparator ; 38 import javax.swing.SwingUtilities ; 39 import javax.swing.event.ChangeEvent ; 40 import javax.swing.event.ChangeListener ; 41 import org.netbeans.api.project.FileOwnerQuery; 42 import org.netbeans.api.project.Project; 43 import org.netbeans.api.project.ProjectUtils; 44 import org.netbeans.api.project.Sources; 45 import org.netbeans.spi.project.ui.LogicalViewProvider; 46 import org.openide.ErrorManager; 47 import org.openide.filesystems.FileObject; 48 import org.openide.filesystems.Repository; 49 import org.openide.loaders.DataFolder; 50 import org.openide.loaders.FolderLookup; 51 import org.openide.nodes.AbstractNode; 52 import org.openide.nodes.Children; 53 import org.openide.nodes.FilterNode; 54 import org.openide.nodes.Node; 55 import org.openide.util.Lookup; 56 import org.openide.util.NbBundle; 57 import org.openide.util.WeakListeners; 58 import org.openide.util.lookup.Lookups; 59 import org.openide.util.lookup.ProxyLookup; 60 import org.openide.xml.XMLUtil; 61 import org.openidex.search.SearchInfo; 62 import org.openidex.search.SearchInfoFactory; 63 64 67 public class ProjectsRootNode extends AbstractNode { 68 69 static final int PHYSICAL_VIEW = 0; 70 static final int LOGICAL_VIEW = 1; 71 72 private static final String ICON_BASE = "org/netbeans/modules/project/ui/resources/projectsRootNode.gif"; private static final String ACTIONS_FOLDER = "ProjectsTabActions"; 75 private ResourceBundle bundle; 76 private final int type; 77 78 public ProjectsRootNode( int type ) { 79 super( new ProjectChildren( type ) ); 80 setIconBaseWithExtension( ICON_BASE ); 81 this.type = type; 82 } 83 84 public String getName() { 85 return ( "OpenProjects" ); } 87 88 public String getDisplayName() { 89 if ( this.bundle == null ) { 90 this.bundle = NbBundle.getBundle( ProjectsRootNode.class ); 91 } 92 return bundle.getString( "LBL_OpenProjectsNode_Name" ); } 94 95 public boolean canRename() { 96 return false; 97 } 98 99 public Node.Handle getHandle() { 100 return new Handle(type); 101 } 102 103 public Action [] getActions( boolean context ) { 104 if (context || type == PHYSICAL_VIEW) { 105 return new Action [0]; 106 } else { 107 List <Action > actions = new ArrayList <Action >(); 108 DataFolder actionsFolder = DataFolder.findFolder(Repository.getDefault().getDefaultFileSystem().findResource(ACTIONS_FOLDER)); 109 for (Object o: new FolderLookup(actionsFolder).getLookup().lookupAll(Object .class)) { 110 if (o instanceof Action ) { 111 actions.add((Action ) o); 112 } else if (o instanceof JSeparator ) { 113 actions.add(null); 114 } 115 } 116 return actions.toArray(new Action [actions.size()]); 117 } 118 } 119 120 123 Node findNode(FileObject target) { 124 125 ProjectChildren ch = (ProjectChildren)getChildren(); 126 127 if ( ch.type == LOGICAL_VIEW ) { 128 Node[] nodes = ch.getNodes( true ); 129 Project ownerProject = FileOwnerQuery.getOwner(target); 131 for (int lookOnlyInOwnerProject = (ownerProject != null) ? 0 : 1; lookOnlyInOwnerProject < 2; lookOnlyInOwnerProject++) { 132 for (int i = 0; i < nodes.length; i++) { 133 Project p = (Project) nodes[i].getLookup().lookup(Project.class); 134 assert p != null : "Should have had a Project in lookup of " + nodes[i]; 135 if (lookOnlyInOwnerProject == 0 && p != ownerProject) { 136 continue; } 138 LogicalViewProvider lvp = (LogicalViewProvider) p.getLookup().lookup(LogicalViewProvider.class); 139 if (lvp != null) { 140 Node selectedNode = lvp.findPath(nodes[i], target); 144 if (selectedNode != null) { 145 return selectedNode; 146 } 147 } 148 } 149 } 150 return null; 151 152 } 153 else if ( ch.type == PHYSICAL_VIEW ) { 154 Node[] nodes = ch.getNodes( true ); 155 for( int i = 0; i < nodes.length; i++ ) { 156 PhysicalView.PathFinder pf = (PhysicalView.PathFinder)nodes[i].getLookup().lookup( PhysicalView.PathFinder.class ); 158 if ( pf != null ) { 159 Node n = pf.findPath( nodes[i], target ); 160 if ( n != null ) { 161 return n; 162 } 163 } 164 } 165 return null; 166 } 167 else { 168 return null; 169 } 170 } 171 172 private static class Handle implements Node.Handle { 173 174 private static final long serialVersionUID = 78374332058L; 175 176 private int viewType; 177 178 public Handle( int viewType ) { 179 this.viewType = viewType; 180 } 181 182 public Node getNode() { 183 return new ProjectsRootNode( viewType ); 184 } 185 186 } 187 188 189 static class ProjectChildren extends Children.Keys<Project> implements ChangeListener , PropertyChangeListener { 192 193 private java.util.Map <Sources,Reference <Project>> sources2projects = new WeakHashMap <Sources,Reference <Project>>(); 194 195 int type; 196 197 public ProjectChildren( int type ) { 198 this.type = type; 199 OpenProjectList.getDefault().addPropertyChangeListener( this ); 200 } 201 202 204 public void addNotify() { 205 setKeys( getKeys() ); 206 } 207 208 public void removeNotify() { 209 for (Sources sources : sources2projects.keySet()) { 210 sources.removeChangeListener( this ); 211 } 212 sources2projects.clear(); 213 setKeys(Collections.<Project>emptySet()); 214 } 215 216 protected Node[] createNodes(Project project) { 217 LogicalViewProvider lvp = project.getLookup().lookup(LogicalViewProvider.class); 218 219 Node nodes[] = null; 220 221 if ( type == PHYSICAL_VIEW ) { 222 Sources sources = ProjectUtils.getSources( project ); 223 sources.removeChangeListener( this ); 224 sources.addChangeListener( this ); 225 sources2projects.put( sources, new WeakReference <Project>( project ) ); 226 nodes = PhysicalView.createNodesForProject( project ); 227 } 228 else if ( lvp == null ) { 229 ErrorManager.getDefault().log(ErrorManager.WARNING, "Warning - project " + ProjectUtils.getInformation(project).getName() + " failed to supply a LogicalViewProvider in its lookup"); Sources sources = ProjectUtils.getSources( project ); 231 sources.removeChangeListener( this ); 232 sources.addChangeListener( this ); 233 nodes = PhysicalView.createNodesForProject( project ); 234 if ( nodes.length > 0 ) { 235 nodes = new Node[] { nodes[0] }; 236 } 237 else { 238 nodes = new Node[] { Node.EMPTY }; 239 } 240 } 241 else { 242 nodes = new Node[] { lvp.createLogicalView() }; 243 if (nodes[0].getLookup().lookup(Project.class) != project) { 244 ErrorManager.getDefault().log(ErrorManager.WARNING, "Warning - project " + ProjectUtils.getInformation(project).getName() + " failed to supply itself in the lookup of the root node of its own logical view"); } 247 } 248 249 Node[] badgedNodes = new Node[ nodes.length ]; 250 for( int i = 0; i < nodes.length; i++ ) { 251 if ( type == PHYSICAL_VIEW && !PhysicalView.isProjectDirNode( nodes[i] ) ) { 252 badgedNodes[i] = nodes[i]; 254 } 255 else { 256 badgedNodes[i] = new BadgingNode( nodes[i], 257 type == LOGICAL_VIEW ); 258 } 259 } 260 261 return badgedNodes; 262 } 263 264 266 public void propertyChange( PropertyChangeEvent e ) { 267 if ( OpenProjectList.PROPERTY_OPEN_PROJECTS.equals( e.getPropertyName() ) ) { 268 setKeys( getKeys() ); 269 } 270 } 271 272 274 public void stateChanged( ChangeEvent e ) { 275 276 Reference <Project> projectRef = sources2projects.get(e.getSource()); 277 if ( projectRef == null ) { 278 return; 279 } 280 281 final Project project = projectRef.get(); 282 283 if ( project == null ) { 284 return; 285 } 286 287 SwingUtilities.invokeLater( new Runnable () { 289 public void run() { 290 refreshKey( project ); 291 } 292 } ); 293 } 294 295 297 public Collection <Project> getKeys() { 298 List <Project> projects = Arrays.asList( OpenProjectList.getDefault().getOpenProjects() ); 299 Collections.sort( projects, OpenProjectList.PROJECT_BY_DISPLAYNAME ); 300 301 return projects; 302 } 303 304 } 305 306 private static final class BadgingNode extends FilterNode implements PropertyChangeListener { 307 308 private static String badgedNamePattern = NbBundle.getMessage( ProjectsRootNode.class, "LBL_MainProject_BadgedNamePattern" ); 309 310 public BadgingNode( Node n, boolean addSearchInfo ) { 311 super( n, 312 null, addSearchInfo 314 ? new ProxyLookup( new Lookup[] { 315 n.getLookup(), 316 Lookups.singleton(alwaysSearchableSearchInfo(SearchInfoFactory 317 .createSearchInfoBySubnodes(n))), 318 }) 319 : n.getLookup() ); 320 OpenProjectList.getDefault().addPropertyChangeListener( WeakListeners.propertyChange( this, OpenProjectList.getDefault() ) ); 321 } 322 323 public String getDisplayName() { 324 String original = super.getDisplayName(); 325 return isMain() ? MessageFormat.format( badgedNamePattern, new Object [] { original } ) : original; 326 } 327 328 public String getHtmlDisplayName() { 329 String htmlName = getOriginal().getHtmlDisplayName(); 330 String dispName = null; 331 if (isMain() && htmlName == null) { 332 dispName = super.getDisplayName(); 333 try { 334 dispName = XMLUtil.toElementContent(dispName); 335 } catch (CharConversionException ex) { 336 } 338 } 339 return isMain() ? "<b>" + (htmlName == null ? dispName : htmlName) + "</b>" : htmlName; } 341 342 public void propertyChange( PropertyChangeEvent e ) { 343 if ( OpenProjectList.PROPERTY_MAIN_PROJECT.equals( e.getPropertyName() ) ) { 344 fireDisplayNameChange( null, null ); 345 } 346 } 347 348 private boolean isMain() { 349 Project p = (Project)getLookup().lookup( Project.class ); 350 return p != null && OpenProjectList.getDefault().isMainProject( p ); 351 } 352 353 } 354 355 359 static SearchInfo alwaysSearchableSearchInfo(SearchInfo i) { 360 return new AlwaysSearchableSearchInfo(i); 361 } 362 363 private static final class AlwaysSearchableSearchInfo implements SearchInfo { 364 365 private final SearchInfo delegate; 366 367 public AlwaysSearchableSearchInfo(SearchInfo delegate) { 368 this.delegate = delegate; 369 } 370 371 public boolean canSearch() { 372 return true; 373 } 374 375 public Iterator objectsToSearch() { 376 return delegate.objectsToSearch(); 377 } 378 379 } 380 381 } 382 | Popular Tags |