1 19 20 package org.netbeans.modules.ant.freeform.ui; 21 22 import java.awt.Image ; 23 import java.awt.event.ActionEvent ; 24 import java.beans.PropertyChangeEvent ; 25 import java.beans.PropertyChangeListener ; 26 import java.io.IOException ; 27 import java.util.ArrayList ; 28 import java.util.Arrays ; 29 import java.util.Collections ; 30 import java.util.List ; 31 import java.util.logging.Level ; 32 import java.util.logging.Logger ; 33 import javax.swing.AbstractAction ; 34 import javax.swing.Action ; 35 import javax.swing.event.ChangeEvent ; 36 import javax.swing.event.ChangeListener ; 37 import javax.swing.event.EventListenerList ; 38 import org.netbeans.api.project.Project; 39 import org.netbeans.api.project.ProjectInformation; 40 import org.netbeans.api.project.ProjectManager; 41 import org.netbeans.api.project.ProjectUtils; 42 import org.netbeans.api.project.ui.OpenProjects; 43 import org.netbeans.api.project.ui.OpenProjects; 44 import org.netbeans.api.queries.VisibilityQuery; 45 import org.netbeans.modules.ant.freeform.FreeformProject; 46 import org.netbeans.modules.ant.freeform.FreeformProjectType; 47 import org.netbeans.modules.ant.freeform.spi.support.Util; 48 import org.netbeans.modules.ant.freeform.spi.ProjectNature; 49 import org.netbeans.spi.project.support.ant.AntProjectEvent; 50 import org.netbeans.spi.project.support.ant.AntProjectListener; 51 import org.netbeans.spi.project.support.ant.PathMatcher; 52 import org.netbeans.spi.project.ui.support.NodeFactory; 53 import org.netbeans.spi.project.ui.support.NodeList; 54 import org.openide.actions.OpenAction; 55 import org.openide.filesystems.FileObject; 56 import org.openide.filesystems.FileUtil; 57 import org.openide.loaders.ChangeableDataFilter; 58 import org.openide.loaders.DataFolder; 59 import org.openide.loaders.DataObject; 60 import org.openide.loaders.DataObjectNotFoundException; 61 import org.openide.nodes.AbstractNode; 62 import org.openide.nodes.Children; 63 import org.openide.nodes.FilterNode; 64 import org.openide.nodes.Node; 65 import org.openide.util.ContextAwareAction; 66 import org.openide.util.Exceptions; 67 import org.openide.util.Lookup; 68 import org.openide.util.RequestProcessor; 69 import org.openide.util.Utilities; 70 import org.openide.util.actions.SystemAction; 71 import org.openide.util.lookup.Lookups; 72 import org.w3c.dom.Element ; 73 74 78 public class FolderNodeFactory implements NodeFactory { 79 80 81 public FolderNodeFactory() { 82 } 83 84 public NodeList createNodes(Project p) { 85 FreeformProject project = p.getLookup().lookup(FreeformProject.class); 86 assert project != null; 87 return new RootChildren(project); 88 } 89 90 91 static boolean synchronous = false; private static final class RootChildren implements NodeList<Element >, AntProjectListener, PropertyChangeListener { 93 94 private final FreeformProject p; 95 private List <Element > keys = new ArrayList <Element >(); 96 private List <ChangeListener > listeners = new ArrayList <ChangeListener >(); 97 98 public RootChildren(FreeformProject p) { 99 this.p = p; 100 } 101 102 public void addNotify() { 103 updateKeys(false); 104 p.helper().addAntProjectListener(this); 105 p.evaluator().addPropertyChangeListener(this); 106 } 107 108 public void removeNotify() { 109 keys = null; 110 p.helper().removeAntProjectListener(this); 111 p.evaluator().removePropertyChangeListener(this); 112 } 113 114 private void updateKeys(boolean fromListener) { 115 Element genldata = p.getPrimaryConfigurationData(); 116 Element viewEl = Util.findElement(genldata, "view", FreeformProjectType.NS_GENERAL); if (viewEl != null) { 118 Element itemsEl = Util.findElement(viewEl, "items", FreeformProjectType.NS_GENERAL); keys = Util.findSubElements(itemsEl); 120 } else { 121 keys = Collections.<Element >emptyList(); 122 } 123 if (fromListener && !synchronous) { 124 RequestProcessor.getDefault().post(new Runnable () { 126 public void run() { 127 fireChange(); 128 } 129 }); 130 } else { 131 fireChange(); 132 } 133 } 134 135 136 public void configurationXmlChanged(AntProjectEvent ev) { 137 updateKeys(true); 138 } 139 140 public void propertiesChanged(AntProjectEvent ev) { 141 } 143 144 public void propertyChange(PropertyChangeEvent ev) { 145 updateKeys(true); 146 } 147 148 public List <Element > keys() { 149 return keys; 150 } 151 152 public void addChangeListener(ChangeListener l) { 153 listeners.add(l); 154 } 155 156 public void removeChangeListener(ChangeListener l) { 157 listeners.remove(l); 158 } 159 160 private void fireChange() { 161 List <ChangeListener > list = new ArrayList <ChangeListener >(); 162 list.addAll(listeners); 163 for (ChangeListener ls : listeners) { 164 ls.stateChanged(new ChangeEvent (this)); 165 } 166 } 167 168 public Node node(Element itemEl) { 169 170 Element locationEl = Util.findElement(itemEl, "location", FreeformProjectType.NS_GENERAL); String location = Util.findText(locationEl); 172 String locationEval = p.evaluator().evaluate(location); 173 if (locationEval == null) { 174 return null; 175 } 176 FileObject file = p.helper().resolveFileObject(locationEval); 177 if (file == null) { 178 return null; 180 } 181 String label; 182 Element labelEl = Util.findElement(itemEl, "label", FreeformProjectType.NS_GENERAL); if (labelEl != null) { 184 label = Util.findText(labelEl); 185 } else { 186 label = null; 187 } 188 if (itemEl.getLocalName().equals("source-folder")) { if (!file.isFolder()) { 190 return null; 192 } 193 String includes = null; 194 Element includesEl = Util.findElement(itemEl, "includes", FreeformProjectType.NS_GENERAL); if (includesEl != null) { 196 includes = p.evaluator().evaluate(Util.findText(includesEl)); 197 if (includes.matches("\\$\\{[^}]+\\}")) { includes = null; 200 } 201 } 202 String excludes = null; 203 Element excludesEl = Util.findElement(itemEl, "excludes", FreeformProjectType.NS_GENERAL); if (excludesEl != null) { 205 excludes = p.evaluator().evaluate(Util.findText(excludesEl)); 206 } 207 String style = itemEl.getAttribute("style"); for (ProjectNature nature : Lookup.getDefault().lookupAll(ProjectNature.class)) { 209 if (nature.getSourceFolderViewStyles().contains(style)) { 210 return nature.createSourceFolderView(p, file, includes, excludes, style, location, label); 211 } 212 } 213 if (style.equals("subproject")) { try { 215 Project subproject = ProjectManager.getDefault().findProject(file); 216 if (subproject != null) { 217 return new SubprojectNode(subproject, label); 218 } 219 } catch (IOException x) { 220 Exceptions.printStackTrace(x); 221 } 222 return null; 223 } 224 if (!style.equals("tree")) { Logger.getLogger(FolderNodeFactory.class.getName()).log(Level.WARNING, "Unrecognized <source-folder> style '{0}' on {1}", new Object [] {style, file}); 226 } 228 DataObject fileDO; 229 try { 230 fileDO = DataObject.find(file); 231 } catch (DataObjectNotFoundException e) { 232 throw new AssertionError (e); 233 } 234 return new ViewItemNode((DataFolder) fileDO, includes, excludes, location, label); 235 } else { 236 assert itemEl.getLocalName().equals("source-file") : itemEl; DataObject fileDO; 238 try { 239 fileDO = DataObject.find(file); 240 } catch (DataObjectNotFoundException e) { 241 throw new AssertionError (e); 242 } 243 return new ViewItemNode(fileDO.getNodeDelegate(), location, label); 244 } 245 } 246 } 247 248 249 static final class VisibilityQueryDataFilter implements ChangeListener , ChangeableDataFilter { 250 251 EventListenerList ell = new EventListenerList (); 252 private final FileObject root; 253 private final PathMatcher matcher; 254 255 public VisibilityQueryDataFilter(FileObject root, String includes, String excludes) { 256 this.root = root; 257 matcher = new PathMatcher(includes, excludes, FileUtil.toFile(root)); 258 VisibilityQuery.getDefault().addChangeListener( this ); 259 } 260 261 public boolean acceptDataObject(DataObject obj) { 262 FileObject fo = obj.getPrimaryFile(); 263 String path = FileUtil.getRelativePath(root, fo); 264 assert path != null : fo + " not in " + root; 265 if (fo.isFolder()) { 266 path += "/"; } 268 if (!matcher.matches(path, true)) { 269 return false; 270 } 271 return VisibilityQuery.getDefault().isVisible( fo ); 272 } 273 274 public void stateChanged( ChangeEvent e) { 275 Object [] listeners = ell.getListenerList(); 276 ChangeEvent event = null; 277 for (int i = listeners.length-2; i>=0; i-=2) { 278 if (listeners[i] == ChangeListener .class) { 279 if ( event == null) { 280 event = new ChangeEvent ( this ); 281 } 282 ((ChangeListener )listeners[i+1]).stateChanged( event ); 283 } 284 } 285 } 286 287 public void addChangeListener( ChangeListener listener ) { 288 ell.add( ChangeListener .class, listener ); 289 } 290 291 public void removeChangeListener( ChangeListener listener ) { 292 ell.remove( ChangeListener .class, listener ); 293 } 294 295 } 296 297 private static final class ViewItemNode extends FilterNode { 298 299 private final String name; 300 301 private final String displayName; 302 303 public ViewItemNode(Node orig, String name, String displayName) { 304 super(orig); 305 this.name = name; 306 this.displayName = displayName; 307 } 308 309 public ViewItemNode(DataFolder folder, String includes, String excludes, String name, String displayName) { 310 super(folder.getNodeDelegate(), folder.createNodeChildren(new VisibilityQueryDataFilter(folder.getPrimaryFile(), includes, excludes))); 311 this.name = name; 312 this.displayName = displayName; 313 } 314 315 public String getName() { 316 return name; 317 } 318 319 public String getDisplayName() { 320 if (displayName != null) { 321 return displayName; 322 } else { 323 return super.getDisplayName(); 325 } 326 } 327 328 public boolean canRename() { 329 return false; 330 } 331 332 public boolean canDestroy() { 333 return false; 334 } 335 336 public boolean canCut() { 337 return false; 338 } 339 340 } 341 342 private static final class SubprojectNode extends AbstractNode { 344 private final Project p; 345 private final String label; 346 private final ProjectInformation info; 347 348 public SubprojectNode(Project p, String label) { 349 super(Children.LEAF, Lookups.singleton(p)); 350 this.p = p; 351 this.label = label; 352 info = ProjectUtils.getInformation(p); 353 } 354 355 @Override 356 public String getName() { 357 return info.getName(); 358 } 359 360 @Override 361 public String getDisplayName() { 362 return label != null ? label : info.getDisplayName(); 363 } 364 365 @Override 366 public Image getIcon(int type) { 367 return Utilities.icon2Image(info.getIcon()); 368 } 369 370 @Override 371 public Image getOpenedIcon(int type) { 372 return getIcon(type); 373 } 374 375 private static final class OpenProjectAction extends AbstractAction implements ContextAwareAction { 376 public void actionPerformed(ActionEvent ev) { 377 assert false; 378 } 379 public Action createContextAwareInstance(Lookup selection) { 380 final Project[] projects = selection.lookupAll(Project.class).toArray(new Project[0]); 381 return new AbstractAction (SystemAction.get(OpenAction.class).getName()) { 382 public void actionPerformed(ActionEvent ev) { 383 OpenProjects.getDefault().open(projects, false); 384 } 385 @Override 386 public boolean isEnabled() { 387 return !Arrays.asList(OpenProjects.getDefault().getOpenProjects()).containsAll(Arrays.asList(projects)); 388 } 389 }; 390 } 391 } 392 private static final Action OPEN = new OpenProjectAction(); 393 @Override 394 public Action [] getActions(boolean context) { 395 return new Action [] {OPEN}; 396 } 397 398 } 399 400 } 401 | Popular Tags |