1 19 20 package org.netbeans.modules.ruby.railsprojects; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.beans.PropertyChangeSupport ; 25 import java.io.File ; 26 import java.io.IOException ; 27 import java.util.Collections ; 28 import javax.swing.Icon ; 29 import javax.swing.ImageIcon ; 30 import org.netbeans.api.java.classpath.ClassPath; 31 import org.netbeans.api.java.classpath.GlobalPathRegistry; 32 import org.netbeans.api.project.Project; 33 import org.netbeans.api.project.ProjectInformation; 34 import org.netbeans.api.project.ProjectManager; 35 import org.netbeans.modules.ruby.railsprojects.SourceRoots; 36 import org.netbeans.modules.ruby.railsprojects.classpath.ClassPathProviderImpl; 37 import org.netbeans.modules.ruby.railsprojects.server.WebrickServer; 38 import org.netbeans.modules.ruby.railsprojects.ui.RailsLogicalViewProvider; 39 import org.netbeans.modules.ruby.railsprojects.ui.customizer.CustomizerProviderImpl; 40 import org.netbeans.modules.ruby.railsprojects.ui.customizer.RailsProjectProperties; 41 import org.netbeans.spi.project.AuxiliaryConfiguration; 42 import org.netbeans.spi.project.SubprojectProvider; 43 import org.netbeans.spi.project.support.LookupProviderSupport; 44 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectEvent; 45 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectHelper; 46 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectListener; 47 import org.netbeans.modules.ruby.spi.project.support.rake.FilterPropertyProvider; 48 import org.netbeans.modules.ruby.spi.project.support.rake.GeneratedFilesHelper; 49 import org.netbeans.modules.ruby.spi.project.support.rake.ProjectXmlSavedHook; 50 import org.netbeans.modules.ruby.spi.project.support.rake.PropertyEvaluator; 51 import org.netbeans.modules.ruby.spi.project.support.rake.PropertyProvider; 52 import org.netbeans.modules.ruby.spi.project.support.rake.PropertyUtils; 53 import org.netbeans.modules.ruby.spi.project.support.rake.ReferenceHelper; 54 import org.netbeans.spi.project.ui.PrivilegedTemplates; 55 import org.netbeans.spi.project.ui.ProjectOpenedHook; 56 import org.netbeans.spi.project.ui.RecommendedTemplates; 57 import org.netbeans.spi.project.ui.support.UILookupMergerSupport; 58 import org.openide.ErrorManager; 59 import org.openide.filesystems.FileObject; 60 import org.openide.filesystems.FileUtil; 61 import org.openide.util.Lookup; 62 import org.openide.util.Mutex; 63 import org.openide.util.Utilities; 64 import org.openide.util.lookup.Lookups; 65 import org.w3c.dom.Element ; 66 import org.w3c.dom.Text ; 67 import org.w3c.dom.Node ; 68 import org.w3c.dom.NodeList ; 69 70 74 public class RailsProject implements Project, RakeProjectListener { 75 79 public static final String SOURCES_TYPE_RUBY = "ruby"; 81 private static final Icon Ruby_PROJECT_ICON = new ImageIcon (Utilities.loadImage("org/netbeans/modules/ruby/railsprojects/ui/resources/rails.png")); 83 protected final AuxiliaryConfiguration aux; 84 protected final RakeProjectHelper helper; 85 protected final PropertyEvaluator eval; 86 protected final ReferenceHelper refHelper; 87 protected final GeneratedFilesHelper genFilesHelper; 88 protected final Lookup lookup; 89 protected final UpdateHelper updateHelper; 90 protected SourceRoots sourceRoots; 92 protected SourceRoots testRoots; 93 94 protected RailsProject(RakeProjectHelper helper) throws IOException { 95 this.helper = helper; 96 eval = createEvaluator(); 97 aux = helper.createAuxiliaryConfiguration(); 98 refHelper = new ReferenceHelper(helper, aux, eval); 99 genFilesHelper = new GeneratedFilesHelper(helper); 100 this.updateHelper = new UpdateHelper (this, this.helper, this.aux, this.genFilesHelper, 101 UpdateHelper.createDefaultNotifier()); 102 103 lookup = createLookup(aux); 104 helper.addRakeProjectListener(this); 105 } 106 107 111 public FileObject getProjectDirectory() { 112 return helper.getProjectDirectory(); 113 } 114 115 public String toString() { 116 return "RailsProject[" + FileUtil.getFileDisplayName(getProjectDirectory()) + "]"; } 118 119 private PropertyEvaluator createEvaluator() { 120 PropertyEvaluator baseEval1 = PropertyUtils.sequentialPropertyEvaluator( 123 helper.getStockPropertyPreprovider(), 124 helper.getPropertyProvider(RailsConfigurationProvider.CONFIG_PROPS_PATH)); 125 PropertyEvaluator baseEval2 = PropertyUtils.sequentialPropertyEvaluator( 126 helper.getStockPropertyPreprovider(), 127 helper.getPropertyProvider(RakeProjectHelper.PRIVATE_PROPERTIES_PATH)); 128 return PropertyUtils.sequentialPropertyEvaluator( 129 helper.getStockPropertyPreprovider(), 130 helper.getPropertyProvider(RailsConfigurationProvider.CONFIG_PROPS_PATH), 131 new ConfigPropertyProvider(baseEval1, "nbproject/private/configs", helper), helper.getPropertyProvider(RakeProjectHelper.PRIVATE_PROPERTIES_PATH), 133 PropertyUtils.userPropertiesProvider(baseEval2, 134 "user.properties.file", FileUtil.toFile(getProjectDirectory())), new ConfigPropertyProvider(baseEval1, "nbproject/configs", helper), helper.getPropertyProvider(RakeProjectHelper.PROJECT_PROPERTIES_PATH)); 137 } 138 private static final class ConfigPropertyProvider extends FilterPropertyProvider implements PropertyChangeListener { 139 private final PropertyEvaluator baseEval; 140 private final String prefix; 141 private final RakeProjectHelper helper; 142 public ConfigPropertyProvider(PropertyEvaluator baseEval, String prefix, RakeProjectHelper helper) { 143 super(computeDelegate(baseEval, prefix, helper)); 144 this.baseEval = baseEval; 145 this.prefix = prefix; 146 this.helper = helper; 147 baseEval.addPropertyChangeListener(this); 148 } 149 public void propertyChange(PropertyChangeEvent ev) { 150 if (RailsConfigurationProvider.PROP_CONFIG.equals(ev.getPropertyName())) { 151 setDelegate(computeDelegate(baseEval, prefix, helper)); 152 } 153 } 154 private static PropertyProvider computeDelegate(PropertyEvaluator baseEval, String prefix, RakeProjectHelper helper) { 155 String config = baseEval.getProperty(RailsConfigurationProvider.PROP_CONFIG); 156 if (config != null) { 157 return helper.getPropertyProvider(prefix + "/" + config + ".properties"); } else { 159 return PropertyUtils.fixedPropertyProvider(Collections.<String ,String >emptyMap()); 160 } 161 } 162 } 163 164 public PropertyEvaluator evaluator() { 165 return eval; 166 } 167 168 public ReferenceHelper getReferenceHelper () { 169 return this.refHelper; 170 } 171 172 public UpdateHelper getUpdateHelper() { 173 return this.updateHelper; 174 } 175 176 public Lookup getLookup() { 177 return lookup; 178 } 179 180 public RakeProjectHelper getRakeProjectHelper() { 181 return helper; 182 } 183 184 protected Lookup createLookup(AuxiliaryConfiguration aux) { 185 SubprojectProvider spp = refHelper.createSubprojectProvider(); 186 Lookup base = Lookups.fixed(new Object [] { 187 new Info(), 188 aux, 189 helper.createCacheDirectoryProvider(), 190 spp, 191 new RailsActionProvider( this, this.updateHelper ), 192 new RailsLogicalViewProvider(this, this.updateHelper, evaluator(), spp, refHelper), 193 new ClassPathProviderImpl(this.helper, evaluator(), getSourceRoots(),getTestSourceRoots()), new CustomizerProviderImpl(this, this.updateHelper, evaluator(), refHelper, this.genFilesHelper), 196 new ProjectXmlSavedHookImpl(), 197 new ProjectOpenedHookImpl(), 198 new RailsSources (this.helper, evaluator(), getSourceRoots(), getTestSourceRoots()), 199 new RailsSharabilityQuery (this.helper, evaluator(), getSourceRoots(), getTestSourceRoots()), new RailsFileBuiltQuery (this.helper, evaluator(),getSourceRoots(),getTestSourceRoots()), new RecommendedTemplatesImpl (this.updateHelper), 202 this, new RailsProjectOperations(this), 204 new RailsConfigurationProvider(this), 205 UILookupMergerSupport.createPrivilegedTemplatesMerger(), 206 UILookupMergerSupport.createRecommendedTemplatesMerger(), 207 LookupProviderSupport.createSourcesMerger(), 208 new WebrickServer(this), 209 }); 210 return LookupProviderSupport.createCompositeLookup(base, "Projects/org-netbeans-modules-ruby-railsprojects/Lookup"); } 212 213 public void configurationXmlChanged(RakeProjectEvent ev) { 214 if (ev.getPath().equals(RakeProjectHelper.PROJECT_XML_PATH)) { 215 Info info = (Info)getLookup().lookup(ProjectInformation.class); 217 info.firePropertyChange(ProjectInformation.PROP_NAME); 218 info.firePropertyChange(ProjectInformation.PROP_DISPLAY_NAME); 219 } 220 } 221 222 public void propertiesChanged(RakeProjectEvent ev) { 223 } 225 226 228 232 public synchronized SourceRoots getSourceRoots() { 233 if (this.sourceRoots == null) { this.sourceRoots = new SourceRoots(this.updateHelper, evaluator(), getReferenceHelper(), "source-roots", false, "src.{0}{1}.dir"); } 236 return this.sourceRoots; 237 } 238 239 public synchronized SourceRoots getTestSourceRoots() { 240 if (this.testRoots == null) { this.testRoots = new SourceRoots(this.updateHelper, evaluator(), getReferenceHelper(), "test-roots", true, "test.{0}{1}.dir"); } 243 return this.testRoots; 244 } 245 246 248 public void setName(final String name) { 249 ProjectManager.mutex().writeAccess(new Mutex.Action<Void >() { 250 public Void run() { 251 Element data = helper.getPrimaryConfigurationData(true); 252 NodeList nl = data.getElementsByTagNameNS(RailsProjectType.PROJECT_CONFIGURATION_NAMESPACE, "name"); 254 Element nameEl; 255 if (nl.getLength() == 1) { 256 nameEl = (Element ) nl.item(0); 257 NodeList deadKids = nameEl.getChildNodes(); 258 while (deadKids.getLength() > 0) { 259 nameEl.removeChild(deadKids.item(0)); 260 } 261 } else { 262 nameEl = data.getOwnerDocument().createElementNS(RailsProjectType.PROJECT_CONFIGURATION_NAMESPACE, "name"); 263 data.insertBefore(nameEl, data.getChildNodes().item(0)); 264 } 265 nameEl.appendChild(data.getOwnerDocument().createTextNode(name)); 266 helper.putPrimaryConfigurationData(data, true); 267 return null; 268 } 269 }); 270 } 271 272 273 274 275 277 protected class Info implements ProjectInformation { 278 279 private final PropertyChangeSupport pcs = new PropertyChangeSupport (this); 280 281 public Info() {} 282 283 void firePropertyChange(String prop) { 284 pcs.firePropertyChange(prop, null, null); 285 } 286 287 public String getName() { 288 return PropertyUtils.getUsablePropertyName(getDisplayName()); 289 } 290 291 public String getDisplayName() { 292 return ProjectManager.mutex().readAccess(new Mutex.Action<String >() { 293 public String run() { 294 Element data = updateHelper.getPrimaryConfigurationData(true); 295 NodeList nl = data.getElementsByTagNameNS(RailsProjectType.PROJECT_CONFIGURATION_NAMESPACE, "name"); if (nl.getLength() == 1) { 298 nl = nl.item(0).getChildNodes(); 299 if (nl.getLength() == 1 && nl.item(0).getNodeType() == Node.TEXT_NODE) { 300 return ((Text ) nl.item(0)).getNodeValue(); 301 } 302 } 303 return "???"; } 305 }); 306 } 307 308 public Icon getIcon() { 309 return Ruby_PROJECT_ICON; 310 } 311 312 public Project getProject() { 313 return RailsProject.this; 314 } 315 316 public void addPropertyChangeListener(PropertyChangeListener listener) { 317 pcs.addPropertyChangeListener(listener); 318 } 319 320 public void removePropertyChangeListener(PropertyChangeListener listener) { 321 pcs.removePropertyChangeListener(listener); 322 } 323 324 } 325 326 protected final class ProjectXmlSavedHookImpl extends ProjectXmlSavedHook { 327 328 public ProjectXmlSavedHookImpl() {} 329 330 protected void projectXmlSaved() throws IOException { 331 346 } 347 348 } 349 350 protected final class ProjectOpenedHookImpl extends ProjectOpenedHook { 351 352 public ProjectOpenedHookImpl() {} 353 354 protected void projectOpened() { 355 373 ClassPathProviderImpl cpProvider = (ClassPathProviderImpl)lookup.lookup(ClassPathProviderImpl.class); 375 GlobalPathRegistry.getDefault().register(ClassPath.BOOT, cpProvider.getProjectClassPaths(ClassPath.BOOT)); 376 GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, cpProvider.getProjectClassPaths(ClassPath.SOURCE)); 377 379 382 404 } 405 406 protected void projectClosed() { 407 try { 409 ProjectManager.getDefault().saveProject(RailsProject.this); 410 } catch (IOException e) { 411 ErrorManager.getDefault().notify(e); 412 } 413 414 ClassPathProviderImpl cpProvider = (ClassPathProviderImpl)lookup.lookup(ClassPathProviderImpl.class); 416 GlobalPathRegistry.getDefault().unregister(ClassPath.BOOT, cpProvider.getProjectClassPaths(ClassPath.BOOT)); 417 GlobalPathRegistry.getDefault().unregister(ClassPath.SOURCE, cpProvider.getProjectClassPaths(ClassPath.SOURCE)); 418 420 426 } 427 428 } 429 430 private static final class RecommendedTemplatesImpl implements RecommendedTemplates, PrivilegedTemplates { 431 RecommendedTemplatesImpl (UpdateHelper helper) { 432 this.helper = helper; 433 } 434 435 private UpdateHelper helper; 436 437 439 private static final String [] APPLICATION_TYPES = new String [] { 440 "ruby", "XML", "simple-files" }; 444 445 private static final String [] PRIVILEGED_NAMES = new String [] { 446 "Templates/Ruby/RhtmlTemplate.rhtml", "Templates/Ruby/main.rb", "Templates/Ruby/test.rb", "Templates/Ruby/class.rb", "Templates/Ruby/module.rb", "Templates/Ruby/rakefile.rb", }; 453 454 public String [] getRecommendedTypes() { 455 return APPLICATION_TYPES; 456 } 457 458 public String [] getPrivilegedTemplates() { 459 return PRIVILEGED_NAMES; 460 } 461 462 } 463 } 464 | Popular Tags |